+static void keymap_lookup_key(MappedKey *mk, KeySym sym, const char *what) {
+ const MappedModifier *shift, *xshift;
+ int col, kc;
+ char cols[MAXMAPCOL+1];
+
+ memset(cols,'.',MAXMAPCOL);
+ cols[MAXMAPCOL]= 0;
+
+ for (col=0; col<mapwidth && col<MAXMAPCOL; col++) {
+ keydebugf("KEYMAP lookup %-10s %#lx col=%d ",
+ what, (unsigned long)sym, col);
+
+#define CHECK_SHIFT(sh) do{ \
+ if ((sh) && (sh)->isdef!='y') { \
+ cols[col]= (sh)->isdef; \
+ keydebugf("no-modifier " #sh "'%c'\n", (sh)->isdef); \
+ continue; \
+ } \
+ }while(0)
+
+ shift= col & 1 ? &mm_shift : 0;
+ CHECK_SHIFT(shift);
+
+ xshift= col >= 4 ? &mm_isol3shift :
+ col >= 2 ? &mm_modeswitch :
+ 0;
+ CHECK_SHIFT(xshift);
+
+ for (kc=kc_min; kc <= kc_max; kc++) {
+ if (mapping[(kc-kc_min)*mapwidth + col] == sym)
+ goto found;
+ }
+ cols[col]= '_';
+ keydebugf("not-found\n");
+ }
+ fprintf(stderr,"\n"
+ "Unable to find a key to press to generate %s.\n"
+ "(Technical details: cols:%s sh:%c:%d modesw:%c:%d isol3:%c:%d)\n",
+ what, cols,
+#define SH_DETAILS(sh) mm_##sh.isdef, mm_##sh.kc
+ SH_DETAILS(shift), SH_DETAILS(modeswitch), SH_DETAILS(isol3shift));
+ fatal("Keymap is unsuitable!");
+
+ found:;
+ int *fill= mk->kc;
+
+ if (xshift) *fill++ = xshift->kc;
+ if (shift) *fill++ = shift->kc;
+ *fill++ += kc;
+ mk->len= fill - mk->kc;
+ keydebugf("found kc=%d len=%d\n",kc,mk->len);
+}
+
+static void keymap_startup(void) {
+ xassert( XDisplayKeycodes(disp,&kc_min,&kc_max) );
+ keydebugf("KEYMAP keycodes %d..%d\n",kc_min,kc_max);
+
+ xassert( mapping= XGetKeyboardMapping(disp, kc_min, kc_max-kc_min+1,
+ &mapwidth) );
+ keydebugf("KEYMAP got keyboard map\n");
+
+ XModifierKeymap *modmap;
+ xassert( modmap= XGetModifierMapping(disp) );
+ keydebugf("KEYMAP got modifier map\n");
+
+ /* find a shift keycode */
+ mm_shift.isdef= 'x';
+ int modent;
+ for (modent=0; modent<modmap->max_keypermod; modent++) {
+ int kc= modmap->modifiermap[modent];
+ keydebugf("KEYMAP modifier #0 key #%d is %d ", modent, kc);
+ if (!kc) { keydebugf("none\n"); continue; }
+ keydebugf("ok\n");
+ mm_shift.kc= kc;
+ mm_shift.isdef= 'y';
+ break;
+ }
+
+ XFreeModifiermap(modmap);
+
+ /* find keycodes for mode_switch (column+=2) and ISO L3 shift (column+=4) */
+ keymap_lookup_modifier(&mm_modeswitch,"modeswitch", XK_Mode_switch, 'm');
+ keymap_lookup_modifier(&mm_isol3shift,"isol3shift", XK_ISO_Level3_Shift,'l');
+
+#define KEY_MAP_LOOKUP(xk) \
+ keymap_lookup_key(&mk_##xk, xk, #xk);
+ KEYS(KEY_MAP_LOOKUP)
+
+ XFree(mapping);
+ mapping= 0;