wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

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