key.c (4178B)
1 /* Copyright ©2006-2010 Kris Maglione <fbsdaemon at Gmail> 2 * Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com> 3 * See LICENSE file for license details. 4 */ 5 #include "dat.h" 6 #include <X11/keysym.h> 7 #include "fns.h" 8 9 static void 10 freekey(Key *k) { 11 Key *n; 12 13 while((n = k)) { 14 k = k->next; 15 free(n); 16 } 17 } 18 19 static void 20 _grab(XWindow w, int keycode, uint mod) { 21 XGrabKey(display, keycode, mod, w, 22 true, GrabModeAsync, GrabModeAsync); 23 } 24 25 static void 26 grabkey(Key *k) { 27 _grab(scr.root.xid, k->key, k->mod); 28 _grab(scr.root.xid, k->key, k->mod | LockMask); 29 if(numlock_mask) { 30 _grab(scr.root.xid, k->key, k->mod | numlock_mask); 31 _grab(scr.root.xid, k->key, k->mod | numlock_mask | LockMask); 32 } 33 } 34 35 static void 36 ungrabkey(Key *k) { 37 XUngrabKey(display, k->key, k->mod, scr.root.xid); 38 XUngrabKey(display, k->key, k->mod | LockMask, scr.root.xid); 39 if(numlock_mask) { 40 XUngrabKey(display, k->key, k->mod | numlock_mask, scr.root.xid); 41 XUngrabKey(display, k->key, k->mod | numlock_mask | LockMask, scr.root.xid); 42 } 43 } 44 45 static Key* 46 name2key(const char *name) { 47 Key *k; 48 49 for(k=key; k; k=k->lnext) 50 if(!strcmp(k->name, name)) 51 return k; 52 return nil; 53 } 54 55 static Key* 56 getkey(const char *name) { 57 Key *k, *r; 58 char buf[128]; 59 char *seq[8]; 60 char *kstr; 61 int mask; 62 uint i, toks; 63 static ushort id = 1; 64 65 r = nil; 66 67 if((k = name2key(name))) { 68 ungrabkey(k); 69 return k; 70 } 71 utflcpy(buf, name, sizeof buf); 72 toks = tokenize(seq, 8, buf, ','); 73 for(i = 0; i < toks; i++) { 74 if(!k) 75 r = k = emallocz(sizeof *k); 76 else { 77 k->next = emallocz(sizeof *k); 78 k = k->next; 79 } 80 utflcpy(k->name, name, sizeof k->name); 81 if(parsekey(seq[i], &mask, &kstr)) { 82 k->key = keycode(kstr); 83 k->mod = mask; 84 } 85 if(k->key == 0) { 86 freekey(r); 87 return nil; 88 } 89 } 90 if(r) { 91 r->id = id++; 92 r->lnext = key; 93 key = r; 94 } 95 96 return r; 97 } 98 99 static void 100 next_keystroke(ulong *mod, KeyCode *code) { 101 XEvent e; 102 KeySym sym; 103 *mod = 0; 104 105 do { 106 XMaskEvent(display, KeyPressMask, &e); 107 *mod |= e.xkey.state & valid_mask; 108 *code = (KeyCode)e.xkey.keycode; 109 sym = XKeycodeToKeysym(display, e.xkey.keycode, 0); 110 } while(IsModifierKey(sym)); 111 } 112 113 static void 114 fake_keypress(ulong mod, KeyCode key) { 115 XKeyEvent e; 116 Client *c; 117 118 c = disp.focus; 119 if(c == nil || c->w.xid == 0) 120 return; 121 122 e.time = event_xtime; 123 e.window = c->w.xid; 124 e.state = mod; 125 e.keycode = key; 126 127 e.type = KeyPress; 128 sendevent(&c->w, true, KeyPressMask, (XEvent*)&e); 129 e.type = KeyRelease; 130 sendevent(&c->w, true, KeyReleaseMask, (XEvent*)&e); 131 132 sync(); 133 } 134 135 static Key * 136 match_keys(Key *k, ulong mod, KeyCode keycode, bool seq) { 137 Key *ret, *next; 138 int i; /* shut up ken */ 139 140 ret = nil; 141 for(next = k->tnext; k; i = (k=next) && (next=k->tnext)) { 142 if(seq) 143 k = k->next; 144 if(k && (k->mod == mod) && (k->key == keycode)) { 145 k->tnext = ret; 146 ret = k; 147 } 148 } 149 USED(i); 150 return ret; 151 } 152 153 static void 154 kpress_seq(XWindow w, Key *done) { 155 ulong mod; 156 KeyCode key; 157 Key *found; 158 159 next_keystroke(&mod, &key); 160 found = match_keys(done, mod, key, true); 161 if((done->mod == mod) && (done->key == key)) 162 fake_keypress(mod, key); /* double key */ 163 else { 164 if(!found) 165 XBell(display, 0); 166 else if(!found->tnext && !found->next) 167 event("Key %s\n", found->name); 168 else 169 kpress_seq(w, found); 170 } 171 } 172 173 void 174 kpress(XWindow w, ulong mod, KeyCode keycode) { 175 Key *k, *found; 176 177 for(k=key; k; k=k->lnext) 178 k->tnext = k->lnext; 179 180 found = match_keys(key, mod, keycode, false); 181 if(!found) /* grabbed but not found */ 182 XBell(display, 0); 183 else if(!found->tnext && !found->next) 184 event("Key %s\n", found->name); 185 else { 186 XGrabKeyboard(display, w, true, GrabModeAsync, GrabModeAsync, CurrentTime); 187 event_flush(FocusChangeMask, true); 188 kpress_seq(w, found); 189 XUngrabKeyboard(display, CurrentTime); 190 } 191 } 192 193 void 194 update_keys(void) { 195 Key *k; 196 char *l, *p; 197 198 numlock_mask = numlockmask(); 199 valid_mask = 0xff & ~(numlock_mask | LockMask); 200 while((k = key)) { 201 key = key->lnext; 202 ungrabkey(k); 203 freekey(k); 204 } 205 for(l = p = def.keys; p && *p; p++) { 206 if(*p == '\n') { 207 *p = 0; 208 if((k = getkey(l))) 209 grabkey(k); 210 *p = '\n'; 211 l = p + 1; 212 } 213 } 214 if(l < p && strlen(l)) { 215 if((k = getkey(l))) 216 grabkey(k); 217 } 218 } 219