diff options
author | Jon Turney <jon.turney@dronecode.org.uk> | 2017-01-15 16:10:19 +0000 |
---|---|---|
committer | Jon Turney <jon.turney@dronecode.org.uk> | 2017-01-27 16:49:04 +0000 |
commit | ea7d0de6ed657aa5e47e77a2a0c596d902504a61 (patch) | |
tree | dc228c5d762720c78784b9e76b1cd5085b190c88 | |
parent | 67d68912f3ccbc3927ceb7c4dc901547f0d0e9c3 (diff) |
deadkey handling
-rw-r--r-- | hw/xwin/winconfig.c | 270 |
1 files changed, 183 insertions, 87 deletions
diff --git a/hw/xwin/winconfig.c b/hw/xwin/winconfig.c index ce490f422..896813c35 100644 --- a/hw/xwin/winconfig.c +++ b/hw/xwin/winconfig.c @@ -28,6 +28,8 @@ * Authors: Alexander Gottwald */ +#define WINVER 0x0600 + #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif @@ -38,6 +40,8 @@ #include "xkbsrv.h" #include "keysym2ucs.h" +#include "wmutil/keyboard.h" +#include "wmutil/scancodes.h" #ifdef XWIN_XF86CONFIG #ifndef CONFIGPATH @@ -281,21 +285,24 @@ BuildModifierMaps(darwinKeyboardInfo *info) break; case XK_Meta_L: - info->modMap[MIN_KEYCODE + i] = Mod2Mask; + info->modMap[MIN_KEYCODE + i] = Mod1Mask; break; case XK_Meta_R: - info->modMap[MIN_KEYCODE + i] = Mod2Mask; + info->modMap[MIN_KEYCODE + i] = Mod1Mask; break; case XK_Num_Lock: - info->modMap[MIN_KEYCODE + i] = Mod3Mask; + info->modMap[MIN_KEYCODE + i] = Mod2Mask; break; case XK_Mode_switch: info->modMap[MIN_KEYCODE + i] = Mod5Mask; break; + case XK_ISO_Level3_Shift: + info->modMap[MIN_KEYCODE + i] = Mod5Mask; + break; } } } @@ -303,80 +310,122 @@ BuildModifierMaps(darwinKeyboardInfo *info) /* Table of virtualkey->keysym mappings for keys that are not Unicode characters */ const static struct { int vk; - KeySym ks; + KeySym ks[GLYPHS_PER_KEY]; } knownVKs[] = { - { VK_ESCAPE, XK_Escape }, - { VK_BACK, XK_BackSpace }, - { VK_TAB, XK_Tab }, - { VK_RETURN, XK_Return }, - { VK_CONTROL, XK_Control_L }, - { VK_LCONTROL, XK_Control_L }, - { VK_RCONTROL, XK_Control_R }, - { VK_SHIFT, XK_Shift_L }, - { VK_LSHIFT, XK_Shift_L }, - { VK_RSHIFT, XK_Shift_R }, - { VK_MENU, XK_Alt_L }, - { VK_LMENU, XK_Alt_L }, - { VK_RMENU, XK_Alt_R }, - { VK_CAPITAL, XK_Caps_Lock }, - - { VK_PAUSE, XK_Pause}, - { VK_SCROLL, XK_Scroll_Lock }, - { VK_SNAPSHOT, XK_Sys_Req }, + { VK_BACK , {XK_BackSpace, XK_BackSpace, XK_BackSpace, XK_BackSpace} }, + { VK_ESCAPE , {XK_Escape, XK_Escape, XK_Escape, XK_Escape} }, + { VK_RETURN , {XK_Return, XK_Return, XK_Return, XK_Return} }, + { VK_TAB , {XK_Tab, XK_Tab, XK_Tab, XK_Tab} }, + + /* Modifier keys */ + { VK_CONTROL , { XK_Control_L, XK_Control_L, XK_Control_L, XK_Control_L} }, + { VK_LCONTROL, { XK_Control_L, XK_Control_L, XK_Control_L, XK_Control_L} }, + { VK_RCONTROL, { XK_Control_R, XK_Control_R, XK_Control_R, XK_Control_R} }, + { VK_SHIFT , { XK_Shift_L, XK_Shift_L, XK_Shift_L, XK_Shift_L} }, + { VK_LSHIFT , { XK_Shift_L, XK_Shift_L, XK_Shift_L, XK_Shift_L} }, + { VK_RSHIFT , { XK_Shift_R, XK_Shift_R, XK_Shift_R, XK_Shift_R} }, + { VK_MENU , { XK_Alt_L, XK_Alt_L, XK_Alt_L, XK_Alt_L} }, + { VK_LMENU , { XK_Alt_L, XK_Alt_L, XK_Alt_L, XK_Alt_L} }, + // VK_RMENU ties up with the keyboard state used for modeswitched states + { VK_RMENU , { XK_ISO_Level3_Shift, XK_ISO_Level3_Shift, XK_ISO_Level3_Shift, XK_ISO_Level3_Shift} }, + { VK_CAPITAL , { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock} }, + { VK_LWIN , { XK_Super_L, XK_Super_L, XK_Super_L, XK_Super_L} }, + { VK_RWIN , { XK_Super_R, XK_Super_R, XK_Super_R, XK_Super_R} }, + + /* */ + { VK_CANCEL , { XK_Break, XK_Break, XK_Break, XK_Break} }, + { VK_PAUSE , { XK_Pause, XK_Pause, XK_Pause, XK_Pause} }, + { VK_SCROLL , { XK_Scroll_Lock, XK_Scroll_Lock, XK_Scroll_Lock, XK_Scroll_Lock} }, + { VK_SNAPSHOT, { XK_Sys_Req, XK_Sys_Req, XK_Sys_Req, XK_Sys_Req} }, + { VK_APPS , { XK_Menu, XK_Menu, XK_Menu, XK_Menu } }, /* function keys */ - { VK_F1, XK_F1 }, - { VK_F2, XK_F2 }, - { VK_F3, XK_F3 }, - { VK_F4, XK_F4 }, - { VK_F5, XK_F5 }, - { VK_F6, XK_F6 }, - { VK_F7, XK_F7 }, - { VK_F8, XK_F8 }, - { VK_F9, XK_F9 }, - { VK_F10, XK_F10 }, - { VK_F11, XK_F11 }, - { VK_F12, XK_F12 }, - { VK_F13, XK_F13 }, - { VK_F14, XK_F14 }, - { VK_F15, XK_F15 }, - { VK_F16, XK_F16 }, - { VK_F17, XK_F17 }, - { VK_F18, XK_F18 }, - { VK_F19, XK_F19 }, - { VK_F20, XK_F20 }, - { VK_F21, XK_F21 }, - { VK_F22, XK_F22 }, - { VK_F23, XK_F23 }, - { VK_F24, XK_F24 }, + { VK_F1 , { XK_F1, XK_F1, XK_F1, XK_F1 } }, + { VK_F2 , { XK_F2, XK_F2, XK_F2, XK_F2 } }, + { VK_F3 , { XK_F3, XK_F3, XK_F3, XK_F3 } }, + { VK_F4 , { XK_F4, XK_F4, XK_F4, XK_F4 } }, + { VK_F5 , { XK_F5, XK_F5, XK_F5, XK_F5 } }, + { VK_F6 , { XK_F6, XK_F6, XK_F6, XK_F6 } }, + { VK_F7 , { XK_F7, XK_F7, XK_F7, XK_F7 } }, + { VK_F8 , { XK_F8, XK_F8, XK_F8, XK_F8 } }, + { VK_F9 , { XK_F9, XK_F9, XK_F9, XK_F9 } }, + { VK_F10 , { XK_F10, XK_F10, XK_F10, XK_F10 } }, + { VK_F11 , { XK_F11, XK_F11, XK_F11, XK_F11 } }, + { VK_F12 , { XK_F12, XK_F12, XK_F12, XK_F12 } }, -#if 0 /* numpad */ - { VK_NUMLOCK, XK_Num_Lock }, - { VK_MULTIPLY, XK_KP_Multiply }, - { VK_ADD, XK_KP_Add }, - { VK_SUBTRACT, XK_KP_Subtract }, - { VK_DECIMAL, XK_KP_Decimal }, + { VK_NUMLOCK , { XK_Num_Lock, XK_Num_Lock, XK_Num_Lock, XK_Num_Lock } }, + { VK_ADD , { XK_KP_Add, XK_KP_Add, XK_KP_Add, XK_KP_Add } }, + { VK_DIVIDE , { XK_KP_Divide, XK_KP_Divide, XK_KP_Divide, XK_KP_Divide } }, + { VK_MULTIPLY, { XK_KP_Multiply, XK_KP_Multiply, XK_KP_Multiply, XK_KP_Multiply } }, + { VK_SUBTRACT, { XK_KP_Subtract, XK_KP_Subtract, XK_KP_Subtract, XK_KP_Subtract } }, + { VK_DECIMAL , { XK_KP_Delete, XK_KP_Decimal, XK_KP_Delete, XK_KP_Decimal } }, + { VK_NUMPAD0 , { XK_KP_Insert, XK_KP_0, XK_KP_Insert, XK_KP_0 } }, + { VK_NUMPAD1 , { XK_KP_End, XK_KP_1, XK_KP_End, XK_KP_1 } }, + { VK_NUMPAD2 , { XK_KP_Down, XK_KP_2, XK_KP_Down, XK_KP_2 } }, + { VK_NUMPAD3 , { XK_KP_Next, XK_KP_3, XK_KP_Next, XK_KP_3 } }, + { VK_NUMPAD4 , { XK_KP_Left, XK_KP_4, XK_KP_Left, XK_KP_4 } }, + { VK_NUMPAD5 , { XK_KP_Begin, XK_KP_5, XK_KP_Begin, XK_KP_5 } }, + { VK_NUMPAD6 , { XK_KP_Right, XK_KP_6, XK_KP_Right, XK_KP_6 } }, + { VK_NUMPAD7 , { XK_KP_Home, XK_KP_7, XK_KP_Home, XK_KP_7 } }, + { VK_NUMPAD8 , { XK_KP_Up, XK_KP_8, XK_KP_Up, XK_KP_8 } }, + { VK_NUMPAD9 , { XK_KP_Prior, XK_KP_9, XK_KP_Prior, XK_KP_9 } }, /* cursor motion */ - { VK_PRIOR, XK_Page_Up }, - { VK_NEXT, XK_Page_Down }, - { VK_END, XK_End }, - { VK_HOME, XK_Home }, - { VK_LEFT, XK_Left }, - { VK_UP, XK_Up }, - { VK_RIGHT, XK_Right }, - { VK_DOWN, XK_Down }, -#endif + { VK_DELETE , { XK_Delete, XK_Delete, XK_Delete, XK_Delete } }, + { VK_DOWN , { XK_Down, XK_Down, XK_Down, XK_Down } }, + { VK_END , { XK_End, XK_End, XK_End, XK_End } }, + { VK_HOME , { XK_Home, XK_Home, XK_Home, XK_Home } }, + { VK_INSERT , { XK_Insert, XK_Insert, XK_Insert, XK_Insert } }, + { VK_LEFT , { XK_Left, XK_Left, XK_Left, XK_Left } }, + { VK_NEXT , { XK_Page_Down, XK_Page_Down, XK_Page_Down, XK_Page_Down } }, + { VK_PRIOR , { XK_Page_Up, XK_Page_Up, XK_Page_Up, XK_Page_Up } }, + { VK_RIGHT , { XK_Right, XK_Right, XK_Right, XK_Right } }, + { VK_UP , { XK_Up, XK_Up, XK_Up, XK_Up } }, }; static KeySym -VKToKeySym(UINT vk) +VKToKeySym(UINT vk, int state) { int i; for (i = 0; i < sizeof(knownVKs) / sizeof(knownVKs[0]); i++) - if (knownVKs[i].vk == vk) return knownVKs[i].ks; + if (knownVKs[i].vk == vk) return knownVKs[i].ks[state]; + + return 0; +} + +const static struct { + WCHAR diacritic; + KeySym dead; +} dead_keys[] = { + /* This table is sorted by KeySym value */ + { L'`', XK_dead_grave }, /* U+0060 GRAVE ACCENT */ + { L'\'', XK_dead_acute }, /* U+0027 APOSTROPHE */ + { L'´', XK_dead_acute }, /* U+00B4 ACUTE ACCENT */ + { L'^', XK_dead_circumflex }, /* U+005E CIRCUMFLEX ACCENT */ + { L'~', XK_dead_tilde }, /* U+007E TILDE */ + { L'¯', XK_dead_macron }, /* U+00AF MARK */ + { L'˘', XK_dead_breve }, /* U+02D8 BREVE */ + { L'˙', XK_dead_abovedot }, /* U+02D9 DOT ABOVE */ + { L'¨', XK_dead_diaeresis }, /* U+00A8 DIAERESIS */ + { L'"', XK_dead_diaeresis }, /* U+0022 QUOTATION MARK */ + { L'°', XK_dead_abovering }, /* U+00B0 DEGREE SIGN */ + { L'˝', XK_dead_doubleacute }, /* U+02DD DOUBLE ACUTE ACCENT */ + { L'ˇ', XK_dead_caron }, /* U+02C7 CARON */ + { L'¸', XK_dead_cedilla }, /* U+00B8 CEDILLA */ + { L'˛', XK_dead_ogonek }, /* U+02DB OGONEK */ + /* This table is incomplete ... */ +}; + +/* Map the spacing form of a diacritic glyph to a deadkey KeySym */ +static KeySym +make_dead_key(WCHAR in) +{ + int i; + + for (i = 0; i < sizeof(dead_keys) / sizeof(dead_keys[0]); i++) + if (dead_keys[i].diacritic == in) return dead_keys[i].dead; return 0; } @@ -526,7 +575,7 @@ winConfigKeyboard(DeviceIntPtr pDevice) /* If that fails, try converting the Windows layout */ if (!bfound) { - int sc; + UINT vk; int j; darwinKeyboardInfo keyInfo; memset(keyInfo.modMap, 0, MAP_LENGTH); @@ -552,67 +601,114 @@ winConfigKeyboard(DeviceIntPtr pDevice) if ((j % 2) == 1) state[VK_SHIFT] = 0x80; if (j >= 2) { + // VK_RMENU is mapped to XK_ISO_Level3_Shift // AltGR = Alt + Control // (what to use here might depend on layout?) state[VK_CONTROL] = 0x80; state[VK_MENU] = 0x80; } - ErrorF("state %d\n", j); + winDebug("Examining %s%s layout\n", (j % 2) ? "shift " : "", + (j >= 2) ? "altgr" : ""); - for (sc = 0; sc < 128; sc++) { - UINT vk; + for (vk = 0; vk < 0xff; vk++) { + int sc; KeySym ks; - WCHAR out[2]; char keyName[64]; - /* Translate scan code to Virtual Key code */ - vk = MapVirtualKey(sc, MAPVK_VSC_TO_VK_EX); - if (vk == 0) + /* Translate Virtual Key code to extended scan code */ + sc = MapVirtualKey(vk, MAPVK_VK_TO_VSC_EX); + if (sc == 0) continue; + /* Workaround what appear to be bugs in MAPVK_VK_TO_VSC_EX */ + if (((vk >= VK_PRIOR) && (vk <= VK_DOWN)) || + (vk == VK_INSERT) || (vk == VK_DELETE)) { + /* cursor keys are extended keys */ + sc = sc | 0xe000; + } + + /* Munge as we do actual key events, to translate extended + scancodes into the server generated ones */ + { + int tsc; + tsc = winTranslateKey(vk, + ((sc & 0xff) | (sc & 0xe000 ? 0x100 : 0)) << 16); + + if (tsc != sc) { + winDebug("scan code munged %x -> %x\n", sc, tsc); + sc = tsc; + } + } + GetKeyNameText(sc << 16, keyName, sizeof(keyName)); /* Is the KeySym for the VK_ known ?*/ - ks = VKToKeySym(vk); + ks = VKToKeySym(vk, j); if (ks) { - ErrorF("scan code %x (%s), VK %x -> keysym %x\n", sc, keyName, vk, ks); + winDebug("scan code %x (%s), VK %x -> keysym %x\n", sc, keyName, vk, ks); } else { /* What unicode characters are output by that key in this modifier state */ int result; - result = ToUnicode(vk, sc, state, &out[0], 2, 0); + WCHAR out[8]; + char outAsUtf8[8]; + memset(outAsUtf8, 0, 8); + + result = ToUnicode(vk, sc, state, &out[0], 8, 0); + + if (result != 0) { + int len = WideCharToMultiByte(CP_UTF8, 0, out, 1, outAsUtf8, 8, NULL, NULL); + outAsUtf8[len] = '\0'; + } switch (result) { case -1: // dead-key - ErrorF("scan code %x (%s), VK %x -> deadkey\n", sc, keyName, vk); + ks = make_dead_key(out[0]); + if (ks) + winDebug("scan code %x (%s), VK %x -> deadkey %x ('%s') -> keysym %x\n", sc, keyName, vk, out[0], outAsUtf8, ks); + else + ErrorF("scan code %x (%s), VK %x -> deadkey %x ('%s') -> unknown keysym\n", sc, keyName, vk, out[0], outAsUtf8); + + // Force the partially-composed state to be + // discarded, so it doesn't effect the next call to + // ToUnicode(). + ToUnicode(vk, sc, state, &out[0], 8, 0); + break; case 0: // nothing - ErrorF("scan code %x (%s), VK %x -> nothing\n", sc, keyName, vk); + winDebug("scan code %x (%s), VK %x -> nothing\n", sc, keyName, vk); break; case 1: // something - { - char outAsUtf8[8]; - int len = WideCharToMultiByte(CP_UTF8, 0, out, 1, outAsUtf8, 8, NULL, NULL); - outAsUtf8[len] = '\0'; - - ks = ucs2keysym(out[0]); - - ErrorF("scan code %x (%s), VK %x -> Unicode %x ('%s') -> keysym %x\n", sc, keyName, vk, out[0], outAsUtf8, ks); - } + ks = ucs2keysym(out[0]); + winDebug("scan code %x (%s), VK %x -> unicode %x ('%s') -> keysym %x\n", sc, keyName, vk, out[0], outAsUtf8, ks); break; + default: case 2: // too much - ErrorF("scan code %x (%s), VK %x produced more than one unicode character\n", sc, keyName, vk); + ErrorF("scan code %x (%s), VK %x produced %d unicode characters ('%s')\n", sc, keyName, vk, result, outAsUtf8); break; } } if (ks) { KeySym *k; - k = keyInfo.keyMap + sc * GLYPHS_PER_KEY; + k = keyInfo.keyMap + (sc & 0xff) * GLYPHS_PER_KEY; + if ((k[j]) && (k[j] != ks)) + ErrorF("X KeyCode collision\n"); k[j] = ks; } } + + /* keypad_enter doesn't have a separate VK code, so we need to + add it ourselves */ + { + int sc; + KeySym *k; + + sc = KEY_KP_Enter; + k = keyInfo.keyMap + (sc & 0xff) * GLYPHS_PER_KEY; + k[j] = XK_KP_Enter; + } } // Build the modmap |