added an extra key column (alt now on keyboard by default), added cyrillic keym… | |
git clone git://git.suckless.org/svkbd | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 99935775afce355bd16964b9a1b96ec35247292a | |
parent 48994f125e2fdaee15f0724e4f97c24443f9eb96 | |
Author: Maarten van Gompel <[email protected]> | |
Date: Sun, 2 Aug 2020 15:46:15 +0200 | |
added an extra key column (alt now on keyboard by default), added cyrillic keym… | |
Diffstat: | |
M README | 31 +++++++++++++++++++++++------… | |
M layout.sxmo.h | 168 +++++++++++++++++++++++++----… | |
M svkbd.c | 164 ++++++++++++++++++++---------… | |
3 files changed, 267 insertions(+), 96 deletions(-) | |
--- | |
diff --git a/README b/README | |
@@ -1,5 +1,6 @@ | |
SVKBD | |
===== | |
+ | |
This is a simple virtual keyboard, intended to be used in environments, | |
where no keyboard is available. | |
@@ -9,8 +10,11 @@ Installation | |
$ make | |
$ make install | |
-This will create by default `svkbd-en`, which is svkbd using an English | |
-keyboard layout. You can create svkbd for additional layouts by doing: | |
+This will create by default `svkbd-sxmo`, which is svkbd using an versatile | |
+layout with multiple layers and overlays, and optimised for mobile devices. | |
+It was designed for [Simple X Mobile](https://sr.ht/~mil/Sxmo). | |
+ | |
+You can create svkbd for additional layouts by doing: | |
$ make LAYOUT=$layout | |
@@ -20,25 +24,36 @@ This will take the file `layout.$layout.h` and create `svkb… | |
Usage | |
----- | |
- $ svkbd-en | |
+ % svkbd-sxmo | |
This will open svkbd at the bottom of the screen, showing the default | |
English layout. | |
- $ svkbd-en -d | |
+ % svkbd-sxmo -d | |
-This tells svkbd-en to announce itself being a dock window, which then | |
+This tells svkbd-sxmo to announce itself being a dock window, which then | |
is managed differently between different window managers. If using dwm | |
and the dock patch, then this will make svkbd being managed by dwm and | |
some space of the screen being reserved for it. | |
- $ svkbd-en -g 400x200+1+1 | |
+ % svkbd-sxmo -g 400x200+1+1 | |
This will start svkbd-en with a size of 400x200 and at the upper left | |
window corner. | |
+You can enable layers on the fly through either the ``-l`` flag or through the… | |
+They both take a comma separated list of layer names (as defined in your ``lay… | |
+bottom-left to cycle through all the layers. | |
+ | |
+The virtual keyboard comes with overlays that will show when certain keys are … | |
+example, a long press on the ``a`` key will enable an overview showing all kin… | |
+ | |
+Overlay functionality interferes with the ability to hold a key and have it ou… | |
+overlay functionality with the ``-O`` flag or by setting the environment varia… | |
+also a key on the function layer of the keyboard itself to enable/disable this… | |
+``≅`` when the overlay functionality is enabled and ``≇`` when not. | |
+ | |
Repository | |
---------- | |
- git clone https://git.suckless.org/svkbd | |
- | |
+ git clone http://git.suckless.org/svkbd | |
diff --git a/layout.sxmo.h b/layout.sxmo.h | |
@@ -1,7 +1,8 @@ | |
-#define KEYS 40 | |
+#define KEYS 43 | |
static Key keys[KEYS] = { NULL }; | |
static Key keys_en[KEYS] = { | |
+ { "Esc", XK_Escape, 1 }, | |
{ 0, XK_q, 1 }, | |
{ 0, XK_w, 1 }, | |
{ 0, XK_e, 1 }, | |
@@ -15,6 +16,7 @@ static Key keys_en[KEYS] = { | |
{ 0 }, /* New row */ | |
+ { "'\"", XK_apostrophe, 1 }, | |
{ 0, XK_a, 1 }, | |
{ 0, XK_s, 1 }, | |
{ 0, XK_d, 1 }, | |
@@ -25,10 +27,10 @@ static Key keys_en[KEYS] = { | |
{ 0, XK_k, 1 }, | |
{ 0, XK_l, 1 }, | |
{ "/?", XK_slash, 1 }, | |
- /*{ "'", XK_apostrophe, 2 },*/ | |
{ 0 }, /* New row */ | |
+ { "123", XK_Mode_switch, 1 }, | |
{ 0, XK_z, 1 }, | |
{ 0, XK_x, 1 }, | |
{ 0, XK_c, 1 }, | |
@@ -36,25 +38,21 @@ static Key keys_en[KEYS] = { | |
{ 0, XK_b, 1 }, | |
{ 0, XK_n, 1 }, | |
{ 0, XK_m, 1 }, | |
- /*{ "/?", XK_slash, 1 },*/ | |
{ "Tab", XK_Tab, 1 }, | |
{ "⌫Bksp", XK_BackSpace, 2 }, | |
{ 0 }, /* New row */ | |
{ "↺", XK_Cancel, 1}, | |
- { "Shft", XK_Shift_L, 1 }, | |
- /*{ "L", XK_Left, 1 },*/ | |
+ { "Shift", XK_Shift_L, 2 }, | |
+ { "Ctrl", XK_Control_L, 1 }, | |
+ { "Alt", XK_Alt_L, 1 }, | |
+ { "", XK_space, 2 }, | |
{ "↓", XK_Down, 1 }, | |
{ "↑", XK_Up, 1 }, | |
- /*{ "R", XK_Right, 1 },*/ | |
- { "", XK_space, 2 }, | |
- { "Esc", XK_Escape, 1 }, | |
- { "Ctrl", XK_Control_L, 1 }, | |
- /*{ "Alt", XK_Alt_L, 1 },*/ | |
{ "↲ Enter", XK_Return, 2 }, | |
}; | |
-#define OVERLAYS 165 | |
+#define OVERLAYS 197 | |
static Key overlay[OVERLAYS] = { | |
{ 0, XK_a }, //Overlay for a | |
//--- | |
@@ -196,6 +194,58 @@ static Key overlay[OVERLAYS] = { | |
//--- | |
{ "ř", XK_rcaron }, | |
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_softsign }, //New overlay | |
+ //--- | |
+ { "ъ", XK_Cyrillic_hardsign }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_ie }, //New overlay | |
+ //--- | |
+ { "ё", XK_Cyrillic_io }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_e }, //New overlay | |
+ //--- | |
+ { "Є", XK_Ukrainian_ie }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_i }, //New overlay | |
+ //--- | |
+ { "і", XK_Ukrainian_i }, | |
+ { "ї", XK_Ukrainian_yi }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_u }, //New overlay | |
+ //--- | |
+ { "ў", XK_Byelorussian_shortu }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_shorti }, //New overlay | |
+ //--- | |
+ { "ј", XK_Cyrillic_je }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_el }, //New overlay | |
+ //--- | |
+ { "љ", XK_Cyrillic_lje }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_en }, //New overlay | |
+ //--- | |
+ { "њ", XK_Cyrillic_nje }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_tse }, //New overlay | |
+ //--- | |
+ { "џ", XK_Cyrillic_dzhe }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
+ //--- | |
+ { 0, XK_Cyrillic_che }, //New overlay | |
+ //--- | |
+ { "ћ", XK_Serbian_tshe }, | |
+ { "ђ", XK_Serbian_dje }, | |
+ { 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */ | |
//--- | |
{ "🙂", 0x101f642 }, //emoji overlay | |
//--- | |
@@ -262,6 +312,7 @@ static Key overlay[OVERLAYS] = { | |
static Key keys_symbols[KEYS] = { | |
+ { "Esc", XK_Escape, 1 }, | |
{ "1!", XK_1, 1 }, | |
{ "2@", XK_2, 1 }, | |
{ "3#", XK_3, 1 }, | |
@@ -285,31 +336,34 @@ static Key keys_symbols[KEYS] = { | |
{ ".>", XK_period, 1 }, | |
{ "/?", XK_slash, 1 }, | |
{ "\\|", XK_backslash, 1 }, | |
+ { ";:", XK_colon, 1 }, | |
{ 0 }, /* New row */ | |
+ { "abc", XK_Mode_switch, 1 }, | |
{ "☺", 0x101f642, 1 }, | |
{ "⇤", XK_Home, 1 }, | |
{ "←", XK_Left, 1 }, | |
{ "→", XK_Right, 1 }, | |
{ "⇥", XK_End, 1 }, | |
{ "⇊", XK_Next, 1 }, | |
- { ";:", XK_colon, 1 }, | |
+ { "⇈", XK_Prior, 1 }, | |
{ "Tab", XK_Tab, 1 }, | |
{ "⌫Bksp", XK_BackSpace, 2 }, | |
{ 0 }, /* New row */ | |
{ "↺", XK_Cancel, 1}, | |
- { "Shft", XK_Shift_L, 1 }, | |
+ { "Shift", XK_Shift_L, 2 }, | |
+ { "Ctrl", XK_Control_L, 1 }, | |
+ { "Alt", XK_Alt_L, 1 }, | |
+ { "", XK_space, 2 }, | |
{ "↓", XK_Down, 1 }, | |
{ "↑", XK_Up, 1 }, | |
- { "", XK_space, 2 }, | |
- { "Esc", XK_Escape, 1 }, | |
- { "Ctrl", XK_Control_L, 1 }, | |
{ "↲ Enter", XK_Return, 2 }, | |
}; | |
static Key keys_functions[KEYS] = { | |
+ { "Esc", XK_Escape, 1 }, | |
{ "F1", XK_F1, 1 }, | |
{ "F2", XK_F2, 1 }, | |
{ "F3", XK_F3, 1 }, | |
@@ -323,6 +377,7 @@ static Key keys_functions[KEYS] = { | |
{ 0 }, /* New row */ | |
+ { "≅", XK_KP_Insert, 1 }, | |
{ "▶", XF86XK_AudioPlay, 1 }, | |
{ "●", XF86XK_AudioRecord, 1 }, | |
{ "■", XF86XK_AudioStop, 1 }, | |
@@ -336,6 +391,7 @@ static Key keys_functions[KEYS] = { | |
{ 0 }, /* New row */ | |
+ { "abc", XK_Mode_switch, 1 }, | |
{ "Del", XK_Delete, 1 }, | |
{ "⇤", XK_Home, 1 }, | |
{ "←", XK_Left, 1 }, | |
@@ -348,30 +404,80 @@ static Key keys_functions[KEYS] = { | |
{ 0 }, /* New row */ | |
{ "↺", XK_Cancel, 1}, | |
- { "Shft", XK_Shift_L, 1 }, | |
+ { "Shift", XK_Shift_L, 2 }, | |
+ { "Ctrl", XK_Control_L, 1 }, | |
+ { "Alt", XK_Alt_L, 1 }, | |
+ { "", XK_space, 2 }, | |
{ "↓", XK_Down, 1 }, | |
{ "↑", XK_Up, 1 }, | |
- { "", XK_space, 2 }, | |
- { "Esc", XK_Escape, 1 }, | |
- { "Ctrl", XK_Control_L, 1 }, | |
{ "↲ Enter", XK_Return, 2 }, | |
}; | |
-#define LAYERS 3 | |
-static Key* layers[LAYERS] = { | |
- keys_en, | |
- keys_symbols, | |
- keys_functions, | |
+static Key keys_ru[KEYS] = { | |
+ { "и", XK_Cyrillic_shorti, 1 }, | |
+ { "ц", XK_Cyrillic_tse, 1 }, | |
+ { "у", XK_Cyrillic_u, 1 }, | |
+ { "к", XK_Cyrillic_ka, 1 }, | |
+ { "е", XK_Cyrillic_ie, 1 }, | |
+ { "н", XK_Cyrillic_en, 1 }, | |
+ { "г", XK_Cyrillic_ghe, 1 }, | |
+ { "ш", XK_Cyrillic_sha, 1 }, | |
+ { "щ", XK_Cyrillic_shcha, 1 }, | |
+ { "з", XK_Cyrillic_ze, 1 }, | |
+ { "х", XK_Cyrillic_ha, 1 }, | |
+ | |
+ { 0 }, /* New row */ | |
+ | |
+ { "ф", XK_Cyrillic_ef, 1 }, | |
+ { "ы", XK_Cyrillic_yeru, 1 }, | |
+ { "в", XK_Cyrillic_ve, 1 }, | |
+ { "а", XK_Cyrillic_a, 1 }, | |
+ { "п", XK_Cyrillic_pe, 1 }, | |
+ { "о", XK_Cyrillic_o, 1 }, | |
+ { "л", XK_Cyrillic_el, 1 }, | |
+ { "д", XK_Cyrillic_de, 1 }, | |
+ { "ж", XK_Cyrillic_zhe, 1 }, | |
+ { "э", XK_Cyrillic_e, 1 }, | |
+ { "ю", XK_Cyrillic_yu, 1 }, | |
+ | |
+ { 0 }, /* New row */ | |
+ | |
+ { "123", XK_Mode_switch, 1 }, | |
+ { "я", XK_Cyrillic_ya, 1 }, | |
+ { "ч", XK_Cyrillic_che, 1 }, | |
+ { "с", XK_Cyrillic_es, 1 }, | |
+ { "м", XK_Cyrillic_em, 1 }, | |
+ { "и", XK_Cyrillic_i, 1 }, | |
+ { "т", XK_Cyrillic_te, 1 }, | |
+ { "ь", XK_Cyrillic_softsign, 1 }, | |
+ { "б", XK_Cyrillic_be, 1 }, | |
+ { "⌫Bksp", XK_BackSpace, 2 }, | |
+ | |
+ { 0 }, /* New row */ | |
+ { "↺", XK_Cancel, 1}, | |
+ { "Shift", XK_Shift_L, 2 }, | |
+ { "Ctrl", XK_Control_L, 1 }, | |
+ { "Alt", XK_Alt_L, 1 }, | |
+ { "", XK_space, 2 }, | |
+ { "↓", XK_Down, 1 }, | |
+ { "↑", XK_Up, 1 }, | |
+ { "↲ Enter", XK_Return, 2 }, | |
}; | |
+#define LAYERS 4 | |
+static char* layer_names[LAYERS] = { | |
+ "en", | |
+ "symbols", | |
+ "functions", | |
+ "ru", | |
+}; | |
-#define CYCLEMODKEY (KEYS - 3) //third last key (Escape) | |
-#define CYCLEMODS 3 | |
-static Key cyclemods[CYCLEMODS] = { | |
- { "Esc", XK_Escape, 1 }, | |
- { "Alt", XK_Alt_L, 1 }, | |
- { "AGr", XK_ISO_Level3_Shift, 1 }, | |
+static Key* available_layers[LAYERS] = { | |
+ keys_en, | |
+ keys_symbols, | |
+ keys_functions, | |
+ keys_ru | |
}; | |
diff --git a/svkbd.c b/svkbd.c | |
@@ -67,7 +67,6 @@ static void drawkeyboard(void); | |
static void drawkey(Key *k); | |
static void expose(XEvent *e); | |
static Key *findkey(int x, int y); | |
-static int iscyclemod(KeySym keysym); | |
static void leavenotify(XEvent *e); | |
static void press(Key *k, KeySym mod); | |
static double get_press_duration(); | |
@@ -76,9 +75,9 @@ static void setup(void); | |
static void simulate_keypress(KeySym keysym); | |
static void simulate_keyrelease(KeySym keysym); | |
static void showoverlay(int idx); | |
-static void cyclemod(); | |
static void hideoverlay(); | |
static void cyclelayer(); | |
+static void togglelayer(); | |
static void unpress(Key *k, KeySym mod); | |
static void updatekeys(); | |
@@ -101,14 +100,15 @@ static Bool running = True, isdock = False; | |
static KeySym pressedmod = 0; | |
static struct timeval pressbegin; | |
static int currentlayer = 0; | |
+static int enableoverlays = 1; | |
static int currentoverlay = -1; // -1 = no overlay | |
-static int currentcyclemod = 0; | |
static KeySym overlaykeysym = 0; //keysym for which the overlay is presented | |
static int releaseprotect = 0; //set to 1 after overlay is shown, protecting a… | |
static int tmp_keycode = 1; | |
static int rows = 0, ww = 0, wh = 0, wx = 0, wy = 0; | |
static char *name = "svkbd"; | |
static int debug = 0; | |
+static int numlayers = 0; | |
static KeySym ispressingkeysym; | |
@@ -122,6 +122,8 @@ Bool sigtermd = False; | |
#endif | |
#include LAYOUT | |
+static Key* layers[LAYERS]; | |
+ | |
void | |
motionnotify(XEvent *e) | |
{ | |
@@ -210,6 +212,15 @@ cleanup(void) { | |
// process will be dead before finger lifts - in that case we | |
// just trigger out fake up presses for all keys | |
if (sigtermd) { | |
+ //handle last pending events | |
+ XEvent ev; | |
+ while (XPending(dpy)) { | |
+ XNextEvent(dpy, &ev); | |
+ if(handler[ev.type]) { | |
+ (handler[ev.type])(&ev); /* call handler */ | |
+ } | |
+ } | |
+ if (debug) { printf("Cleanup: simulating key release\n"); fflu… | |
for (i = 0; i < LENGTH(keys); i++) { | |
XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].k… | |
} | |
@@ -218,6 +229,7 @@ cleanup(void) { | |
for (i = 0; i < SchemeLast; i++) | |
free(scheme[i]); | |
drw_sync(drw); | |
+ drw_free(drw); | |
XSync(dpy, False); | |
drw_free(drw); | |
XDestroyWindow(dpy, win); | |
@@ -272,7 +284,13 @@ drawkey(Key *k) { | |
drw_rect(drw, k->x, k->y, k->w, k->h, 1, 1); | |
drw_rect(drw, k->x, k->y, k->w, k->h, 0, 0); | |
- if(k->label) { | |
+ if (k->keysym == XK_KP_Insert) { | |
+ if (enableoverlays) { | |
+ l = "≅"; | |
+ } else { | |
+ l = "≇"; | |
+ } | |
+ } else if(k->label) { | |
l = k->label; | |
} else { | |
l = XKeysymToString(k->keysym); | |
@@ -322,17 +340,6 @@ hasoverlay(KeySym keysym) { | |
return -1; | |
} | |
-int | |
-iscyclemod(KeySym keysym) { | |
- int i; | |
- for(i = 0; i < CYCLEMODS; i++) { | |
- if(cyclemods[i].keysym == keysym) { | |
- return i; | |
- } | |
- } | |
- return -1; | |
-} | |
- | |
void | |
leavenotify(XEvent *e) { | |
if (currentoverlay != -1) { | |
@@ -358,16 +365,10 @@ press(Key *k, KeySym mod) { | |
pressbegin.tv_usec = 0; | |
ispressingkeysym = 0; | |
- int cm = iscyclemod(k->keysym); | |
- if (cm != -1) { | |
- if (!pressbegin.tv_sec && !pressbegin.tv_usec) { | |
- //record the begin of the press, don't simulate the ac… | |
- record_press_begin(k->keysym); | |
- } | |
- } else if(!IsModifierKey(k->keysym)) { | |
- if (currentoverlay == -1) | |
+ if(!IsModifierKey(k->keysym)) { | |
+ if (enableoverlays && currentoverlay == -1) | |
overlayidx = hasoverlay(k->keysym); | |
- if (overlayidx != -1) { | |
+ if (enableoverlays && overlayidx != -1) { | |
if (!pressbegin.tv_sec && !pressbegin.tv_usec) { | |
//record the begin of the press, don't simulat… | |
record_press_begin(k->keysym); | |
@@ -437,6 +438,12 @@ unpress(Key *k, KeySym mod) { | |
case XK_Cancel: | |
cyclelayer(); | |
break; | |
+ case XK_script_switch: | |
+ togglelayer(); | |
+ break; | |
+ case XK_KP_Insert: | |
+ enableoverlays = !enableoverlays; | |
+ break; | |
case XK_Break: | |
running = False; | |
default: | |
@@ -445,7 +452,7 @@ unpress(Key *k, KeySym mod) { | |
} | |
- if ((pressbegin.tv_sec || pressbegin.tv_usec) && k && k->keysym == isp… | |
+ if ((pressbegin.tv_sec || pressbegin.tv_usec) && enableoverlays && k &… | |
if (currentoverlay == -1) { | |
if (get_press_duration() < overlay_delay) { | |
if (debug) { printf("Delayed simulation of pre… | |
@@ -472,7 +479,7 @@ unpress(Key *k, KeySym mod) { | |
if (k) { | |
printf("Simulation of release: %ld\n", k->keysym); ffl… | |
} else { | |
- printf("Simulation of release (all keys)"); fflush(std… | |
+ printf("Simulation of release (all keys)\n"); fflush(s… | |
} | |
} | |
@@ -500,7 +507,7 @@ unpress(Key *k, KeySym mod) { | |
} | |
} | |
- if (currentoverlay != -1) { | |
+ if (enableoverlays && currentoverlay != -1) { | |
if (releaseprotect) { | |
releaseprotect = 0; | |
} else { | |
@@ -516,7 +523,6 @@ run(void) { | |
fd_set fds; | |
struct timeval tv; | |
double duration = 0.0; | |
- int cyclemodidx; | |
xfd = ConnectionNumber(dpy); | |
@@ -528,6 +534,7 @@ run(void) { | |
XFlush(dpy); | |
while (running) { | |
+ usleep(100000L); | |
FD_ZERO(&fds); | |
FD_SET(xfd, &fds); | |
if (select(xfd + 1, &fds, NULL, NULL, &tv)) { | |
@@ -543,19 +550,13 @@ run(void) { | |
if (debug == 2) { printf("%f\n", duration); ff… | |
if (get_press_duration() >= overlay_delay) { | |
if (debug) { printf("press duration %f… | |
- cyclemodidx = iscyclemod(ispressingkey… | |
- if (cyclemodidx != -1) { | |
- cyclemod(); | |
- } else { | |
- showoverlay(hasoverlay(ispress… | |
- } | |
+ showoverlay(hasoverlay(ispressingkeysy… | |
pressbegin.tv_sec = 0; | |
pressbegin.tv_usec = 0; | |
ispressingkeysym = 0; | |
} | |
} | |
} | |
- usleep(100000L); | |
} | |
} | |
@@ -719,14 +720,20 @@ updatekeys() { | |
void | |
usage(char *argv0) { | |
- fprintf(stderr, "usage: %s [-hdvD] [-g geometry] [-fn font]\n", argv0); | |
+ fprintf(stderr, "usage: %s [-hdvDOl] [-g geometry] [-fn font]\n", argv… | |
+ fprintf(stderr, "Options:\n"); | |
+ fprintf(stderr, " -d - Set Dock Window Type\n"); | |
+ fprintf(stderr, " -D - Enable debug\n"); | |
+ fprintf(stderr, " -O - Disable overlays\n"); | |
+ fprintf(stderr, " -l - Comma separated list of layers to enab… | |
+ fprintf(stderr, " -fn [font] - Set font (Xft, e.g: DejaVu Sans:bold:s… | |
exit(1); | |
} | |
void | |
cyclelayer() { | |
currentlayer++; | |
- if (currentlayer >= LAYERS) | |
+ if (currentlayer >= numlayers) | |
currentlayer = 0; | |
if (debug) { printf("Cycling to layer %d\n", currentlayer); fflush(std… | |
memcpy(&keys, layers[currentlayer], sizeof(keys_en)); | |
@@ -735,29 +742,19 @@ cyclelayer() { | |
} | |
void | |
-cyclemod() { | |
- int i; | |
- //unpress all pressed keys | |
- for(i = 0; i < LENGTH(keys); i++) { | |
- if(keys[i].pressed) { | |
- keys[i].pressed = 0; | |
- drawkey(&keys[i]); | |
- } | |
+togglelayer() { | |
+ if (currentlayer > 0) { | |
+ currentlayer = 0; | |
+ } else if (numlayers > 1) { | |
+ currentlayer = 1; | |
} | |
- pressedmod = 0; | |
- pressbegin.tv_sec = 0; | |
- pressbegin.tv_usec = 0; | |
- ispressingkeysym = 0; | |
- currentcyclemod++; | |
- if (currentcyclemod >= CYCLEMODS) | |
- currentcyclemod = 0; | |
- if (debug) { printf("Cycling modifier to %d\n", currentcyclemod); fflu… | |
- keys[CYCLEMODKEY].label = cyclemods[currentcyclemod].label; | |
- keys[CYCLEMODKEY].keysym = cyclemods[currentcyclemod].keysym; | |
- drawkey(&keys[CYCLEMODKEY]); | |
- XSync(dpy, False); | |
+ if (debug) { printf("Toggling layer %d\n", currentlayer); fflush(stdou… | |
+ memcpy(&keys, layers[currentlayer], sizeof(keys_en)); | |
+ updatekeys(); | |
+ drawkeyboard(); | |
} | |
+ | |
void | |
showoverlay(int idx) { | |
if (debug) { printf("Showing overlay %d\n", idx); fflush(stdout); } | |
@@ -802,15 +799,58 @@ sigterm(int sig) | |
{ | |
running = False; | |
sigtermd = True; | |
+ if (debug) { printf("Sigterm received\n"); fflush(stdout); } | |
+} | |
+ | |
+ | |
+void | |
+init_layers(char * layer_names_list) { | |
+ if (layer_names_list == NULL) { | |
+ numlayers = LAYERS; | |
+ memcpy(&layers, &available_layers, sizeof(available_layers)); | |
+ } else { | |
+ char * s; | |
+ int j; | |
+ s = strtok(layer_names_list, ","); | |
+ while (s != NULL) { | |
+ if (numlayers+1 > LAYERS) die("too many layers specifi… | |
+ int found = 0; | |
+ for (j = 0; j < LAYERS; j++) { | |
+ if (strcmp(layer_names[j], s) == 0) { | |
+ layers[numlayers] = available_layers[j… | |
+ printf("Adding layer %s\n", s); | |
+ found = 1; | |
+ break; | |
+ } | |
+ } | |
+ if (!found) { | |
+ fprintf(stderr, "Undefined layer: %s\n", s); | |
+ exit(3); | |
+ } | |
+ numlayers++; | |
+ s = strtok(NULL,","); | |
+ } | |
+ } | |
} | |
int | |
main(int argc, char *argv[]) { | |
int i, xr, yr, bitm; | |
unsigned int wr, hr; | |
+ char * layer_names_list = NULL; | |
memcpy(&keys, &keys_en, sizeof(keys_en)); | |
signal(SIGTERM, sigterm); | |
+ | |
+ const char* enableoverlays_env = getenv("SVKBD_ENABLEOVERLAYS"); | |
+ if (enableoverlays_env != NULL) enableoverlays = atoi(enableoverlays_e… | |
+ const char* layers_env = getenv("SVKBD_LAYERS"); | |
+ if (layers_env != NULL) { | |
+ layer_names_list = malloc(128); | |
+ strcpy(layer_names_list, layers_env); | |
+ } | |
+ | |
+ | |
for (i = 1; argv[i]; i++) { | |
if(!strcmp(argv[i], "-v")) { | |
die("svkbd-"VERSION", © 2006-2020 svkbd engineers," | |
@@ -842,9 +882,18 @@ main(int argc, char *argv[]) { | |
debug = 1; | |
} else if(!strcmp(argv[i], "-h")) { | |
usage(argv[0]); | |
+ } else if(!strcmp(argv[i], "-O")) { | |
+ enableoverlays = 0; | |
+ } else if(!strcmp(argv[i], "-l")) { | |
+ if(i >= argc - 1) | |
+ continue; | |
+ if (layer_names_list == NULL) layer_names_list = mallo… | |
+ strcpy(layer_names_list, argv[i+1]); | |
} | |
} | |
+ init_layers(layer_names_list); | |
+ | |
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) | |
fprintf(stderr, "warning: no locale support\n"); | |
if(!(dpy = XOpenDisplay(0))) | |
@@ -853,5 +902,6 @@ main(int argc, char *argv[]) { | |
run(); | |
cleanup(); | |
XCloseDisplay(dpy); | |
+ if (layer_names_list != NULL) free(layer_names_list); | |
return 0; | |
} |