As a default implementation for en_US keyboard layout, calling the driver implementation next so that it can override the result.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: * Use the english keyboard layout for the default impl, let the driver override the result if they can.
* Only copy default buffer to user buffer in nulldrv, to leave user buffer untouched for drivers. ToUnicodeEx is not re-entrant when dealing with dead keys (although I don't think Wine uses that).
* Use lstrcpynW instead of wcscpy.
* Don't call debugstr_wn if len is < 0.
* Drop controversial (Un)LoadKeyboardLayoutW patch for now.
Supersedes: 204512, 204513, 204518, 204519
dlls/user32/driver.c | 11 ++- dlls/user32/input.c | 80 ++++++++++++++++++- dlls/user32/user_private.h | 2 +- dlls/wineandroid.drv/keyboard.c | 94 ----------------------- dlls/wineandroid.drv/wineandroid.drv.spec | 1 - dlls/winemac.drv/keyboard.c | 3 +- dlls/winemac.drv/winemac.drv.spec | 2 +- dlls/winex11.drv/keyboard.c | 3 +- dlls/winex11.drv/winex11.drv.spec | 2 +- 9 files changed, 90 insertions(+), 108 deletions(-)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 7ac77141696..c385ce0599c 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -284,9 +284,11 @@ static BOOL CDECL nulldrv_RegisterHotKey( HWND hwnd, UINT modifiers, UINT vk ) }
static INT CDECL nulldrv_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, LPWSTR str, - int size, UINT flags, HKL layout ) + int size, UINT flags, HKL layout, + const WCHAR *default_buf, INT default_len ) { - return 0; + lstrcpynW( str, default_buf, size ); + return default_len; }
static BOOL CDECL nulldrv_UnloadKeyboardLayout( HKL layout ) @@ -592,9 +594,10 @@ static BOOL CDECL loaderdrv_RegisterHotKey( HWND hwnd, UINT modifiers, UINT vk ) }
static INT CDECL loaderdrv_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, LPWSTR str, - int size, UINT flags, HKL layout ) + int size, UINT flags, HKL layout, + const WCHAR *default_buf, INT default_len ) { - return load_driver()->pToUnicodeEx( virt, scan, state, str, size, flags, layout ); + return load_driver()->pToUnicodeEx( virt, scan, state, str, size, flags, layout, default_buf, default_len ); }
static BOOL CDECL loaderdrv_UnloadKeyboardLayout( HKL layout ) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 805bfe3e9de..51a08d0786b 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -877,11 +877,83 @@ INT WINAPI ToUnicode(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, /**************************************************************************** * ToUnicodeEx (USER32.@) */ -INT WINAPI ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, - LPWSTR lpwStr, int size, UINT flags, HKL hkl) +INT WINAPI ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, + WCHAR *str, int size, UINT flags, HKL layout ) { - if (!lpKeyState) return 0; - return USER_Driver->pToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, hkl); + BOOL shift, ctrl, numlock; + WCHAR buffer[2]; + INT len; + + TRACE_(keyboard)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n", + virt, scan, state, str, size, flags, layout ); + + if (!state) return 0; + + shift = state[VK_SHIFT] & 0x80; + ctrl = state[VK_CONTROL] & 0x80; + numlock = state[VK_NUMLOCK] & 0x01; + + /* FIXME: English keyboard layout specific */ + + if (scan & 0x8000) buffer[0] = 0; /* key up */ + else if (!ctrl) + { + switch (virt) + { + case VK_BACK: buffer[0] = '\b'; break; + case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break; + case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break; + case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break; + case VK_OEM_4: buffer[0] = shift ? '{' : '['; break; + case VK_OEM_5: buffer[0] = shift ? '|' : '\'; break; + case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break; + case VK_OEM_7: buffer[0] = shift ? '"' : '''; break; + case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break; + case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break; + case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break; + case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break; + case VK_RETURN: buffer[0] = '\r'; break; + case VK_SPACE: buffer[0] = ' '; break; + case VK_TAB: buffer[0] = '\t'; break; + case VK_MULTIPLY: buffer[0] = '*'; break; + case VK_ADD: buffer[0] = '+'; break; + case VK_SUBTRACT: buffer[0] = '-'; break; + case VK_DIVIDE: buffer[0] = '/'; break; + default: + if (virt >= '0' && virt <= '9') + buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt; + else if (virt >= 'A' && virt <= 'Z') + buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A'; + else if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift) + buffer[0] = '0' + virt - VK_NUMPAD0; + else if (virt == VK_DECIMAL && numlock && !shift) + buffer[0] = '.'; + else + buffer[0] = 0; + break; + } + } + else /* Control codes */ + { + switch (virt) + { + case VK_OEM_4: buffer[0] = 0x1b; break; + case VK_OEM_5: buffer[0] = 0x1c; break; + case VK_OEM_6: buffer[0] = 0x1d; break; + case VK_SUBTRACT: buffer[0] = 0x1e; break; + default: + if (virt >= 'A' && virt <= 'Z') buffer[0] = virt - 'A' + 1; + else buffer[0] = 0; + break; + } + } + buffer[1] = 0; + len = wcslen( buffer ); + + len = USER_Driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout, buffer, len ); + + TRACE_(keyboard)( "ret %d, str %s.\n", len, len < 0 ? "" : debugstr_wn(str, len) ); + return len; }
/**************************************************************************** diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 5f8059a12a0..8f9841ec48b 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -71,7 +71,7 @@ typedef struct tagUSER_DRIVER { HKL (CDECL *pLoadKeyboardLayout)(LPCWSTR, UINT); UINT (CDECL *pMapVirtualKeyEx)(UINT, UINT, HKL); BOOL (CDECL *pRegisterHotKey)(HWND, UINT, UINT); - INT (CDECL *pToUnicodeEx)(UINT, UINT, const BYTE *, LPWSTR, int, UINT, HKL); + INT (CDECL *pToUnicodeEx)(UINT, UINT, const BYTE *, LPWSTR, int, UINT, HKL, const WCHAR *, INT); BOOL (CDECL *pUnloadKeyboardLayout)(HKL); void (CDECL *pUnregisterHotKey)(HWND, UINT, UINT); SHORT (CDECL *pVkKeyScanEx)(WCHAR, HKL); diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c index 0a6ede0ec5f..04565c3fad8 100644 --- a/dlls/wineandroid.drv/keyboard.c +++ b/dlls/wineandroid.drv/keyboard.c @@ -750,100 +750,6 @@ jboolean keyboard_event( JNIEnv *env, jobject obj, jint win, jint action, jint k }
-/*********************************************************************** - * ANDROID_ToUnicodeEx - */ -INT CDECL ANDROID_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, - LPWSTR buf, int size, UINT flags, HKL hkl ) -{ - WCHAR buffer[2]; - BOOL shift = state[VK_SHIFT] & 0x80; - BOOL ctrl = state[VK_CONTROL] & 0x80; - BOOL numlock = state[VK_NUMLOCK] & 0x01; - - buffer[0] = buffer[1] = 0; - - if (scan & 0x8000) return 0; /* key up */ - - /* FIXME: hardcoded layout */ - - if (!ctrl) - { - switch (virt) - { - case VK_BACK: buffer[0] = '\b'; break; - case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break; - case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break; - case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break; - case VK_OEM_4: buffer[0] = shift ? '{' : '['; break; - case VK_OEM_5: buffer[0] = shift ? '|' : '\'; break; - case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break; - case VK_OEM_7: buffer[0] = shift ? '"' : '''; break; - case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break; - case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break; - case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break; - case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break; - case VK_RETURN: buffer[0] = '\r'; break; - case VK_SPACE: buffer[0] = ' '; break; - case VK_TAB: buffer[0] = '\t'; break; - case VK_MULTIPLY: buffer[0] = '*'; break; - case VK_ADD: buffer[0] = '+'; break; - case VK_SUBTRACT: buffer[0] = '-'; break; - case VK_DIVIDE: buffer[0] = '/'; break; - default: - if (virt >= '0' && virt <= '9') - { - buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt; - break; - } - if (virt >= 'A' && virt <= 'Z') - { - buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A'; - break; - } - if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift) - { - buffer[0] = '0' + virt - VK_NUMPAD0; - break; - } - if (virt == VK_DECIMAL && numlock && !shift) - { - buffer[0] = '.'; - break; - } - break; - } - } - else /* Control codes */ - { - if (virt >= 'A' && virt <= 'Z') - buffer[0] = virt - 'A' + 1; - else - { - switch (virt) - { - case VK_OEM_4: - buffer[0] = 0x1b; - break; - case VK_OEM_5: - buffer[0] = 0x1c; - break; - case VK_OEM_6: - buffer[0] = 0x1d; - break; - case VK_SUBTRACT: - buffer[0] = 0x1e; - break; - } - } - } - - lstrcpynW( buf, buffer, size ); - TRACE( "returning %d / %s\n", strlenW( buffer ), debugstr_wn(buf, strlenW( buffer ))); - return strlenW( buffer ); -} - - /*********************************************************************** * ANDROID_GetKeyNameText */ diff --git a/dlls/wineandroid.drv/wineandroid.drv.spec b/dlls/wineandroid.drv/wineandroid.drv.spec index 00de23de27e..6f27c1586b3 100644 --- a/dlls/wineandroid.drv/wineandroid.drv.spec +++ b/dlls/wineandroid.drv/wineandroid.drv.spec @@ -7,7 +7,6 @@ @ cdecl GetKeyNameText(long ptr long) ANDROID_GetKeyNameText @ cdecl GetKeyboardLayout(long) ANDROID_GetKeyboardLayout @ cdecl MapVirtualKeyEx(long long long) ANDROID_MapVirtualKeyEx -@ cdecl ToUnicodeEx(long long ptr ptr long long long) ANDROID_ToUnicodeEx @ cdecl VkKeyScanEx(long long) ANDROID_VkKeyScanEx @ cdecl SetCursor(long) ANDROID_SetCursor @ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) ANDROID_ChangeDisplaySettingsEx diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 1ea15f59341..d9c819431f2 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1553,7 +1553,8 @@ BOOL CDECL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey) * */ INT CDECL macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, - LPWSTR bufW, int bufW_size, UINT flags, HKL hkl) + LPWSTR bufW, int bufW_size, UINT flags, HKL hkl, + const WCHAR *default_buf, INT default_len) { struct macdrv_thread_data *thread_data = macdrv_init_thread_data(); INT ret = 0; diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index 39cf33370b4..97c94b6ee88 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -34,7 +34,7 @@ @ cdecl SysCommand(long long long) macdrv_SysCommand @ cdecl SystemParametersInfo(long long ptr long) macdrv_SystemParametersInfo @ cdecl ThreadDetach() macdrv_ThreadDetach -@ cdecl ToUnicodeEx(long long ptr ptr long long long) macdrv_ToUnicodeEx +@ cdecl ToUnicodeEx(long long ptr ptr long long long ptr long) macdrv_ToUnicodeEx @ cdecl UnregisterHotKey(long long long) macdrv_UnregisterHotKey @ cdecl UpdateClipboard() macdrv_UpdateClipboard @ cdecl UpdateLayeredWindow(long ptr ptr) macdrv_UpdateLayeredWindow diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 01620c5e4a4..c45d12c7517 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -2432,7 +2432,8 @@ static char KEYBOARD_MapDeadKeysym(KeySym keysym) * */ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, - LPWSTR bufW, int bufW_size, UINT flags, HKL hkl) + LPWSTR bufW, int bufW_size, UINT flags, HKL hkl, + const WCHAR *default_buf, INT default_len) { Display *display = thread_init_display(); XKeyEvent e; diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index c0e24d8fe82..b73ae87b929 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -11,7 +11,7 @@ @ cdecl GetKeyboardLayoutName(ptr) X11DRV_GetKeyboardLayoutName @ cdecl LoadKeyboardLayout(wstr long) X11DRV_LoadKeyboardLayout @ cdecl MapVirtualKeyEx(long long long) X11DRV_MapVirtualKeyEx -@ cdecl ToUnicodeEx(long long ptr ptr long long long) X11DRV_ToUnicodeEx +@ cdecl ToUnicodeEx(long long ptr ptr long long long ptr long) X11DRV_ToUnicodeEx @ cdecl UnloadKeyboardLayout(long) X11DRV_UnloadKeyboardLayout @ cdecl VkKeyScanEx(long long) X11DRV_VkKeyScanEx @ cdecl DestroyCursorIcon(long) X11DRV_DestroyCursorIcon