summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Turney <jon.turney@dronecode.org.uk>2017-01-15 16:10:19 +0000
committerJon Turney <jon.turney@dronecode.org.uk>2017-01-27 16:49:04 +0000
commitea7d0de6ed657aa5e47e77a2a0c596d902504a61 (patch)
treedc228c5d762720c78784b9e76b1cd5085b190c88
parent67d68912f3ccbc3927ceb7c4dc901547f0d0e9c3 (diff)
deadkey handling
-rw-r--r--hw/xwin/winconfig.c270
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