From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/wayland.c | 1 + dlls/winewayland.drv/wayland_keyboard.c | 231 ++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 8 +- dlls/winewayland.drv/waylanddrv_main.c | 2 + 4 files changed, 241 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 31c225e76d7..0740d4c179a 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -35,6 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); struct wayland process_wayland = { .seat.mutex = PTHREAD_MUTEX_INITIALIZER, + .keyboard.mutex = PTHREAD_MUTEX_INITIALIZER, .pointer.mutex = PTHREAD_MUTEX_INITIALIZER, .output_list = {&process_wayland.output_list, &process_wayland.output_list}, .output_mutex = PTHREAD_MUTEX_INITIALIZER diff --git a/dlls/winewayland.drv/wayland_keyboard.c b/dlls/winewayland.drv/wayland_keyboard.c index fb2f4b0ab6f..ac0b5128323 100644 --- a/dlls/winewayland.drv/wayland_keyboard.c +++ b/dlls/winewayland.drv/wayland_keyboard.c @@ -31,8 +31,11 @@ #include <sys/mman.h> #include <unistd.h>
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "waylanddrv.h" #include "wine/debug.h" +#include "ime.h"
WINE_DEFAULT_DEBUG_CHANNEL(keyboard); WINE_DECLARE_DEBUG_CHANNEL(key); @@ -220,6 +223,91 @@ static WORD key2scan(UINT key) return 0x200 | (key & 0x7f); }
+static UINT scan2key(WORD scan) +{ + /* base keys can be mapped directly */ + if (scan <= KEY_KPDOT) return scan; + + /* map keys found in KBDTABLES definitions (Txx Xxx Yxx macros) */ + switch (scan) + { + case 0x005a: return 84 /* ISO_Level3_Shift */; /* T5A / VK_OEM_WSCTRL */ + case 0x0054: return KEY_SYSRQ; /* T54 / VK_SNAPSHOT */ + case 0x0056: return KEY_102ND; /* T56 / VK_OEM_102 */ + case 0x0057: return KEY_F11; /* T57 / VK_F11 */ + case 0x0058: return KEY_F12; /* T58 / VK_F12 */ + case 0x0059: return KEY_LINEFEED; /* T59 / VK_CLEAR */ + case 0x005b: return KEY_EXIT; /* T5B / VK_OEM_FINISH */ + case 0x005c: return KEY_OPEN; /* T5C / VK_OEM_JUMP */ + /* case 0x005d: return KEY_EREOF; */ /* T5D / VK_EREOF */ + /* case 0x005e: return KEY_OEM_BACKTAB; */ /* T5E / VK_OEM_BACKTAB */ + case 0x005f: return KEY_COMPOSE; /* T5F / VK_OEM_AUTO */ + case 0x0062: return KEY_SCALE; /* T62 / VK_ZOOM */ + case 0x0063: return KEY_HELP; /* T63 / VK_HELP */ + case 0x0064: return KEY_F13; /* T64 / VK_F13 */ + case 0x0065: return KEY_F14; /* T65 / VK_F14 */ + case 0x0066: return KEY_F15; /* T66 / VK_F15 */ + case 0x0067: return KEY_F16; /* T67 / VK_F16 */ + case 0x0068: return KEY_F17; /* T68 / VK_F17 */ + case 0x0069: return KEY_F18; /* T69 / VK_F18 */ + case 0x006a: return KEY_F19; /* T6A / VK_F19 */ + case 0x006b: return KEY_F20; /* T6B / VK_F20 */ + case 0x006c: return KEY_F21; /* T6C / VK_F21 */ + case 0x006d: return KEY_F22; /* T6D / VK_F22 */ + case 0x006e: return KEY_F23; /* T6E / VK_F23 */ + /* case 0x006f: return KEY_OEM_PA3; */ /* T6F / VK_OEM_PA3 */ + case 0x0071: return KEY_COMPUTER; /* T71 / VK_OEM_RESET */ + /* case 0x0073: return KEY_ABNT_C1; */ /* T73 / VK_ABNT_C1 */ + case 0x0076: return KEY_F24; /* T76 / VK_F24 */ + case 0x007b: return KEY_KPPLUSMINUS; /* T7B / VK_OEM_PA1 */ + case 0x007c: return KEY_TAB; /* T7C / VK_TAB */ + /* case 0x007e: return KEY_ABNT_C2; */ /* T7E / VK_ABNT_C2 */ + /* case 0x007f: return KEY_OEM_PA2; */ /* T7F / VK_OEM_PA2 */ + case 0x0110: return KEY_PREVIOUSSONG; /* X10 / VK_MEDIA_PREV_TRACK */ + case 0x0119: return KEY_NEXTSONG; /* X19 / VK_MEDIA_NEXT_TRACK */ + case 0x011c: return KEY_KPENTER; /* X1C / VK_RETURN */ + case 0x011d: return KEY_RIGHTCTRL; /* X1D / VK_RCONTROL */ + case 0x0120: return KEY_MUTE; /* X20 / VK_VOLUME_MUTE */ + case 0x0121: return KEY_PROG2; /* X21 / VK_LAUNCH_APP2 */ + case 0x0122: return KEY_PLAYPAUSE; /* X22 / VK_MEDIA_PLAY_PAUSE */ + case 0x0124: return KEY_STOPCD; /* X24 / VK_MEDIA_STOP */ + case 0x012e: return KEY_VOLUMEDOWN; /* X2E / VK_VOLUME_DOWN */ + case 0x0130: return KEY_VOLUMEUP; /* X30 / VK_VOLUME_UP */ + case 0x0132: return KEY_HOMEPAGE; /* X32 / VK_BROWSER_HOME */ + case 0x0135: return KEY_KPSLASH; /* X35 / VK_DIVIDE */ + case 0x0137: return KEY_PRINT; /* X37 / VK_SNAPSHOT */ + case 0x0138: return KEY_RIGHTALT; /* X38 / VK_RMENU */ + case 0x0146: return KEY_CANCEL; /* X46 / VK_CANCEL */ + case 0x0147: return KEY_HOME; /* X47 / VK_HOME */ + case 0x0148: return KEY_UP; /* X48 / VK_UP */ + case 0x0149: return KEY_PAGEUP; /* X49 / VK_PRIOR */ + case 0x014b: return KEY_LEFT; /* X4B / VK_LEFT */ + case 0x014d: return KEY_RIGHT; /* X4D / VK_RIGHT */ + case 0x014f: return KEY_END; /* X4F / VK_END */ + case 0x0150: return KEY_DOWN; /* X50 / VK_DOWN */ + case 0x0151: return KEY_PAGEDOWN; /* X51 / VK_NEXT */ + case 0x0152: return KEY_INSERT; /* X52 / VK_INSERT */ + case 0x0153: return KEY_DELETE; /* X53 / VK_DELETE */ + case 0x015b: return KEY_LEFTMETA; /* X5B / VK_LWIN */ + case 0x015c: return KEY_RIGHTMETA; /* X5C / VK_RWIN */ + case 0x015d: return KEY_MENU; /* X5D / VK_APPS */ + case 0x015e: return KEY_POWER; /* X5E / VK_POWER */ + case 0x015f: return KEY_SLEEP; /* X5F / VK_SLEEP */ + case 0x0165: return KEY_FIND; /* X65 / VK_BROWSER_SEARCH */ + case 0x0166: return KEY_BOOKMARKS; /* X66 / VK_BROWSER_FAVORITES */ + case 0x0167: return KEY_REFRESH; /* X67 / VK_BROWSER_REFRESH */ + case 0x0168: return KEY_STOP; /* X68 / VK_BROWSER_STOP */ + case 0x0169: return KEY_FORWARD; /* X69 / VK_BROWSER_FORWARD */ + case 0x016a: return KEY_BACK; /* X6A / VK_BROWSER_BACK */ + case 0x016b: return KEY_PROG1; /* X6B / VK_LAUNCH_APP1 */ + case 0x016c: return KEY_MAIL; /* X6C / VK_LAUNCH_MAIL */ + case 0x016d: return KEY_MEDIA; /* X6D / VK_LAUNCH_MEDIA_SELECT */ + case 0x021d: return KEY_PAUSE; /* Y1D / VK_PAUSE */ + } + + return 0; +} + static inline LANGID langid_from_xkb_layout(const char *layout, size_t layout_len) { #define MAKEINDEX(c0, c1) (MAKEWORD(c0, c1) - MAKEWORD('a', 'a')) @@ -622,8 +710,10 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
if ((xkb_state = xkb_state_new(xkb_keymap))) { + pthread_mutex_lock(&keyboard->mutex); xkb_state_unref(keyboard->xkb_state); keyboard->xkb_state = xkb_state; + pthread_mutex_unlock(&keyboard->mutex); }
xkb_keymap_unref(xkb_keymap); @@ -719,8 +809,11 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboar TRACE("serial=%u mods_depressed=%#x mods_latched=%#x mods_locked=%#x xkb_group=%d stub!\n", serial, mods_depressed, mods_latched, mods_locked, xkb_group);
+ pthread_mutex_lock(&keyboard->mutex); xkb_state_update_mask(keyboard->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, xkb_group); + pthread_mutex_unlock(&keyboard->mutex); + set_current_xkb_group(xkb_group);
/* TODO: Sync wine modifier state with XKB modifier state. */ @@ -759,6 +852,14 @@ static const struct wl_keyboard_listener keyboard_listener = { void wayland_keyboard_init(struct wayland_keyboard *keyboard, struct wayland *wayland, struct wl_keyboard *wl_keyboard) { + struct xkb_compose_table *compose_table; + const char *locale; + + locale = getenv("LC_ALL"); + if (!locale || !*locale) locale = getenv("LC_CTYPE"); + if (!locale || !*locale) locale = getenv("LANG"); + if (!locale || !*locale) locale = "C"; + keyboard->wl_keyboard = wl_keyboard;
if (!(keyboard->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS))) @@ -767,6 +868,17 @@ void wayland_keyboard_init(struct wayland_keyboard *keyboard, struct wayland *wa return; }
+ if ((compose_table = xkb_compose_table_new_from_locale(keyboard->xkb_context, locale, + XKB_COMPOSE_COMPILE_NO_FLAGS))) + { + keyboard->xkb_compose_state = + xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + xkb_compose_table_unref(compose_table); + } + + if (!keyboard->xkb_compose_state) + ERR("Failed to create XKB compose table\n"); + rxkb_context = rxkb_context_new(RXKB_CONTEXT_NO_FLAGS); if (!rxkb_context_parse_default_ruleset(rxkb_context)) ERR("Failed to parse default Xkb ruleset\n"); @@ -783,6 +895,7 @@ void wayland_keyboard_deinit(struct wayland_keyboard *keyboard) if (keyboard->wl_keyboard) wl_keyboard_destroy(keyboard->wl_keyboard);
+ xkb_compose_state_unref(keyboard->xkb_compose_state); xkb_state_unref(keyboard->xkb_state); xkb_context_unref(keyboard->xkb_context); memset(keyboard, 0, sizeof(*keyboard)); @@ -828,3 +941,121 @@ void WAYLAND_ReleaseKbdTables(const KBDTABLES *tables) struct layout *layout = CONTAINING_RECORD(tables, struct layout, tables); xkb_layout_release(layout); } + +/*********************************************************************** + * ImeProcessKey (WAYLANDDRV.@) + */ +UINT WAYLAND_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *key_state) +{ + struct wayland_keyboard *keyboard = &process_wayland.keyboard; + WORD scan = HIWORD(lparam) & 0x1ff, vkey = LOWORD(wparam); + BOOL repeat = !!(lparam >> 30), pressed = !(lparam >> 31); + UINT key = scan2key(scan); + xkb_keysym_t xkb_keysym; + BOOL ret = FALSE; + + TRACE_(key)("himc=%p scan=%#x vkey=%#x repeat=%u pressed=%u\n", + himc, scan, vkey, repeat, pressed); + + if (!pressed) return FALSE; + + pthread_mutex_lock(&keyboard->mutex); + + if ((xkb_keysym = xkb_state_key_get_one_sym(keyboard->xkb_state, key + 8)) != XKB_KEY_NoSymbol && + (xkb_compose_state_feed(keyboard->xkb_compose_state, xkb_keysym)) == XKB_COMPOSE_FEED_ACCEPTED) + { + enum xkb_compose_status compose_status = xkb_compose_state_get_status(keyboard->xkb_compose_state); + if (compose_status == XKB_COMPOSE_COMPOSING || compose_status == XKB_COMPOSE_COMPOSED) ret = TRUE; + } + + pthread_mutex_unlock(&keyboard->mutex); + + return ret; +} + +/*********************************************************************** + * ImeToAsciiEx (WAYLANDDRV.@) + */ +UINT WAYLAND_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc) +{ + DWORD needed = sizeof(COMPOSITIONSTRING), comp_len, result_len, len, size; + struct wayland_keyboard *keyboard = &process_wayland.keyboard; + enum xkb_compose_status compose_status; + char buffer[64]; + void *dst; + + TRACE_(key)("vkey=%#x vsc=%#x state=%p compstr=%p himc=%p\n", vkey, vsc, state, compstr, himc); + + pthread_mutex_lock(&keyboard->mutex); + compose_status = xkb_compose_state_get_status(keyboard->xkb_compose_state); + len = xkb_compose_state_get_utf8(keyboard->xkb_compose_state, buffer, sizeof(buffer)); + pthread_mutex_unlock(&keyboard->mutex); + + if (compose_status != XKB_COMPOSE_COMPOSING) comp_len = 0; + else + { + comp_len = len; + needed += comp_len * sizeof(WCHAR); /* GCS_COMPSTR */ + needed += comp_len; /* GCS_COMPATTR */ + needed += 2 * sizeof(DWORD); /* GCS_COMPCLAUSE */ + } + + if (compose_status != XKB_COMPOSE_COMPOSED) result_len = 0; + else + { + result_len = len; + needed += result_len * sizeof(WCHAR); /* GCS_RESULTSTR */ + needed += 2 * sizeof(DWORD); /* GCS_RESULTCLAUSE */ + } + + if (compstr->dwSize < needed) + { + compstr->dwSize = needed; + return STATUS_BUFFER_TOO_SMALL; + } + + memset(compstr, 0, sizeof(*compstr)); + compstr->dwSize = sizeof(*compstr); + + if (compose_status == XKB_COMPOSE_COMPOSING) + { + compstr->dwCursorPos = 0; + + compstr->dwCompStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompStrOffset; + RtlUTF8ToUnicodeN(dst, len * sizeof(WCHAR), &size, buffer, len); + compstr->dwCompStrLen = size / sizeof(WCHAR); + compstr->dwSize += size; + + compstr->dwCompClauseLen = 2 * sizeof(DWORD); + compstr->dwCompClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwCompStrLen; + compstr->dwSize += compstr->dwCompClauseLen; + + compstr->dwCompAttrLen = compstr->dwCompStrLen; + compstr->dwCompAttrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompAttrOffset; + memset(dst, ATTR_INPUT, compstr->dwCompAttrLen); + compstr->dwSize += compstr->dwCompAttrLen; + } + + if (compose_status == XKB_COMPOSE_COMPOSED) + { + compstr->dwResultStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwResultStrOffset; + RtlUTF8ToUnicodeN(dst, len * sizeof(WCHAR), &size, buffer, len); + compstr->dwResultStrLen = size / sizeof(WCHAR); + compstr->dwSize += size; + + compstr->dwResultClauseLen = 2 * sizeof(DWORD); + compstr->dwResultClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwResultClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwResultStrLen; + compstr->dwSize += compstr->dwResultClauseLen; + } + + return 0; +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index fa5e12acf77..52d56280d78 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -28,6 +28,7 @@ #include <pthread.h> #include <wayland-client.h> #include <xkbcommon/xkbcommon.h> +#include <xkbcommon/xkbcommon-compose.h> #include <xkbcommon/xkbregistry.h> #include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" @@ -71,9 +72,12 @@ struct wayland_keyboard { struct wl_keyboard *wl_keyboard; struct xkb_context *xkb_context; - struct xkb_state *xkb_state; HWND focused_hwnd; HKL last_hkl; + + pthread_mutex_t mutex; + struct xkb_state *xkb_state; + struct xkb_compose_state *xkb_compose_state; };
struct wayland_cursor @@ -244,6 +248,8 @@ void wayland_keyboard_init(struct wayland_keyboard *keyboard, struct wayland *wa void wayland_keyboard_deinit(struct wayland_keyboard *keyboard) DECLSPEC_HIDDEN; const KBDTABLES *WAYLAND_KbdLayerDescriptor(HKL hkl) DECLSPEC_HIDDEN; void WAYLAND_ReleaseKbdTables(const KBDTABLES *) DECLSPEC_HIDDEN; +UINT WAYLAND_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *key_state) DECLSPEC_HIDDEN; +UINT WAYLAND_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc) DECLSPEC_HIDDEN;
/********************************************************************** * Wayland pointer diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 93d32e9e38a..89a32edf9e6 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -35,6 +35,8 @@ static const struct user_driver_funcs waylanddrv_funcs = .pDestroyWindow = WAYLAND_DestroyWindow, .pKbdLayerDescriptor = WAYLAND_KbdLayerDescriptor, .pReleaseKbdTables = WAYLAND_ReleaseKbdTables, + .pImeProcessKey = WAYLAND_ImeProcessKey, + .pImeToAsciiEx = WAYLAND_ImeToAsciiEx, .pSetCursor = WAYLAND_SetCursor, .pSysCommand = WAYLAND_SysCommand, .pUpdateDisplayDevices = WAYLAND_UpdateDisplayDevices,