Re: [hackers] [PATCH 4/6] added an extra key column (alt now on keyboard by default), added cyrillic keymap, added a toggle to enable/disable overlays, added quick toggle buttons to toggle primary two layers. Added some configurability using command line parameters and environment variables.

From: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
Date: Sat, 25 Jul 2020 01:35:20 +0200

On Fri, Jul 24, 2020 at 09:49:58PM +0200, Maarten van Gompel wrote:
> ---
> README | 63 ++++++++++++++++---
> layout.sxmo.h | 168 ++++++++++++++++++++++++++++++++++++++++----------
> svkbd.c | 165 ++++++++++++++++++++++++++++++++-----------------
> 3 files changed, 297 insertions(+), 99 deletions(-)
>
> diff --git a/README b/README
> index f1f2b82..fd0e4d9 100644
> --- a/README
> +++ b/README
> _AT_@ -1,5 +1,6 @@
> -SVKBD
> -=====
> +SVKBD: Simple Virtual Keyboard
> +=================================
> +
> This is a simple virtual keyboard, intended to be used in environments,
> where no keyboard is available.
>
> _AT_@ -9,34 +10,76 @@ 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-intl`, which is svkbd using an international
> +layout with multiple layers and overlays, and optimised for mobile devices.
> +
> +You can create svkbd for additional layouts by doing:
>
> $ make LAYOUT=$layout
>
> This will take the file `layout.$layout.h` and create `svkbd-$layout`.
> `make install` will then pick up the new file and install it accordingly.
>
> +Layouts
> +---------
> +
> +The following layouts are available:
> +
> +* **Mobile Layouts:**
> + * ``intl`` - A small international layout optimised for mobile devices. This layout consists of multiple layers which
> + can be switched on the fly, and overlays that appear on long-press of certain keys, adding input ability for
> + diacritics and other variants, as well as some emoji. The layers are:
> + * a basic qwerty layer
> + * a layer for numeric input, arrows, and punctuation
> + * a layer for function keys, media keys, and arrows
> + * a cyrillic layer (ЙЦУКЕН)
> + * a dialer/numeric layer
> + * ``sxmo`` - This is the original English layout for [sxmo](https://sr.ht/~mil/Sxmo) with only a qwerty layer and numeric/punctuation layer.
> +* **Traditional layouts**:
> + * ``en`` - An english layout without layers (QWERTY)
> + * ``de`` - A german layout (QWERTZ)
> + * ``ru`` - A russian layout (ЙЦУКЕН)
> + * ``sh`` - A serbo-croatian layout using latin script (QWERTZ)
> +
> Usage
> -----
>
> - $ svkbd-en
> + $ svkbd-intl
>
> This will open svkbd at the bottom of the screen, showing the default
> -English layout.
> +international layout.
>
> - $ svkbd-en -d
> + $ svkbd-intl -d
>
> -This tells svkbd-en to announce itself being a dock window, which then
> +This tells svkbd 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-intl -g 400x200+1+1
>
> -This will start svkbd-en with a size of 400x200 and at the upper left
> +This will start svkbd-intl with a size of 400x200 and at the upper left
> window corner.
>
> +For layouts that consist of multiple layers, you can enable layers on program start through either the ``-l`` flag or
> +through the ``SVKBD_LAYERS`` environment variable. They both take a comma separated list of layer names (as defined in
> +your ``layout.*.h``). Use the ``↺`` button in the bottom-left to cycle through all the layers.
> +
> +Some layouts come with overlays that will show when certain keys are hold pressed for a longer time. For
> +example, a long press on the ``a`` key will enable an overview showing all kinds of diacritic combinations for ``a``.
> +
> +Overlay functionality interferes with the ability to hold a key and have it outputted repeatedly. You can disable
> +overlay functionality with the ``-O`` flag or by setting the environment variable ``SVKBD_ENABLEOVERLAYS=0``. There is
> +also a key on the function layer of the keyboard itself to enable/disable this behaviour on the fly. Its label shows
> +``≅`` when the overlay functionality is enabled and ``≇`` when not.
> +
> +Notes
> +---------
> +
> +This virtual keyboard does not actually modify the X keyboard layout, the ``intl``, ``sxmo`` and ``en`` layouts simply rely on a standard US QWERTY layout (setxkbmap us) being activated, the other layouts (``de``, ``ru``, ``sh``) require their respective XKB keymaps to be active.
> +
> +If you use another XKB layout you will get unpredictable output that does not match the labels on the virtual keycaps!
> +
> Repository
> ----------
>
> diff --git a/layout.sxmo.h b/layout.sxmo.h
> index 2ca0727..f036fd6 100644
> --- a/layout.sxmo.h
> +++ b/layout.sxmo.h
> _AT_@ -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 },
> _AT_@ -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 },
> _AT_@ -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 },
> _AT_@ -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
> //---
> _AT_@ -195,6 +193,58 @@ static Key overlay[OVERLAYS] = {
> { 0, XK_r }, //New overlay
> //---
> { "ř", 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
> _AT_@ -262,6 +312,7 @@ static Key overlay[OVERLAYS] = {
>
>
> static Key keys_symbols[KEYS] = {
> + { "Esc", XK_Escape, 1 },
> { "1!", XK_1, 1 },
> { "2_AT_", XK_2, 1 },
> { "3#", XK_3, 1 },
> _AT_@ -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 },
> _AT_@ -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 },
> _AT_@ -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 },
> _AT_@ -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
> index 6044732..746af77 100644
> --- a/svkbd.c
> +++ b/svkbd.c
> _AT_@ -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();
> _AT_@ -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();
>
> _AT_@ -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 against immediate release
> 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;
>
> _AT_@ -122,6 +122,8 @@ Bool sigtermd = False;
> #endif
> #include LAYOUT
>
> +static Key* layers[LAYERS];
> +
> void
> motionnotify(XEvent *e)
> {
> _AT_@ -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"); fflush(stdout); }
> for (i = 0; i < LENGTH(keys); i++) {
> XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), False, 0);
> }
> _AT_@ -217,8 +228,8 @@ cleanup(void) {
>
> for (i = 0; i < SchemeLast; i++)
> free(scheme[i]);
> - drw_free(drw);
> drw_sync(drw);
> + drw_free(drw);
> XSync(dpy, False);
> XDestroyWindow(dpy, win);
> XSync(dpy, False);
> _AT_@ -272,7 +283,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);
> _AT_@ -322,17 +339,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) {
> _AT_@ -358,16 +364,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 actual keypress yet
> - 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 simulate the actual keypress yet
> record_press_begin(k->keysym);
> _AT_@ -437,6 +437,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:
> _AT_@ -445,7 +451,7 @@ unpress(Key *k, KeySym mod) {
> }
>
>
> - if ((pressbegin.tv_sec || pressbegin.tv_usec) && k && k->keysym == ispressingkeysym) {
> + if ((pressbegin.tv_sec || pressbegin.tv_usec) && enableoverlays && k && k->keysym == ispressingkeysym) {
> if (currentoverlay == -1) {
> if (get_press_duration() < overlay_delay) {
> if (debug) { printf("Delayed simulation of press after release: %ld\n", k->keysym); fflush(stdout); }
> _AT_@ -472,7 +478,7 @@ unpress(Key *k, KeySym mod) {
> if (k) {
> printf("Simulation of release: %ld\n", k->keysym); fflush(stdout);
> } else {
> - printf("Simulation of release (all keys)"); fflush(stdout);
> + printf("Simulation of release (all keys)\n"); fflush(stdout);
> }
> }
>
> _AT_@ -500,7 +506,7 @@ unpress(Key *k, KeySym mod) {
> }
> }
>
> - if (currentoverlay != -1) {
> + if (enableoverlays && currentoverlay != -1) {
> if (releaseprotect) {
> releaseprotect = 0;
> } else {
> _AT_@ -516,7 +522,6 @@ run(void) {
> fd_set fds;
> struct timeval tv;
> double duration = 0.0;
> - int cyclemodidx;
>
>
> xfd = ConnectionNumber(dpy);
> _AT_@ -528,6 +533,7 @@ run(void) {
> XFlush(dpy);
>
> while (running) {
> + usleep(100000L);
> FD_ZERO(&fds);
> FD_SET(xfd, &fds);
> if (select(xfd + 1, &fds, NULL, NULL, &tv)) {
> _AT_@ -543,19 +549,13 @@ run(void) {
> if (debug == 2) { printf("%f\n", duration); fflush(stdout); }
> if (get_press_duration() >= overlay_delay) {
> if (debug) { printf("press duration %f\n", duration); fflush(stdout); }
> - cyclemodidx = iscyclemod(ispressingkeysym);
> - if (cyclemodidx != -1) {
> - cyclemod();
> - } else {
> - showoverlay(hasoverlay(ispressingkeysym));
> - }
> + showoverlay(hasoverlay(ispressingkeysym));
> pressbegin.tv_sec = 0;
> pressbegin.tv_usec = 0;
> ispressingkeysym = 0;
> }
> }
> }
> - usleep(100000L);
> }
> }
>
> _AT_@ -719,14 +719,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", argv0);
> + 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 enable\n");
> + fprintf(stderr, " -fn [font] - Set font (Xft, e.g: DejaVu Sans:bold:size=20)\n");
> exit(1);
> }
>
> void
> cyclelayer() {
> currentlayer++;
> - if (currentlayer >= LAYERS)
> + if (currentlayer >= numlayers)
> currentlayer = 0;
> if (debug) { printf("Cycling to layer %d\n", currentlayer); fflush(stdout); }
> memcpy(&keys, layers[currentlayer], sizeof(keys_en));
> _AT_@ -735,29 +741,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); fflush(stdout); }
> - 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(stdout); }
> + memcpy(&keys, layers[currentlayer], sizeof(keys_en));
> + updatekeys();
> + drawkeyboard();
> }
>
> +
> void
> showoverlay(int idx) {
> if (debug) { printf("Showing overlay %d\n", idx); fflush(stdout); }
> _AT_@ -802,15 +798,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 specified");
> + 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_env);
> + const char* layers_env = getenv("SVKBD_LAYERS");
> + if (layers_env != NULL) {
> + layer_names_list = malloc(128);

No malloc check.

> + strcpy(layer_names_list, layers_env);
> + }
> +

Buffer overflow.

> +
> for (i = 1; argv[i]; i++) {
> if(!strcmp(argv[i], "-v")) {
> die("svkbd-"VERSION", © 2006-2020 svkbd engineers,"
> _AT_@ -842,9 +881,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 = malloc(128);

No malloc check.

> + strcpy(layer_names_list, argv[i+1]);

Buffer overflow.
> }
> }
>
> + init_layers(layer_names_list);
> +
> if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
> fprintf(stderr, "warning: no locale support\n");
> if(!(dpy = XOpenDisplay(0)))
> _AT_@ -853,5 +901,6 @@ main(int argc, char *argv[]) {
> run();
> cleanup();
> XCloseDisplay(dpy);
> + if (layer_names_list != NULL) free(layer_names_list);

No need to check free(NULL). free(NULL) is valid.

> return 0;
> }
> --
> 2.27.0
>
>

-- 
Kind regards,
Hiltjo
Received on Sat Jul 25 2020 - 01:35:20 CEST

This archive was generated by hypermail 2.3.0 : Sat Jul 25 2020 - 01:36:32 CEST