/* * (C)opyright MMIV-MMVI Anselm R. Garbe * See LICENSE file for license details. */ #include #include #include #include #include "wm.h" void init_lock_keys() { XModifierKeymap *modmap; KeyCode num_lock; static int masks[] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; int i; num_lock_mask = 0; modmap = XGetModifierMapping(dpy); num_lock = XKeysymToKeycode(dpy, XStringToKeysym("Num_Lock")); if(modmap && modmap->max_keypermod > 0) { int max = (sizeof(masks) / sizeof(int)) * modmap->max_keypermod; for(i = 0; i < max; i++) if(num_lock && (modmap->modifiermap[i] == num_lock)) num_lock_mask = masks[i / modmap->max_keypermod]; } XFreeModifiermap(modmap); valid_mask = 255 & ~(num_lock_mask | LockMask); } unsigned long mod_key_of_str(char *val) { unsigned long mod = 0; if (strstr(val, "Shift")) mod |= ShiftMask; if (strstr(val, "Control")) mod |= ControlMask; if (strstr(val, "Mod1")) mod |= Mod1Mask; if (strstr(val, "Mod2")) mod |= Mod2Mask; if (strstr(val, "Mod3")) mod |= Mod3Mask; if (strstr(val, "Mod4")) mod |= Mod4Mask; if (strstr(val, "Mod5")) mod |= Mod5Mask; return mod; } static void grab_key(Key *k) { XGrabKey(dpy, k->key, k->mod, root, True, GrabModeAsync, GrabModeAsync); if(num_lock_mask) { XGrabKey(dpy, k->key, k->mod | num_lock_mask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, k->key, k->mod | num_lock_mask | LockMask, root, True, GrabModeAsync, GrabModeAsync); } XSync(dpy, False); } static void ungrab_key(Key *k) { XUngrabKey(dpy, k->key, k->mod, root); if(num_lock_mask) { XUngrabKey(dpy, k->key, k->mod | num_lock_mask, root); XUngrabKey(dpy, k->key, k->mod | num_lock_mask | LockMask, root); } XSync(dpy, False); } static Key * name2key(const char *name) { Key *k; for(k=key; k && strncmp(k->name, name, sizeof(k->name)); k=k->lnext); return k; } static Key * get_key(const char *name) { char buf[128]; char *seq[8]; char *kstr; unsigned int i, toks; static unsigned short id = 1; Key *k = 0, *r = 0; if((k = name2key(name))) { ungrab_key(k); return k; } cext_strlcpy(buf, name, sizeof(buf)); toks = cext_tokenize(seq, 8, buf, ','); for(i = 0; i < toks; i++) { if(!k) r = k = cext_emallocz(sizeof(Key)); else { k->next = cext_emallocz(sizeof(Key)); k = k->next; } cext_strlcpy(k->name, name, sizeof(k->name)); kstr = strrchr(seq[i], '-'); if(kstr) kstr++; else kstr = seq[i]; k->key = XKeysymToKeycode(dpy, XStringToKeysym(kstr)); k->mod = mod_key_of_str(seq[i]); } if(r) { r->id = id++; r->lnext = key; key = r; } return r; } static void next_keystroke(unsigned long *mod, KeyCode *keyCode) { XEvent e; KeySym sym; *mod = 0; do { XMaskEvent(dpy, KeyPressMask, &e); *mod |= e.xkey.state & valid_mask; *keyCode = (KeyCode) e.xkey.keycode; sym = XKeycodeToKeysym(dpy, e.xkey.keycode, 0); } while(IsModifierKey(sym)); } static void emulate_key_press(unsigned long mod, KeyCode key) { XEvent e; Window client_win; int revert; XGetInputFocus(dpy, &client_win, &revert); e.xkey.type = KeyPress; e.xkey.time = CurrentTime; e.xkey.window = client_win; e.xkey.display = dpy; e.xkey.state = mod; e.xkey.keycode = key; XSendEvent(dpy, client_win, True, KeyPressMask, &e); e.xkey.type = KeyRelease; XSendEvent(dpy, client_win, True, KeyReleaseMask, &e); XSync(dpy, False); } static Key * match_keys(Key *k, unsigned long mod, KeyCode keycode, Bool seq) { Key *ret = nil, *next; for(next = k->tnext; k; (k=next) && (next=k->tnext)) { if(seq) k = k->next; if(k && (k->mod == mod) && (k->key == keycode)) { k->tnext = ret; ret = k; } } return ret; } static void handle_key_seq(Window w, Key *done) { unsigned long mod; KeyCode key; Key *found; char buf[128]; next_keystroke(&mod, &key); found = match_keys(done, mod, key, True); if((done->mod == mod) && (done->key == key)) emulate_key_press(mod, key); /* double key */ else { if(!found) { XBell(dpy, 0); } /* grabbed but not found */ else if(!found->tnext && !found->next) { snprintf(buf, sizeof(buf), "Key %s\n", found->name); write_event(buf); } else handle_key_seq(w, found); } } void handle_key(Window w, unsigned long mod, KeyCode keycode) { Key *k; char buf[128]; for(k=key; k; k->tnext=k->lnext, k=k->lnext); Key *found = match_keys(key, mod, keycode, False); if(!found) { XBell(dpy, 0); } /* grabbed but not found */ else if(!found->tnext && !found->next) { snprintf(buf, sizeof(buf), "Key %s\n", found->name); write_event(buf); } else { XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); handle_key_seq(w, found); XUngrabKeyboard(dpy, CurrentTime); XSync(dpy, False); } } void update_keys() { Key *k, *n; char *l, *p; init_lock_keys(); while((k = key)) { key = key->lnext; ungrab_key(k); while((n = k)) { k = k->next; free(n); } } for(l = p = def.keys; p && *p;) { if(*p == '\n') { *p = 0; if((k = get_key(l))) grab_key(k); *p = '\n'; l = ++p; } else p++; } if(l < p && strlen(l)) { if((k = get_key(l))) grab_key(k); } XSync(dpy, False); }