From 26fb3d4a69d3d63d79442bb782db9a946118eba4 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 16 Aug 2012 16:43:19 +0200 Subject: [PATCH] winex11: Add a critical section to protect the keyboard mapping tables. --- dlls/winex11.drv/keyboard.c | 292 ++++++++++++++++++++++---------------------- 1 file changed, 143 insertions(+), 149 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index e2c306b6c0a..2ccacb7050c 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -66,6 +66,15 @@ static WORD keyc2vkey[256], keyc2scan[256]; static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */ +static CRITICAL_SECTION kbd_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &kbd_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": kbd_section") } +}; +static CRITICAL_SECTION kbd_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + static char KEYBOARD_MapDeadKeysym(KeySym keysym); /* Keyboard translation tables */ @@ -1111,7 +1120,7 @@ static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int i } /* Returns the Windows virtual key code associated with the X event */ -/* x11 lock must be held */ +/* kbd_section must be held */ static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e) { KeySym keysym = 0; @@ -1229,6 +1238,8 @@ void X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) memset(modifiers, 0, sizeof(modifiers)); + EnterCriticalSection( &kbd_section ); + /* the minimum keycode is always greater or equal to 8, so we can * skip the first 8 values, hence start at 1 */ @@ -1270,6 +1281,7 @@ void X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) } } + LeaveCriticalSection( &kbd_section ); if (!changed) return; update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 ); @@ -1341,7 +1353,6 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) if (event->type == KeyPress) update_user_time( event->time ); - wine_tsx11_lock(); /* Clients should pass only KeyPress events to XmbLookupString */ if (xic && event->type == KeyPress) { @@ -1353,7 +1364,6 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) if (Str == NULL) { ERR_(key)("Failed to allocate memory!\n"); - wine_tsx11_unlock(); return; } ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status); @@ -1361,7 +1371,6 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) } else ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL); - wine_tsx11_unlock(); TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status); @@ -1373,6 +1382,8 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return; } + EnterCriticalSection( &kbd_section ); + /* If XKB extensions are used, the state mask for AltGr will use the group index instead of the modifier mask. The group index is set in bits 13-14 of the state field in the XKeyEvent structure. So if AltGr is @@ -1398,27 +1409,26 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) if (buf != Str) HeapFree(GetProcessHeap(), 0, Str); - wine_tsx11_lock(); vkey = EVENT_event_to_vkey(xic,event); /* X returns keycode 0 for composed characters */ if (!vkey && ascii_chars) vkey = VK_NONAME; - wine_tsx11_unlock(); - - TRACE_(key)("keycode %u converted to vkey 0x%X\n", - event->keycode, vkey); + bScan = keyc2scan[event->keycode] & 0xFF; - if (!vkey) return; + TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n", + event->keycode, vkey, bScan); - dwFlags = 0; - if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP; - if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY; + if (vkey) + { + dwFlags = 0; + if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP; + if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY; - update_lock_state( hwnd, vkey, event->state, event_time ); + update_lock_state( hwnd, vkey, event->state, event_time ); - bScan = keyc2scan[event->keycode] & 0xFF; - TRACE_(key)("bScan = 0x%02x.\n", bScan); + X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time ); + } + LeaveCriticalSection( &kbd_section ); - X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time ); } /********************************************************************** @@ -1427,7 +1437,7 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) * Called from X11DRV_InitKeyboard * This routine walks through the defined keyboard layouts and selects * whichever matches most closely. - * X11 lock must be held. + * kbd_section must be held. */ static void X11DRV_KEYBOARD_DetectLayout( Display *display ) @@ -1641,7 +1651,7 @@ void X11DRV_InitKeyboard( Display *display ) set_kbd_layout_preload_key(); - wine_tsx11_lock(); + EnterCriticalSection( &kbd_section ); XDisplayKeycodes(display, &min_keycode, &max_keycode); if (key_mapping) XFree( key_mapping ); key_mapping = XGetKeyboardMapping(display, min_keycode, @@ -1878,7 +1888,7 @@ void X11DRV_InitKeyboard( Display *display ) keyc2scan[keyc]=scan++; } - wine_tsx11_unlock(); + LeaveCriticalSection( &kbd_section ); } static BOOL match_x11_keyboard_layout(HKL hkl) @@ -2012,7 +2022,7 @@ SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl) Display *display = thread_init_display(); KeyCode keycode; KeySym keysym; - int i, index; + int index; CHAR cChar; SHORT ret; @@ -2031,7 +2041,6 @@ SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl) keysym = (unsigned char)cChar; /* (!) cChar is signed */ if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */ - wine_tsx11_lock(); keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */ if (!keycode) { @@ -2039,49 +2048,41 @@ SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl) { ret = 0x0240 + cChar; /* 0x0200 indicates a control character */ TRACE(" ... returning ctrl char %#.2x\n", ret); - wine_tsx11_unlock(); return ret; } /* It didn't work ... let's try with deadchar code. */ TRACE("retrying with | 0xFE00\n"); keycode = XKeysymToKeycode(display, keysym | 0xFE00); } - wine_tsx11_unlock(); TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode); + if (!keycode) return -1; + + EnterCriticalSection( &kbd_section ); /* keycode -> (keyc2vkey) vkey */ ret = keyc2vkey[keycode]; - - if (!keycode || !ret) + if (!ret) { + LeaveCriticalSection( &kbd_section ); TRACE("keycode for '%c' not found, returning -1\n", cChar); return -1; } - index = -1; - wine_tsx11_lock(); - for (i = 0; i < 4; i++) /* find shift state */ - { - if (keycode_to_keysym(display, keycode, i) == keysym) - { - index = i; - break; - } - } - wine_tsx11_unlock(); + for (index = 0; index < 4; index++) /* find shift state */ + if (keycode_to_keysym(display, keycode, index) == keysym) break; + + LeaveCriticalSection( &kbd_section ); switch (index) { - default: - case -1: - WARN("Keysym %lx not found while parsing the keycode table\n", keysym); - return -1; - case 0: break; case 1: ret += 0x0100; break; case 2: ret += 0x0600; break; case 3: ret += 0x0700; break; + default: + WARN("Keysym %lx not found while parsing the keycode table\n", keysym); + return -1; } /* index : 0 adds 0x0000 @@ -2100,21 +2101,20 @@ SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl) */ UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl) { + UINT ret = 0; + int keyc; Display *display = thread_init_display(); -#define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0) - TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl); if (!match_x11_keyboard_layout(hkl)) FIXME("keyboard layout %p is not supported\n", hkl); + EnterCriticalSection( &kbd_section ); + switch(wMapType) { case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */ case MAPVK_VK_TO_VSC_EX: - { - int keyc; - switch (wCode) { case VK_SHIFT: wCode = VK_LSHIFT; break; @@ -2124,127 +2124,115 @@ UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl) /* let's do vkey -> keycode -> scan */ for (keyc = min_keycode; keyc <= max_keycode; keyc++) - if ((keyc2vkey[keyc] & 0xFF) == wCode) break; - - if (keyc > max_keycode) { - TRACE("returning no scan-code.\n"); - return 0; + if ((keyc2vkey[keyc] & 0xFF) == wCode) + { + ret = keyc2scan[keyc] & 0xFF; + break; + } } - returnMVK (keyc2scan[keyc] & 0xFF); - } + break; + case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */ case MAPVK_VSC_TO_VK_EX: - { - int keyc; - UINT vkey = 0; /* let's do scan -> keycode -> vkey */ for (keyc = min_keycode; keyc <= max_keycode; keyc++) if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF)) { - vkey = keyc2vkey[keyc] & 0xFF; + ret = keyc2vkey[keyc] & 0xFF; /* Only stop if it's not a numpad vkey; otherwise keep looking for a potential better vkey. */ - if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey)) + if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret)) break; } - if (vkey == 0) - { - TRACE("returning no vkey-code.\n"); - return 0; - } - if (wMapType == MAPVK_VSC_TO_VK) - switch (vkey) + switch (ret) { case VK_LSHIFT: case VK_RSHIFT: - vkey = VK_SHIFT; break; + ret = VK_SHIFT; break; case VK_LCONTROL: case VK_RCONTROL: - vkey = VK_CONTROL; break; + ret = VK_CONTROL; break; case VK_LMENU: case VK_RMENU: - vkey = VK_MENU; break; + ret = VK_MENU; break; + } + + break; + + case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */ + { + /* we still don't know what "unshifted" means. in windows VK_W (0x57) + * returns 0x57, which is uppercase 'W'. So we have to return the uppercase + * key.. Looks like something is wrong with the MS docs? + * This is only true for letters, for example VK_0 returns '0' not ')'. + * - hence we use the lock mask to ensure this happens. + */ + /* let's do vkey -> keycode -> (XLookupString) ansi char */ + XKeyEvent e; + KeySym keysym; + int len; + char s[10]; + + e.display = display; + e.state = 0; + e.keycode = 0; + e.type = KeyPress; + + /* We exit on the first keycode found, to speed up the thing. */ + for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++) + { /* Find a keycode that could have generated this virtual key */ + if ((keyc2vkey[keyc] & 0xFF) == wCode) + { /* We filter the extended bit, we don't know it */ + e.keycode = keyc; /* Store it temporarily */ + if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) { + e.keycode = 0; /* Wrong one (ex: because of the NumLock + state), so set it to 0, we'll find another one */ + } } + } + + if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9)) + e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0); + + /* Windows always generates VK_DECIMAL for Del/. on keypad while some + * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal + * in order to produce a locale dependent numeric separator. + */ + if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR) + { + e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator); + if (!e.keycode) + e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal); + } + + if (!e.keycode) + { + WARN("Unknown virtual key %X !!!\n", wCode); + break; + } + TRACE("Found keycode %u\n",e.keycode); - returnMVK (vkey); + len = XLookupString(&e, s, sizeof(s), &keysym, NULL); + if (len) + { + WCHAR wch; + if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1)) ret = toupperW(wch); + } + break; } - case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */ - { - /* we still don't know what "unshifted" means. in windows VK_W (0x57) - * returns 0x57, which is uppercase 'W'. So we have to return the uppercase - * key.. Looks like something is wrong with the MS docs? - * This is only true for letters, for example VK_0 returns '0' not ')'. - * - hence we use the lock mask to ensure this happens. - */ - /* let's do vkey -> keycode -> (XLookupString) ansi char */ - XKeyEvent e; - KeySym keysym; - int keyc, len; - char s[10]; - - e.display = display; - e.state = 0; - e.keycode = 0; - e.type = KeyPress; - - wine_tsx11_lock(); - - /* We exit on the first keycode found, to speed up the thing. */ - for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++) - { /* Find a keycode that could have generated this virtual key */ - if ((keyc2vkey[keyc] & 0xFF) == wCode) - { /* We filter the extended bit, we don't know it */ - e.keycode = keyc; /* Store it temporarily */ - if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) { - e.keycode = 0; /* Wrong one (ex: because of the NumLock - state), so set it to 0, we'll find another one */ - } - } - } - - if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9)) - e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0); - - /* Windows always generates VK_DECIMAL for Del/. on keypad while some - * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal - * in order to produce a locale dependent numeric separator. - */ - if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR) - { - e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator); - if (!e.keycode) - e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal); - } - - if (!e.keycode) - { - WARN("Unknown virtual key %X !!!\n", wCode); - wine_tsx11_unlock(); - return 0; /* whatever */ - } - TRACE("Found keycode %u\n",e.keycode); - - len = XLookupString(&e, s, sizeof(s), &keysym, NULL); - wine_tsx11_unlock(); - - if (len) - { - WCHAR wch; - if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1)) - returnMVK(toupperW(wch)); - } - TRACE("returning no ANSI.\n"); - return 0; - } - default: /* reserved */ - FIXME("Unknown wMapType %d !\n", wMapType); - return 0; - } - return 0; + + default: /* reserved */ + FIXME("Unknown wMapType %d !\n", wMapType); + break; + } + + LeaveCriticalSection( &kbd_section ); + TRACE( "returning 0x%x.\n", ret ); + return ret; } /*********************************************************************** @@ -2319,6 +2307,8 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize) /* let's do scancode -> keycode -> keysym -> String */ + EnterCriticalSection( &kbd_section ); + for (keyi=min_keycode; keyi<=max_keycode; keyi++) if ((keyc2scan[keyi]) == scanCode) break; @@ -2326,17 +2316,16 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize) { INT rc; - wine_tsx11_lock(); keyc = (KeyCode) keyi; keys = keycode_to_keysym(display, keyc, 0); name = XKeysymToString(keys); - wine_tsx11_unlock(); if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU)) { char* idx = strrchr(name, '_'); if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0)) { + LeaveCriticalSection( &kbd_section ); TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n", scanCode, keyc, keys, debugstr_an(name,idx-name)); rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize); @@ -2348,6 +2337,7 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize) if (name) { + LeaveCriticalSection( &kbd_section ); TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n", scanCode, keyc, (int)keys, vkey, debugstr_a(name)); rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize); @@ -2359,6 +2349,7 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize) /* Finally issue WARN for unknown keys */ + LeaveCriticalSection( &kbd_section ); WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi); *lpBuffer = 0; return 0; @@ -2504,6 +2495,8 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState e.window = X11DRV_get_whole_window( focus ); xic = X11DRV_get_ic( focus ); + EnterCriticalSection( &kbd_section ); + if (lpKeyState[VK_SHIFT] & 0x80) { TRACE_(key)("ShiftMask = %04x\n", ShiftMask); @@ -2531,7 +2524,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n", virtKey, scanCode, e.state); - wine_tsx11_lock(); + /* We exit on the first keycode found, to speed up the thing. */ for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++) { /* Find a keycode that could have generated this virtual key */ @@ -2565,7 +2558,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState if (!e.keycode && virtKey != VK_NONAME) { WARN_(key)("Unknown virtual key %X !!!\n", virtKey); - wine_tsx11_unlock(); + LeaveCriticalSection( &kbd_section ); return 0; } else TRACE_(key)("Found keycode %u\n",e.keycode); @@ -2586,7 +2579,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState if (lpChar == NULL) { ERR_(key)("Failed to allocate memory!\n"); - wine_tsx11_unlock(); + LeaveCriticalSection( &kbd_section ); return 0; } ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status); @@ -2594,7 +2587,6 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState } else ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL); - wine_tsx11_unlock(); TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status); @@ -2731,6 +2723,8 @@ found: if (buf != lpChar) HeapFree(GetProcessHeap(), 0, lpChar); + LeaveCriticalSection( &kbd_section ); + /* Null-terminate the buffer, if there's room. MSDN clearly states that the caller must not assume this is done, but some programs (e.g. Audiosurf) do. */ if (1 <= ret && ret < bufW_size) -- 2.11.4.GIT