svkbd

Simple X11 onscreen keyboard.
git clone git://r-36.net/svkbd
Log | Files | Refs | LICENSE

commit 81e162dc4b3446afd6811a4f73478301ba234781
parent 1aa6bd5ebe5e58142af641c34dcb2f02420c5dbc
Author: Enno Boland (Gottox) <gottox@s01.de>
Date:   Wed, 16 Jul 2008 08:59:28 +0200

rearranging source, adding mousebuttonmodifier.
Diffstat:
config.def.h | 16++++++++++------
config.h | 8++++++--
svkbd.c | 154+++++++++++++++++++++++++++++++++++++------------------------------------------
3 files changed, 89 insertions(+), 89 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -20,7 +20,7 @@ static Key keys[] = { { "-_", XK_minus, 1 }, { "=+", XK_plus, 1 }, { "<-", XK_BackSpace, 2 }, - { 0 }, + { 0 }, /* New row */ { "->|", XK_Tab, 1 }, { 0, XK_q, 1 }, { 0, XK_w, 1 }, @@ -35,7 +35,7 @@ static Key keys[] = { { "[", XK_bracketleft, 1 }, { "]", XK_bracketright, 1 }, { "Return", XK_Return, 3 }, - { 0 }, + { 0 }, /* New row */ { 0, XK_Caps_Lock, 2 }, { 0, XK_a, 1 }, { 0, XK_s, 1 }, @@ -49,9 +49,8 @@ static Key keys[] = { { ":;", XK_semicolon, 1 }, { "'\"", XK_exclam, 1 }, { "\\|", XK_backslash, 1 }, - { 0 }, - { 0, XK_Shift_L, 2 }, - { "<>|", XK_greater, 1 }, + { 0 }, /* New row */ + { 0, XK_Shift_L, 3 }, { 0, XK_z, 1 }, { 0, XK_x, 1 }, { 0, XK_c, 1 }, @@ -63,10 +62,15 @@ static Key keys[] = { { ".", XK_period, 1 }, { "/?", XK_slash, 1 }, { 0, XK_Shift_R, 2 }, - { 0 }, + { 0 }, /* New row */ { "Ctrl", XK_Control_L, 2 }, { "Alt", XK_Alt_L, 2 }, { "", XK_space, 5 }, { "Alt", XK_Alt_R, 2 }, { "Ctrl", XK_Control_R, 2 }, }; + +Buttonmod buttonmods[] = { + { XK_Shift_L, Button2 }, + { XK_Alt_L, Button3 }, +}; diff --git a/config.h b/config.h @@ -50,8 +50,7 @@ static Key keys[] = { { "'\"", XK_exclam, 1 }, { "\\|", XK_backslash, 1 }, { 0 }, - { 0, XK_Shift_L, 2 }, - { "<>|", XK_greater, 1 }, + { 0, XK_Shift_L, 3 }, { 0, XK_z, 1 }, { 0, XK_x, 1 }, { 0, XK_c, 1 }, @@ -70,3 +69,8 @@ static Key keys[] = { { "Alt", XK_Alt_R, 2 }, { "Ctrl", XK_Control_R, 2 }, }; + +Buttonmod buttonmods[] = { + { XK_Shift_L, Button2 }, + { XK_Alt_L, Button3 }, +}; diff --git a/svkbd.c b/svkbd.c @@ -1,29 +1,7 @@ /* See LICENSE file for copyright and license details. * - * dynamic window manager is designed like any other X client as well. It is - * driven through handling X events. In contrast to other X clients, a window - * manager selects for SubstructureRedirectMask on the root window, to receive - * events about window (dis-)appearance. Only one X connection at a time is - * allowed to select for this event mask. - * - * Calls to fetch an X event from the event queue are blocking. Due reading - * status text from standard input, a select()-driven main loop has been - * implemented which selects for reads on the X connection and STDIN_FILENO to - * handle all data smoothly. The event handlers of dwm are organized in an - * array which is accessed whenever a new event has been fetched. This allows - * event dispatching in O(1) time. - * - * Each child of the root window is called a client, except windows which have - * set the override_redirect flag. Clients are organized in a global - * doubly-linked client list, the focus history is remembered through a global - * stack list. Each client contains a bit array to indicate the tags of a - * client. - * - * Keys and tagging rules are organized as arrays and defined in config.h. - * - * To understand everything else, start reading main(). + * To understand svkbd, start reading main(). */ -#include <errno.h> #include <locale.h> #include <stdarg.h> #include <stdio.h> @@ -32,20 +10,13 @@ #include <X11/keysym.h> #include <X11/Xatom.h> #include <X11/Xlib.h> -#include <X11/Xproto.h> #include <X11/Xutil.h> +#include <X11/Xproto.h> #include <X11/extensions/XTest.h> /* macros */ #define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) -#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) #define LENGTH(x) (sizeof x / sizeof x[0]) -#define MAXMOD 16 -#define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define TAGMASK ((int)((1LL << LENGTH(tags)) - 1)) -#define TEXTW(x) (textnw(x, strlen(x)) + dc.font.height) /* enums */ enum { ColFG, ColBG, ColLast }; @@ -77,12 +48,17 @@ typedef struct { Bool pressed; } Key; +typedef struct { + KeySym mod; + uint button; +} Buttonmod; + /* function declarations */ static void buttonpress(XEvent *e); static void buttonrelease(XEvent *e); static void cleanup(void); static void configurenotify(XEvent *e); -static void destroynotify(XEvent *e); +static void unmapnotify(XEvent *e); static void die(const char *errstr, ...); static void drawkeyboard(void); static void drawkey(Key *k); @@ -92,9 +68,11 @@ static ulong getcolor(const char *colstr); static void initfont(const char *fontstr); static void leavenotify(XEvent *e); static void motionnotify(XEvent *e); +static void press(Key *k, KeySym mod); static void run(void); static void setup(void); static int textnw(const char *text, uint len); +static void unpress(); static void updatekeys(); /* variables */ @@ -104,7 +82,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { [ButtonPress] = buttonpress, [ButtonRelease] = buttonrelease, [ConfigureNotify] = configurenotify, - [DestroyNotify] = destroynotify, + [UnmapNotify] = unmapnotify, [Expose] = expose, [LeaveNotify] = leavenotify, [MotionNotify] = motionnotify, @@ -113,57 +91,34 @@ static Display *dpy; static DC dc; static Window root, win; static Bool running = True; -static Key *hover = NULL, *pressed = NULL; +static Key *hover = NULL; +static KeySym pressedmod = 0; /* configuration, allows nested code to access above variables */ #include "config.h" void buttonpress(XEvent *e) { + int i; XButtonPressedEvent *ev = &e->xbutton; Key *k; + KeySym mod = 0; - if((k = findkey(ev->x, ev->y))) { - if(k->pressed && IsModifierKey(k->keysym)) { - XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, k->keysym), False, 0); - k->pressed = 0; - pressed = NULL; + for(i = 0; i < LENGTH(buttonmods); i++) + if(ev->button == buttonmods[i].button) { + mod = buttonmods[i].mod; + break; } - else { - pressed = k; - k->pressed = True; - XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, k->keysym), True, 0); - } - drawkey(k); - XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, wh, 0, 0); - } + if((k = findkey(ev->x, ev->y))) + press(k, mod); } void buttonrelease(XEvent *e) { - int i; XButtonPressedEvent *ev = &e->xbutton; - Key *k = findkey(ev->x, ev->y); + Key *k; - if(pressed && k && !IsModifierKey(k->keysym)) { - if(k != pressed) { - XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, k->keysym), True, 0); - k->pressed = 1; - } - for(i = 0; i < LENGTH(keys); i++) { - if(keys[i].pressed && !IsModifierKey(keys[i].keysym)) { - XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), False, 0); - keys[i].pressed = 0; - } - } - for(i = 0; i < LENGTH(keys); i++) { - if(keys[i].pressed) { - XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), False, 0); - keys[i].pressed = 0; - } - } - pressed = NULL; - } - drawkeyboard(); + if((k = findkey(ev->x, ev->y))) + unpress(k); } void @@ -229,8 +184,9 @@ drawkey(Key *k) { col = dc.norm; XSetForeground(dpy, dc.gc, col[ColBG]); XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); - XSetForeground(dpy, dc.gc, col[ColFG]); + XSetForeground(dpy, dc.gc, dc.norm[ColFG]); XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1); + XSetForeground(dpy, dc.gc, col[ColFG]); if(k->label) l = k->label; else @@ -246,7 +202,7 @@ drawkey(Key *k) { } void -destroynotify(XEvent *e) { +unmapnotify(XEvent *e) { running = False; } @@ -291,7 +247,7 @@ initfont(const char *fontstr) { dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); if(missing) { while(n--) - fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); + fprintf(stderr, "svkbd: missing fontset: %s\n", missing[n]); XFreeStringList(missing); } if(dc.font.set) { @@ -322,13 +278,11 @@ initfont(const char *fontstr) { void leavenotify(XEvent *e) { - Key *h = hover; - + unpress(NULL); if(!hover) return; hover = NULL; - drawkey(h); - XCopyArea(dpy, dc.drawable, win, dc.gc, h->x, h->y, h->w, h->h, h->x, h->y); + drawkeyboard(); } void @@ -348,6 +302,24 @@ motionnotify(XEvent *e) { } void +press(Key *k, KeySym mod) { + int i; + k->pressed = !k->pressed; + + if(!IsModifierKey(k->keysym)) { + for(i = 0; i < LENGTH(keys); i++) + if(keys[i].pressed && IsModifierKey(keys[i].keysym)) + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), True, 0); + pressedmod = mod; + if(pressedmod) + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, mod), True, 0); + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, k->keysym), True, 0); + } + drawkey(k); + XCopyArea(dpy, dc.drawable, win, dc.gc, k->x, k->y, k->w, k->h, k->x, k->y); +} + +void run(void) { XEvent ev; @@ -414,6 +386,30 @@ textnw(const char *text, uint len) { } void +unpress() { + int i; + + for(i = 0; i < LENGTH(keys); i++) + if(keys[i].pressed && !IsModifierKey(keys[i].keysym)) { + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), False, 0); + keys[i].pressed = 0; + break; + } + if(i != LENGTH(keys)) { + for(i = 0; i < LENGTH(keys); i++) { + if(pressedmod) + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, pressedmod), False, 0); + pressedmod = 0; + if(keys[i].pressed) { + XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), False, 0); + keys[i].pressed = 0; + } + } + drawkeyboard(); + } +} + +void updatekeys() { int rows, i, j; int x = 0, y = 0, h, base; @@ -429,7 +425,7 @@ updatekeys() { keys[i].x = x; keys[i].y = y; keys[i].w = keys[i].width * (ww - 1) / base; - if(rows) + if(rows != 1) keys[i].h = h; else keys[i].h = (wh - 1) - y; @@ -447,17 +443,13 @@ main(int argc, char *argv[]) { die("svkc-"VERSION", © 2006-2008 svkbd engineers, see LICENSE for details\n"); else if(argc != 1) die("usage: svkbd [-v]\n"); - if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); - if(!(dpy = XOpenDisplay(0))) die("svkbd: cannot open display\n"); - setup(); run(); cleanup(); - XCloseDisplay(dpy); return 0; }