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
> @@ -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.
>  
> @@ -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
> @@ -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
>          //---
> @@ -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
> @@ -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
> index 6044732..746af77 100644
> --- 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 
> 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;
>  
> @@ -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"); 
> fflush(stdout); }
>               for (i = 0; i < LENGTH(keys); i++) {
>                       XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, 
> keys[i].keysym), False, 0);
>               }
> @@ -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);
> @@ -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);
> @@ -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) {
> @@ -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);
> @@ -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:
> @@ -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); }
> @@ -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);
>               }
>       }
>  
> @@ -500,7 +506,7 @@ unpress(Key *k, KeySym mod) {
>               }
>       }
>  
> -     if (currentoverlay != -1) {
> +     if (enableoverlays && currentoverlay != -1) {
>               if (releaseprotect) {
>                       releaseprotect = 0;
>               } else {
> @@ -516,7 +522,6 @@ run(void) {
>       fd_set fds;
>       struct timeval tv;
>       double duration = 0.0;
> -     int cyclemodidx;
>  
>  
>       xfd = ConnectionNumber(dpy);
> @@ -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)) {
> @@ -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);
>       }
>  }
>  
> @@ -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));
> @@ -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); }
> @@ -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,"
> @@ -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)))
> @@ -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

Reply via email to