xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

winkeybd.c (16561B)


      1 /*
      2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
      3  *
      4  *Permission is hereby granted, free of charge, to any person obtaining
      5  * a copy of this software and associated documentation files (the
      6  *"Software"), to deal in the Software without restriction, including
      7  *without limitation the rights to use, copy, modify, merge, publish,
      8  *distribute, sublicense, and/or sell copies of the Software, and to
      9  *permit persons to whom the Software is furnished to do so, subject to
     10  *the following conditions:
     11  *
     12  *The above copyright notice and this permission notice shall be
     13  *included in all copies or substantial portions of the Software.
     14  *
     15  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     18  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
     19  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     20  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     21  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  *
     23  *Except as contained in this notice, the name of the XFree86 Project
     24  *shall not be used in advertising or otherwise to promote the sale, use
     25  *or other dealings in this Software without prior written authorization
     26  *from the XFree86 Project.
     27  *
     28  * Authors:	Dakshinamurthy Karra
     29  *		Suhaib M Siddiqi
     30  *		Peter Busch
     31  *		Harold L Hunt II
     32  */
     33 
     34 #ifdef HAVE_XWIN_CONFIG_H
     35 #include <xwin-config.h>
     36 #endif
     37 #include "win.h"
     38 #include "winkeybd.h"
     39 #include "winconfig.h"
     40 #include "winmsg.h"
     41 
     42 #include "xkbsrv.h"
     43 
     44 /* C does not have a logical XOR operator, so we use a macro instead */
     45 #define LOGICAL_XOR(a,b) ((!(a) && (b)) || ((a) && !(b)))
     46 
     47 static Bool g_winKeyState[NUM_KEYCODES];
     48 
     49 /*
     50  * Local prototypes
     51  */
     52 
     53 static void
     54  winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass);
     55 
     56 static void
     57  winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl);
     58 
     59 /*
     60  * Translate a Windows WM_[SYS]KEY(UP/DOWN) message
     61  * into an ASCII scan code.
     62  *
     63  * We do this ourselves, rather than letting Windows handle it,
     64  * because Windows tends to munge the handling of special keys,
     65  * like AltGr on European keyboards.
     66  */
     67 
     68 int
     69 winTranslateKey(WPARAM wParam, LPARAM lParam)
     70 {
     71     int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1];
     72     int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2];
     73     int iParam = HIWORD(lParam);
     74     int iParamScanCode = LOBYTE(iParam);
     75     int iScanCode;
     76 
     77     winDebug("winTranslateKey: wParam %08x lParam %08x\n", (int)wParam, (int)lParam);
     78 
     79 /* WM_ key messages faked by Vista speech recognition (WSR) don't have a
     80  * scan code.
     81  *
     82  * Vocola 3 (Rick Mohr's supplement to WSR) uses
     83  * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a
     84  * scan code of 1
     85  */
     86     if (iParamScanCode <= 1) {
     87         if (VK_PRIOR <= wParam && wParam <= VK_DOWN)
     88             /* Trigger special case table to translate to extended
     89              * keycode, otherwise if num_lock is on, we can get keypad
     90              * numbers instead of navigation keys. */
     91             iParam |= KF_EXTENDED;
     92         else
     93             iParamScanCode = MapVirtualKeyEx(wParam,
     94                                              /*MAPVK_VK_TO_VSC */ 0,
     95                                              GetKeyboardLayout(0));
     96     }
     97 
     98     /* Branch on special extended, special non-extended, or normal key */
     99     if ((iParam & KF_EXTENDED) && iKeyFixupEx)
    100         iScanCode = iKeyFixupEx;
    101     else if (iKeyFixup)
    102         iScanCode = iKeyFixup;
    103     else if (wParam == 0 && iParamScanCode == 0x70)
    104         iScanCode = KEY_HKTG;
    105     else
    106         switch (iParamScanCode) {
    107         case 0x70:
    108             iScanCode = KEY_HKTG;
    109             break;
    110         case 0x73:
    111             iScanCode = KEY_BSlash2;
    112             break;
    113         default:
    114             iScanCode = iParamScanCode;
    115             break;
    116         }
    117 
    118     return iScanCode;
    119 }
    120 
    121 /* Ring the keyboard bell (system speaker on PCs) */
    122 static void
    123 winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass)
    124 {
    125     /*
    126      * We can't use Beep () here because it uses the PC speaker
    127      * on NT/2000.  MessageBeep (MB_OK) will play the default system
    128      * sound on systems with a sound card or it will beep the PC speaker
    129      * on systems that do not have a sound card.
    130      */
    131     if (iPercent > 0) MessageBeep(MB_OK);
    132 }
    133 
    134 /* Change some keyboard configuration parameters */
    135 static void
    136 winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl)
    137 {
    138 }
    139 
    140 /*
    141  * See Porting Layer Definition - p. 18
    142  * winKeybdProc is known as a DeviceProc.
    143  */
    144 
    145 int
    146 winKeybdProc(DeviceIntPtr pDeviceInt, int iState)
    147 {
    148     DevicePtr pDevice = (DevicePtr) pDeviceInt;
    149     XkbSrvInfoPtr xkbi;
    150     XkbControlsPtr ctrl;
    151 
    152     switch (iState) {
    153     case DEVICE_INIT:
    154         winConfigKeyboard(pDeviceInt);
    155 
    156         /* FIXME: Maybe we should use winGetKbdLeds () here? */
    157         defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
    158 
    159         winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\""
    160                       " Variant = \"%s\" Options = \"%s\"\n",
    161                       g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none",
    162                       g_winInfo.xkb.model ? g_winInfo.xkb.model : "none",
    163                       g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none",
    164                       g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none",
    165                       g_winInfo.xkb.options ? g_winInfo.xkb.options : "none");
    166 
    167         InitKeyboardDeviceStruct(pDeviceInt,
    168                                  &g_winInfo.xkb, winKeybdBell, winKeybdCtrl);
    169 
    170         xkbi = pDeviceInt->key->xkbInfo;
    171         if ((xkbi != NULL) && (xkbi->desc != NULL)) {
    172             ctrl = xkbi->desc->ctrls;
    173             ctrl->repeat_delay = g_winInfo.keyboard.delay;
    174             ctrl->repeat_interval = 1000 / g_winInfo.keyboard.rate;
    175         }
    176         else {
    177             winErrorFVerb(1,
    178                           "winKeybdProc - Error initializing keyboard AutoRepeat\n");
    179         }
    180 
    181         break;
    182 
    183     case DEVICE_ON:
    184         pDevice->on = TRUE;
    185 
    186         // immediately copy the state of this keyboard device to the VCK
    187         // (which otherwise happens lazily after the first keypress)
    188         CopyKeyClass(pDeviceInt, inputInfo.keyboard);
    189         break;
    190 
    191     case DEVICE_CLOSE:
    192     case DEVICE_OFF:
    193         pDevice->on = FALSE;
    194         break;
    195     }
    196 
    197     return Success;
    198 }
    199 
    200 /*
    201  * Detect current mode key states upon server startup.
    202  *
    203  * Simulate a press and release of any key that is currently
    204  * toggled.
    205  */
    206 
    207 void
    208 winInitializeModeKeyStates(void)
    209 {
    210     /* Restore NumLock */
    211     if (GetKeyState(VK_NUMLOCK) & 0x0001) {
    212         winSendKeyEvent(KEY_NumLock, TRUE);
    213         winSendKeyEvent(KEY_NumLock, FALSE);
    214     }
    215 
    216     /* Restore CapsLock */
    217     if (GetKeyState(VK_CAPITAL) & 0x0001) {
    218         winSendKeyEvent(KEY_CapsLock, TRUE);
    219         winSendKeyEvent(KEY_CapsLock, FALSE);
    220     }
    221 
    222     /* Restore ScrollLock */
    223     if (GetKeyState(VK_SCROLL) & 0x0001) {
    224         winSendKeyEvent(KEY_ScrollLock, TRUE);
    225         winSendKeyEvent(KEY_ScrollLock, FALSE);
    226     }
    227 
    228     /* Restore KanaLock */
    229     if (GetKeyState(VK_KANA) & 0x0001) {
    230         winSendKeyEvent(KEY_HKTG, TRUE);
    231         winSendKeyEvent(KEY_HKTG, FALSE);
    232     }
    233 }
    234 
    235 /*
    236  * Upon regaining the keyboard focus we must
    237  * resynchronize our internal mode key states
    238  * with the actual state of the keys.
    239  */
    240 
    241 void
    242 winRestoreModeKeyStates(void)
    243 {
    244     DWORD dwKeyState;
    245     BOOL processEvents = TRUE;
    246     unsigned short internalKeyStates;
    247 
    248     /* X server is being initialized */
    249     if (!inputInfo.keyboard || !inputInfo.keyboard->key)
    250         return;
    251 
    252     /* Only process events if the rootwindow is mapped. The keyboard events
    253      * will cause segfaults otherwise */
    254     if (screenInfo.screens[0]->root &&
    255         screenInfo.screens[0]->root->mapped == FALSE)
    256         processEvents = FALSE;
    257 
    258     /* Force to process all pending events in the mi event queue */
    259     if (processEvents)
    260         mieqProcessInputEvents();
    261 
    262     /* Read the mode key states of our X server */
    263     /* (stored in the virtual core keyboard) */
    264     internalKeyStates =
    265         XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state);
    266     winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates);
    267 
    268     /* Check if modifier keys are pressed, and if so, fake a press */
    269     {
    270 
    271         BOOL lctrl = (GetAsyncKeyState(VK_LCONTROL) < 0);
    272         BOOL rctrl = (GetAsyncKeyState(VK_RCONTROL) < 0);
    273         BOOL lshift = (GetAsyncKeyState(VK_LSHIFT) < 0);
    274         BOOL rshift = (GetAsyncKeyState(VK_RSHIFT) < 0);
    275         BOOL alt = (GetAsyncKeyState(VK_LMENU) < 0);
    276         BOOL altgr = (GetAsyncKeyState(VK_RMENU) < 0);
    277 
    278         /*
    279            If AltGr and CtrlL appear to be pressed, assume the
    280            CtrL is a fake one
    281          */
    282         if (lctrl && altgr)
    283             lctrl = FALSE;
    284 
    285         if (lctrl)
    286             winSendKeyEvent(KEY_LCtrl, TRUE);
    287 
    288         if (rctrl)
    289             winSendKeyEvent(KEY_RCtrl, TRUE);
    290 
    291         if (lshift)
    292             winSendKeyEvent(KEY_ShiftL, TRUE);
    293 
    294         if (rshift)
    295             winSendKeyEvent(KEY_ShiftL, TRUE);
    296 
    297         if (alt)
    298             winSendKeyEvent(KEY_Alt, TRUE);
    299 
    300         if (altgr)
    301             winSendKeyEvent(KEY_AltLang, TRUE);
    302     }
    303 
    304     /*
    305        Check if latching modifier key states have changed, and if so,
    306        fake a press and a release to toggle the modifier to the correct
    307        state
    308     */
    309     dwKeyState = GetKeyState(VK_NUMLOCK) & 0x0001;
    310     if (LOGICAL_XOR(internalKeyStates & NumLockMask, dwKeyState)) {
    311         winSendKeyEvent(KEY_NumLock, TRUE);
    312         winSendKeyEvent(KEY_NumLock, FALSE);
    313     }
    314 
    315     dwKeyState = GetKeyState(VK_CAPITAL) & 0x0001;
    316     if (LOGICAL_XOR(internalKeyStates & LockMask, dwKeyState)) {
    317         winSendKeyEvent(KEY_CapsLock, TRUE);
    318         winSendKeyEvent(KEY_CapsLock, FALSE);
    319     }
    320 
    321     dwKeyState = GetKeyState(VK_SCROLL) & 0x0001;
    322     if (LOGICAL_XOR(internalKeyStates & ScrollLockMask, dwKeyState)) {
    323         winSendKeyEvent(KEY_ScrollLock, TRUE);
    324         winSendKeyEvent(KEY_ScrollLock, FALSE);
    325     }
    326 
    327     dwKeyState = GetKeyState(VK_KANA) & 0x0001;
    328     if (LOGICAL_XOR(internalKeyStates & KanaMask, dwKeyState)) {
    329         winSendKeyEvent(KEY_HKTG, TRUE);
    330         winSendKeyEvent(KEY_HKTG, FALSE);
    331     }
    332 
    333     /*
    334        For strict correctness, we should also press any non-modifier keys
    335        which are already down when we gain focus, but nobody has complained
    336        yet :-)
    337      */
    338 }
    339 
    340 /*
    341  * Look for the lovely fake Control_L press/release generated by Windows
    342  * when AltGr is pressed/released on a non-U.S. keyboard.
    343  */
    344 
    345 Bool
    346 winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam)
    347 {
    348     MSG msgNext;
    349     LONG lTime;
    350     Bool fReturn;
    351 
    352     static Bool lastWasControlL = FALSE;
    353     static LONG lastTime;
    354 
    355     /*
    356      * Fake Ctrl_L presses will be followed by an Alt_R press
    357      * with the same timestamp as the Ctrl_L press.
    358      */
    359     if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
    360         && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) {
    361         /* Got a Ctrl_L press */
    362 
    363         /* Get time of current message */
    364         lTime = GetMessageTime();
    365 
    366         /* Look for next press message */
    367         fReturn = PeekMessage(&msgNext, NULL,
    368                               WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE);
    369 
    370         if (fReturn && msgNext.message != WM_KEYDOWN &&
    371             msgNext.message != WM_SYSKEYDOWN)
    372             fReturn = 0;
    373 
    374         if (!fReturn) {
    375             lastWasControlL = TRUE;
    376             lastTime = lTime;
    377         }
    378         else {
    379             lastWasControlL = FALSE;
    380         }
    381 
    382         /* Is next press an Alt_R with the same timestamp? */
    383         if (fReturn && msgNext.wParam == VK_MENU
    384             && msgNext.time == lTime
    385             && (HIWORD(msgNext.lParam) & KF_EXTENDED)) {
    386             /*
    387              * Next key press is Alt_R with same timestamp as current
    388              * Ctrl_L message.  Therefore, this Ctrl_L press is a fake
    389              * event, so discard it.
    390              */
    391             return TRUE;
    392         }
    393     }
    394     /*
    395      * Sometimes, the Alt_R press message is not yet posted when the
    396      * fake Ctrl_L press message arrives (even though it has the
    397      * same timestamp), so check for an Alt_R press message that has
    398      * arrived since the last Ctrl_L message.
    399      */
    400     else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
    401              && wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) {
    402         /* Got a Alt_R press */
    403 
    404         if (lastWasControlL) {
    405             lTime = GetMessageTime();
    406 
    407             if (lastTime == lTime) {
    408                 /* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */
    409                 winSendKeyEvent(KEY_LCtrl, FALSE);
    410             }
    411             lastWasControlL = FALSE;
    412         }
    413     }
    414     /*
    415      * Fake Ctrl_L releases will be followed by an Alt_R release
    416      * with the same timestamp as the Ctrl_L release.
    417      */
    418     else if ((message == WM_KEYUP || message == WM_SYSKEYUP)
    419              && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) {
    420         /* Got a Ctrl_L release */
    421 
    422         /* Get time of current message */
    423         lTime = GetMessageTime();
    424 
    425         /* Look for next release message */
    426         fReturn = PeekMessage(&msgNext, NULL,
    427                               WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE);
    428 
    429         if (fReturn && msgNext.message != WM_KEYUP &&
    430             msgNext.message != WM_SYSKEYUP)
    431             fReturn = 0;
    432 
    433         lastWasControlL = FALSE;
    434 
    435         /* Is next press an Alt_R with the same timestamp? */
    436         if (fReturn
    437             && (msgNext.message == WM_KEYUP || msgNext.message == WM_SYSKEYUP)
    438             && msgNext.wParam == VK_MENU
    439             && msgNext.time == lTime
    440             && (HIWORD(msgNext.lParam) & KF_EXTENDED)) {
    441             /*
    442              * Next key release is Alt_R with same timestamp as current
    443              * Ctrl_L message. Therefore, this Ctrl_L release is a fake
    444              * event, so discard it.
    445              */
    446             return TRUE;
    447         }
    448     }
    449     else {
    450         /* On any other press or release message, we don't have a
    451            potentially fake Ctrl_L to worry about anymore... */
    452         lastWasControlL = FALSE;
    453     }
    454 
    455     /* Not a fake control left press/release */
    456     return FALSE;
    457 }
    458 
    459 /*
    460  * Lift any modifier keys that are pressed
    461  */
    462 
    463 void
    464 winKeybdReleaseKeys(void)
    465 {
    466     int i;
    467 
    468 #ifdef HAS_DEVWINDOWS
    469     /* Verify that the mi input system has been initialized */
    470     if (g_fdMessageQueue == WIN_FD_INVALID)
    471         return;
    472 #endif
    473 
    474     /* Loop through all keys */
    475     for (i = 0; i < NUM_KEYCODES; ++i) {
    476         /* Pop key if pressed */
    477         if (g_winKeyState[i])
    478             winSendKeyEvent(i, FALSE);
    479 
    480         /* Reset pressed flag for keys */
    481         g_winKeyState[i] = FALSE;
    482     }
    483 }
    484 
    485 /*
    486  * Take a raw X key code and send an up or down event for it.
    487  *
    488  * Thanks to VNC for inspiration, though it is a simple function.
    489  */
    490 
    491 void
    492 winSendKeyEvent(DWORD dwKey, Bool fDown)
    493 {
    494     /*
    495      * When alt-tabing between screens we can get phantom key up messages
    496      * Here we only pass them through it we think we should!
    497      */
    498     if (g_winKeyState[dwKey] == FALSE && fDown == FALSE)
    499         return;
    500 
    501     /* Update the keyState map */
    502     g_winKeyState[dwKey] = fDown;
    503 
    504     QueueKeyboardEvents(g_pwinKeyboard, fDown ? KeyPress : KeyRelease,
    505                         dwKey + MIN_KEYCODE);
    506 
    507     winDebug("winSendKeyEvent: dwKey: %u, fDown: %u\n", (unsigned int)dwKey, fDown);
    508 }
    509 
    510 BOOL
    511 winCheckKeyPressed(WPARAM wParam, LPARAM lParam)
    512 {
    513     switch (wParam) {
    514     case VK_CONTROL:
    515         if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl])
    516             return TRUE;
    517         if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl])
    518             return TRUE;
    519         break;
    520     case VK_SHIFT:
    521         if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR])
    522             return TRUE;
    523         if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL])
    524             return TRUE;
    525         break;
    526     default:
    527         return TRUE;
    528     }
    529     return FALSE;
    530 }
    531 
    532 /* Only one shift release message is sent even if both are pressed.
    533  * Fix this here
    534  */
    535 void
    536 winFixShiftKeys(int iScanCode)
    537 {
    538     if (GetKeyState(VK_SHIFT) & 0x8000)
    539         return;
    540 
    541     if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR])
    542         winSendKeyEvent(KEY_ShiftR, FALSE);
    543     if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL])
    544         winSendKeyEvent(KEY_ShiftL, FALSE);
    545 }