Added dead keys support using X input methods (based on a patch by Dmitry Timoshkov).
diff --git a/dlls/x11drv/event.c b/dlls/x11drv/event.c index 399ce34..a570993 100644 --- a/dlls/x11drv/event.c +++ b/dlls/x11drv/event.c
@@ -136,9 +136,12 @@ wine_tsx11_lock(); while ( XPending( data->display ) ) { + Bool ignore; + XNextEvent( data->display, &event ); + ignore = XFilterEvent( &event, None ); wine_tsx11_unlock(); - EVENT_ProcessEvent( &event ); + if (!ignore) EVENT_ProcessEvent( &event ); count++; wine_tsx11_lock(); } @@ -478,13 +481,22 @@ */ static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event ) { + XIC xic; + if (!hwnd) return; TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] ); - if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */ if (event->detail == NotifyPointer) return; + if ((xic = X11DRV_get_ic( hwnd ))) + { + wine_tsx11_lock(); + XSetICFocus( xic ); + wine_tsx11_unlock(); + } + if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */ + if (!can_activate_window(hwnd)) { HWND hwnd = GetFocus(); @@ -507,11 +519,18 @@ HWND hwnd_tmp; Window focus_win; int revert; + XIC xic; TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] ); if (event->detail == NotifyPointer) return; x11drv_thread_data()->last_focus = hwnd; + if ((xic = X11DRV_get_ic( hwnd ))) + { + wine_tsx11_lock(); + XUnsetICFocus( xic ); + wine_tsx11_unlock(); + } if (hwnd != GetForegroundWindow()) return; SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
diff --git a/dlls/x11drv/keyboard.c b/dlls/x11drv/keyboard.c index 13d3dfc..73c67cd 100644 --- a/dlls/x11drv/keyboard.c +++ b/dlls/x11drv/keyboard.c
@@ -840,11 +840,14 @@ /* Returns the Windows virtual key code associated with the X event <e> */ /* x11 lock must be held */ -static WORD EVENT_event_to_vkey( XKeyEvent *e) +static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e) { KeySym keysym; - XLookupString(e, NULL, 0, &keysym, NULL); + if (xic) + XmbLookupString(xic, e, NULL, 0, &keysym, NULL); + else + XLookupString(e, NULL, 0, &keysym, NULL); if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF) && (e->state & NumLockMask)) @@ -988,7 +991,7 @@ WORD vkey = 0, bScan; DWORD dwFlags; int ascii_chars; - + XIC xic = X11DRV_get_ic( hwnd ); DWORD event_time = event->time - X11DRV_server_startticks; /* this allows support for dead keys */ @@ -996,18 +999,12 @@ event->keycode=(event->keycode & 0xff); wine_tsx11_lock(); - ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL); + if (xic) + ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, NULL); + else + ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL); wine_tsx11_unlock(); - /* Ignore some unwanted events */ - if (keysym == XK_ISO_Prev_Group || - keysym == XK_ISO_Next_Group || - keysym == XK_Mode_switch) - { - TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym)); - return; - } - TRACE_(key)("state = %X\n", event->state); /* If XKB extensions are used, the state mask for AltGr will use the group @@ -1034,7 +1031,9 @@ } wine_tsx11_lock(); - vkey = EVENT_event_to_vkey(event); + 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 0x%x converted to vkey 0x%x\n", @@ -1123,7 +1122,19 @@ keysym = XKeycodeToKeysym (display, keyc, i); /* Allow both one-byte and two-byte national keysyms */ if ((keysym < 0x8000) && (keysym != ' ')) - ckey[i] = keysym & 0xFF; + { +#ifdef HAVE_XKB + if (!is_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL)) +#endif + { + TRACE("XKB could not translate keysym %ld\n", keysym); + /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent + * with appropriate ShiftMask and Mode_switch, use XLookupString + * to get character in the local encoding. + */ + ckey[i] = keysym & 0xFF; + } + } else { ckey[i] = KEYBOARD_MapDeadKeysym(keysym); } @@ -1277,8 +1288,18 @@ int maxlen=0,maxval=-1,ok; for (i=0; i<syms; i++) { keysym = XKeycodeToKeysym(display, keyc, i); - if ((keysym<0x800) && (keysym!=' ')) { - ckey[i] = keysym & 0xFF; + if ((keysym<0x800) && (keysym!=' ')) + { +#ifdef HAVE_XKB + if (!is_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL)) +#endif + { + /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent + * with appropriate ShiftMask and Mode_switch, use XLookupString + * to get character in the local encoding. + */ + ckey[i] = keysym & 0xFF; + } } else { ckey[i] = KEYBOARD_MapDeadKeysym(keysym); } @@ -1507,7 +1528,7 @@ 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(&e) & 0xFF) != wCode) { + 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 */ } @@ -1751,16 +1772,27 @@ KeySym keysym; INT ret; int keyc; - BYTE lpChar[2]; + char lpChar[2]; + HWND focus; + XIC xic; if (scanCode & 0x8000) { TRACE("Key UP, doing nothing\n" ); return 0; } + e.display = display; e.keycode = 0; e.state = 0; + e.type = KeyPress; + + focus = GetFocus(); + if (focus) focus = GetAncestor( focus, GA_ROOT ); + if (!focus) focus = GetActiveWindow(); + e.window = X11DRV_get_whole_window( focus ); + xic = X11DRV_get_ic( focus ); + if (lpKeyState[VK_SHIFT] & 0x80) { TRACE("ShiftMask = %04x\n", ShiftMask); @@ -1795,7 +1827,7 @@ if ((keyc2vkey[keyc] & 0xFF) == virtKey) { /* We filter the extended bit, we don't know it */ e.keycode = keyc; /* Store it temporarily */ - if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) { + if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) { e.keycode = 0; /* Wrong one (ex: because of the NumLock state), so set it to 0, we'll find another one */ } @@ -1808,7 +1840,7 @@ if (virtKey==VK_DECIMAL) e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal); - if (!e.keycode) + if (!e.keycode && virtKey != VK_NONAME) { WARN("Unknown virtual key %X !!! \n",virtKey); wine_tsx11_unlock(); @@ -1816,7 +1848,10 @@ } else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode); - ret = XLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL); + if (xic) + ret = XmbLookupString(xic, &e, lpChar, 2, &keysym, NULL); + else + ret = XLookupString(&e, lpChar, 2, &keysym, NULL); wine_tsx11_unlock(); if (ret == 0) @@ -1852,7 +1887,7 @@ && (e.state & ShiftMask) /* Shift is pressed */ && (keysym>=XK_KP_0) && (keysym<=XK_KP_9)) { - *(char*)lpChar = 0; + lpChar[0] = 0; ret = 0; } @@ -1863,7 +1898,7 @@ if (((keysym>=33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) { - *(char*)lpChar = 0; + lpChar[0] = 0; ret = 0; } } @@ -1872,13 +1907,13 @@ extended keyboard. X returns a char for it, but Windows doesn't */ if (keysym == XK_Delete) { - *(char*)lpChar = 0; + lpChar[0] = 0; ret = 0; } else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */ && (keysym == XK_KP_Decimal)) { - *(char*)lpChar = 0; + lpChar[0] = 0; ret = 0; } @@ -1887,7 +1922,7 @@ { TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n", *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp); - ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size); + ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, lpChar, ret, bufW, bufW_size); } }