Added overlays (appearing on long press), multiple layer support (rather than just a toggle) with new layers, style changes
This commit is contained in:
parent
b488ae6410
commit
48994f125e
@ -1,11 +1,12 @@
|
|||||||
static const Bool wmborder = True;
|
static const Bool wmborder = True;
|
||||||
static int fontsize = 16;
|
static int fontsize = 20;
|
||||||
|
static double overlay_delay = 1.0;
|
||||||
static const char *fonts[] = {
|
static const char *fonts[] = {
|
||||||
"monospace:size=16"
|
"DejaVu Sans:bold:size=20"
|
||||||
};
|
};
|
||||||
static const char *colors[SchemeLast][2] = {
|
static const char *colors[SchemeLast][2] = {
|
||||||
/* fg bg */
|
/* fg bg */
|
||||||
[SchemeNorm] = { "#58a7c6", "#14313d" },
|
[SchemeNorm] = { "#ffffff", "#14313d" },
|
||||||
[SchemePress] = { "#ffffff", "#005577" },
|
[SchemePress] = { "#ffffff", "#000000" },
|
||||||
[SchemeHighlight] = { "#58a7c6", "#005577" },
|
[SchemeHighlight] = { "#58a7c6", "#005577" },
|
||||||
};
|
};
|
||||||
|
291
layout.sxmo.h
291
layout.sxmo.h
@ -1,6 +1,7 @@
|
|||||||
static Key keys[40] = { NULL };
|
#define KEYS 40
|
||||||
|
static Key keys[KEYS] = { NULL };
|
||||||
|
|
||||||
static Key keys_en[40] = {
|
static Key keys_en[KEYS] = {
|
||||||
{ 0, XK_q, 1 },
|
{ 0, XK_q, 1 },
|
||||||
{ 0, XK_w, 1 },
|
{ 0, XK_w, 1 },
|
||||||
{ 0, XK_e, 1 },
|
{ 0, XK_e, 1 },
|
||||||
@ -23,7 +24,7 @@ static Key keys_en[40] = {
|
|||||||
{ 0, XK_j, 1 },
|
{ 0, XK_j, 1 },
|
||||||
{ 0, XK_k, 1 },
|
{ 0, XK_k, 1 },
|
||||||
{ 0, XK_l, 1 },
|
{ 0, XK_l, 1 },
|
||||||
{ ";:", XK_colon, 1 },
|
{ "/?", XK_slash, 1 },
|
||||||
/*{ "'", XK_apostrophe, 2 },*/
|
/*{ "'", XK_apostrophe, 2 },*/
|
||||||
|
|
||||||
{ 0 }, /* New row */
|
{ 0 }, /* New row */
|
||||||
@ -37,7 +38,7 @@ static Key keys_en[40] = {
|
|||||||
{ 0, XK_m, 1 },
|
{ 0, XK_m, 1 },
|
||||||
/*{ "/?", XK_slash, 1 },*/
|
/*{ "/?", XK_slash, 1 },*/
|
||||||
{ "Tab", XK_Tab, 1 },
|
{ "Tab", XK_Tab, 1 },
|
||||||
{ "⇍ Bksp", XK_BackSpace, 2 },
|
{ "⌫Bksp", XK_BackSpace, 2 },
|
||||||
|
|
||||||
{ 0 }, /* New row */
|
{ 0 }, /* New row */
|
||||||
{ "↺", XK_Cancel, 1},
|
{ "↺", XK_Cancel, 1},
|
||||||
@ -53,7 +54,214 @@ static Key keys_en[40] = {
|
|||||||
{ "↲ Enter", XK_Return, 2 },
|
{ "↲ Enter", XK_Return, 2 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static Key keys_symbols[40] = {
|
#define OVERLAYS 165
|
||||||
|
static Key overlay[OVERLAYS] = {
|
||||||
|
{ 0, XK_a }, //Overlay for a
|
||||||
|
//---
|
||||||
|
{ "à", XK_agrave },
|
||||||
|
{ "á", XK_aacute },
|
||||||
|
{ "â", XK_acircumflex },
|
||||||
|
{ "ä", XK_adiaeresis },
|
||||||
|
{ "ą", XK_aogonek },
|
||||||
|
{ "ã", XK_atilde },
|
||||||
|
{ "ā", XK_amacron },
|
||||||
|
{ "ă", XK_abreve },
|
||||||
|
{ "å", XK_aring },
|
||||||
|
{ "æ", XK_ae },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_e }, //Overlay for e
|
||||||
|
//---
|
||||||
|
{ "è", XK_egrave },
|
||||||
|
{ "é", XK_eacute },
|
||||||
|
{ "ê", XK_ecircumflex },
|
||||||
|
{ "ë", XK_ediaeresis },
|
||||||
|
{ "ę", XK_eogonek },
|
||||||
|
{ "ē", XK_emacron },
|
||||||
|
{ "ė", XK_eabovedot },
|
||||||
|
{ 0, XK_Cancel },
|
||||||
|
//--
|
||||||
|
{ 0, XK_y }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ỳ", XK_ygrave },
|
||||||
|
{ "ý", XK_yacute },
|
||||||
|
{ "ŷ", XK_ycircumflex },
|
||||||
|
{ "ÿ", XK_ydiaeresis },
|
||||||
|
{ 0, XK_Cancel },
|
||||||
|
//--
|
||||||
|
{ 0, XK_u }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ù", XK_ugrave },
|
||||||
|
{ "ú", XK_uacute },
|
||||||
|
{ "û", XK_ucircumflex },
|
||||||
|
{ "ü", XK_udiaeresis },
|
||||||
|
{ "ų", XK_uogonek },
|
||||||
|
{ "ū", XK_umacron },
|
||||||
|
{ "ů", XK_uring},
|
||||||
|
{ "ŭ", XK_ubreve},
|
||||||
|
{ "ű", XK_udoubleacute },
|
||||||
|
{ 0, XK_Cancel },
|
||||||
|
//--
|
||||||
|
{ 0, XK_i }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ì", XK_igrave },
|
||||||
|
{ "í", XK_iacute },
|
||||||
|
{ "î", XK_icircumflex },
|
||||||
|
{ "ï", XK_idiaeresis },
|
||||||
|
{ "į", XK_iogonek },
|
||||||
|
{ "ī", XK_imacron },
|
||||||
|
{ "ı", XK_idotless },
|
||||||
|
{ 0, XK_Cancel },
|
||||||
|
//--
|
||||||
|
{ 0, XK_o }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ò", XK_ograve },
|
||||||
|
{ "ó", XK_oacute },
|
||||||
|
{ "ô", XK_ocircumflex },
|
||||||
|
{ "ö", XK_odiaeresis },
|
||||||
|
{ "ǫ", XK_ogonek },
|
||||||
|
{ "õ", XK_otilde },
|
||||||
|
{ "ō", XK_omacron },
|
||||||
|
{ "ø", XK_oslash },
|
||||||
|
{ "ő", XK_odoubleacute },
|
||||||
|
{ "œ", XK_oe },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_d }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ď", XK_dcaron },
|
||||||
|
{ "ð", XK_eth },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_c }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ç", XK_ccedilla },
|
||||||
|
{ "ĉ", XK_ccircumflex },
|
||||||
|
{ "č", XK_ccaron },
|
||||||
|
{ "ć", XK_cacute },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_s }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ş", XK_scedilla },
|
||||||
|
{ "ŝ", XK_scircumflex },
|
||||||
|
{ "š", XK_scaron },
|
||||||
|
{ "ś", XK_sacute },
|
||||||
|
{ "ß", XK_ssharp },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//---
|
||||||
|
{ 0, XK_z }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ž", XK_zcaron },
|
||||||
|
{ "ż", XK_zabovedot },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_n }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ñ", XK_ntilde },
|
||||||
|
{ "ń", XK_nacute },
|
||||||
|
{ "ň", XK_ncaron },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//
|
||||||
|
{ 0, XK_t }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ț", XK_tcedilla },
|
||||||
|
{ "ť", XK_tcaron },
|
||||||
|
{ "þ", XK_thorn },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//----
|
||||||
|
{ 0, XK_g }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ĝ", XK_gcircumflex },
|
||||||
|
{ "ğ", XK_gbreve },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//
|
||||||
|
{ 0, XK_h }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ĥ", XK_hcircumflex },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//
|
||||||
|
{ 0, XK_j }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ĵ", XK_jcircumflex },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_l }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ł", XK_lstroke },
|
||||||
|
{ "ľ", XK_lcaron },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ 0, XK_r }, //New overlay
|
||||||
|
//---
|
||||||
|
{ "ř", XK_rcaron },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//---
|
||||||
|
{ "🙂", 0x101f642 }, //emoji overlay
|
||||||
|
//---
|
||||||
|
{ "😀", 0x101f600 },
|
||||||
|
{ "😁", 0x101f601 },
|
||||||
|
{ "😂", 0x101f602 },
|
||||||
|
{ "😃", 0x101f603 },
|
||||||
|
{ "😄", 0x101f604 },
|
||||||
|
{ "😅", 0x101f605 },
|
||||||
|
{ "😆", 0x101f606 },
|
||||||
|
{ "😇", 0x101f607 },
|
||||||
|
{ "😈", 0x101f608 },
|
||||||
|
{ "😉", 0x101f609 },
|
||||||
|
{ "😊", 0x101f60a },
|
||||||
|
{ "😋", 0x101f60b },
|
||||||
|
{ "😌", 0x101f60c },
|
||||||
|
{ "😍", 0x101f60d },
|
||||||
|
{ "😎", 0x101f60e },
|
||||||
|
{ "😏", 0x101f60f },
|
||||||
|
{ "😐", 0x101f610 },
|
||||||
|
{ "😒", 0x101f612 },
|
||||||
|
{ "😓", 0x101f613 },
|
||||||
|
{ "😛", 0x101f61b },
|
||||||
|
{ "😮", 0x101f62e },
|
||||||
|
{ "😟", 0x101f61f },
|
||||||
|
{ "😟", 0x101f620 },
|
||||||
|
{ "😢", 0x101f622 },
|
||||||
|
{ "😭", 0x101f62d },
|
||||||
|
{ "😳", 0x101f633 },
|
||||||
|
{ "😴", 0x101f634 },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
//--
|
||||||
|
{ "/?", XK_slash }, //punctuation overlay
|
||||||
|
//--
|
||||||
|
{ "1!", XK_1, 1 },
|
||||||
|
{ "2@", XK_2, 1 },
|
||||||
|
{ "3#", XK_3, 1 },
|
||||||
|
{ "4$", XK_4, 1 },
|
||||||
|
{ "5%", XK_5, 1 },
|
||||||
|
{ "6^", XK_6, 1 },
|
||||||
|
{ "7&", XK_7, 1 },
|
||||||
|
{ "8*", XK_8, 1 },
|
||||||
|
{ "9(", XK_9, 1 },
|
||||||
|
{ "0)", XK_0, 1 },
|
||||||
|
{ "'\"", XK_apostrophe, 1 },
|
||||||
|
{ "`~", XK_grave, 1 },
|
||||||
|
{ "-_", XK_minus, 1 },
|
||||||
|
{ "=+", XK_plus, 1 },
|
||||||
|
{ "[{", XK_bracketleft, 1 },
|
||||||
|
{ "]}", XK_bracketright, 1 },
|
||||||
|
{ ",<", XK_comma, 1 },
|
||||||
|
{ ".>", XK_period, 1 },
|
||||||
|
{ "/?", XK_slash, 1 },
|
||||||
|
{ "\\|", XK_backslash, 1 },
|
||||||
|
{ "¡", XK_exclamdown, 1 },
|
||||||
|
{ "?", XK_questiondown, 1 },
|
||||||
|
{ "°", XK_degree, 1 },
|
||||||
|
{ "£", XK_sterling, 1 },
|
||||||
|
{ "€", XK_EuroSign, 1 },
|
||||||
|
{ "¥", XK_yen, 1 },
|
||||||
|
{ ";:", XK_colon, 1 },
|
||||||
|
{ 0, XK_Cancel }, /* XK_Cancel signifies overlay boundary */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Key keys_symbols[KEYS] = {
|
||||||
{ "1!", XK_1, 1 },
|
{ "1!", XK_1, 1 },
|
||||||
{ "2@", XK_2, 1 },
|
{ "2@", XK_2, 1 },
|
||||||
{ "3#", XK_3, 1 },
|
{ "3#", XK_3, 1 },
|
||||||
@ -80,7 +288,55 @@ static Key keys_symbols[40] = {
|
|||||||
|
|
||||||
{ 0 }, /* New row */
|
{ 0 }, /* New row */
|
||||||
|
|
||||||
{ "", XK_Shift_L|XK_bar, 1 },
|
{ "☺", 0x101f642, 1 },
|
||||||
|
{ "⇤", XK_Home, 1 },
|
||||||
|
{ "←", XK_Left, 1 },
|
||||||
|
{ "→", XK_Right, 1 },
|
||||||
|
{ "⇥", XK_End, 1 },
|
||||||
|
{ "⇊", XK_Next, 1 },
|
||||||
|
{ ";:", XK_colon, 1 },
|
||||||
|
{ "Tab", XK_Tab, 1 },
|
||||||
|
{ "⌫Bksp", XK_BackSpace, 2 },
|
||||||
|
|
||||||
|
{ 0 }, /* New row */
|
||||||
|
{ "↺", XK_Cancel, 1},
|
||||||
|
{ "Shft", XK_Shift_L, 1 },
|
||||||
|
{ "↓", 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] = {
|
||||||
|
{ "F1", XK_F1, 1 },
|
||||||
|
{ "F2", XK_F2, 1 },
|
||||||
|
{ "F3", XK_F3, 1 },
|
||||||
|
{ "F4", XK_F4, 1 },
|
||||||
|
{ "F5", XK_F5, 1 },
|
||||||
|
{ "F6", XK_F6, 1 },
|
||||||
|
{ "F7", XK_F7, 1 },
|
||||||
|
{ "F8", XK_F8, 1 },
|
||||||
|
{ "F9", XK_F9, 1 },
|
||||||
|
{ "F10", XK_F10, 1 },
|
||||||
|
|
||||||
|
{ 0 }, /* New row */
|
||||||
|
|
||||||
|
{ "▶", XF86XK_AudioPlay, 1 },
|
||||||
|
{ "●", XF86XK_AudioRecord, 1 },
|
||||||
|
{ "■", XF86XK_AudioStop, 1 },
|
||||||
|
{ "◂◂", XF86XK_AudioPrev, 1 },
|
||||||
|
{ "▸▸", XF86XK_AudioNext, 1 },
|
||||||
|
{ "♫M", XF86XK_AudioMute, 1 },
|
||||||
|
{ "♫-", XF86XK_AudioLowerVolume, 1 },
|
||||||
|
{ "♫+", XF86XK_AudioRaiseVolume, 1 },
|
||||||
|
{ "☀-", XF86XK_MonBrightnessDown, 1 },
|
||||||
|
{ "☀+", XF86XK_MonBrightnessUp, 1 },
|
||||||
|
|
||||||
|
{ 0 }, /* New row */
|
||||||
|
|
||||||
|
{ "Del", XK_Delete, 1 },
|
||||||
{ "⇤", XK_Home, 1 },
|
{ "⇤", XK_Home, 1 },
|
||||||
{ "←", XK_Left, 1 },
|
{ "←", XK_Left, 1 },
|
||||||
{ "→", XK_Right, 1 },
|
{ "→", XK_Right, 1 },
|
||||||
@ -88,22 +344,37 @@ static Key keys_symbols[40] = {
|
|||||||
{ "⇊", XK_Next, 1 },
|
{ "⇊", XK_Next, 1 },
|
||||||
{ "⇈", XK_Prior, 1 },
|
{ "⇈", XK_Prior, 1 },
|
||||||
{ "Tab", XK_Tab, 1 },
|
{ "Tab", XK_Tab, 1 },
|
||||||
{ "⇍ Bksp", XK_BackSpace, 2 },
|
{ "⌫Bksp", XK_BackSpace, 2 },
|
||||||
|
|
||||||
{ 0 }, /* New row */
|
{ 0 }, /* New row */
|
||||||
{ "↺", XK_Cancel, 1},
|
{ "↺", XK_Cancel, 1},
|
||||||
{ "Shft", XK_Shift_L, 1 },
|
{ "Shft", XK_Shift_L, 1 },
|
||||||
/*{ "L", XK_Left, 1 },*/
|
|
||||||
{ "↓", XK_Down, 1 },
|
{ "↓", XK_Down, 1 },
|
||||||
{ "↑", XK_Up, 1 },
|
{ "↑", XK_Up, 1 },
|
||||||
/*{ "R", XK_Right, 1 },*/
|
|
||||||
{ "", XK_space, 2 },
|
{ "", XK_space, 2 },
|
||||||
{ "Esc", XK_Escape, 1 },
|
{ "Esc", XK_Escape, 1 },
|
||||||
{ "Ctrl", XK_Control_L, 1 },
|
{ "Ctrl", XK_Control_L, 1 },
|
||||||
/*{ "Alt", XK_Alt_L, 1 },*/
|
|
||||||
{ "↲ Enter", XK_Return, 2 },
|
{ "↲ Enter", XK_Return, 2 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define LAYERS 3
|
||||||
|
static Key* layers[LAYERS] = {
|
||||||
|
keys_en,
|
||||||
|
keys_symbols,
|
||||||
|
keys_functions,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#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 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Buttonmod buttonmods[] = {
|
Buttonmod buttonmods[] = {
|
||||||
{ XK_Shift_L, Button2 },
|
{ XK_Shift_L, Button2 },
|
||||||
{ XK_Alt_L, Button3 },
|
{ XK_Alt_L, Button3 },
|
||||||
|
312
svkbd.c
312
svkbd.c
@ -8,6 +8,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
|
#include <X11/keysymdef.h>
|
||||||
|
#include <X11/XF86keysym.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
@ -18,16 +20,19 @@
|
|||||||
#include <X11/extensions/Xinerama.h>
|
#include <X11/extensions/Xinerama.h>
|
||||||
#endif
|
#endif
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "drw.h"
|
#include "drw.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
#define LENGTH(x) (sizeof x / sizeof x[0])
|
#define LENGTH(x) (sizeof x / sizeof x[0])
|
||||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)))
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)))
|
||||||
|
#define STRINGTOKEYSYM(X) (XStringToKeySym(X))
|
||||||
|
|
||||||
/* enums */
|
/* enums */
|
||||||
enum { SchemeNorm, SchemePress, SchemeHighlight, SchemeLast };
|
enum { SchemeNorm, SchemePress, SchemeHighlight, SchemeLast };
|
||||||
@ -62,11 +67,18 @@ static void drawkeyboard(void);
|
|||||||
static void drawkey(Key *k);
|
static void drawkey(Key *k);
|
||||||
static void expose(XEvent *e);
|
static void expose(XEvent *e);
|
||||||
static Key *findkey(int x, int y);
|
static Key *findkey(int x, int y);
|
||||||
|
static int iscyclemod(KeySym keysym);
|
||||||
static void leavenotify(XEvent *e);
|
static void leavenotify(XEvent *e);
|
||||||
static void press(Key *k, KeySym mod);
|
static void press(Key *k, KeySym mod);
|
||||||
|
static double get_press_duration();
|
||||||
static void run(void);
|
static void run(void);
|
||||||
static void setup(void);
|
static void setup(void);
|
||||||
static void togglelayer();
|
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 unpress(Key *k, KeySym mod);
|
static void unpress(Key *k, KeySym mod);
|
||||||
static void updatekeys();
|
static void updatekeys();
|
||||||
|
|
||||||
@ -87,11 +99,20 @@ static Window root, win;
|
|||||||
static Clr* scheme[SchemeLast];
|
static Clr* scheme[SchemeLast];
|
||||||
static Bool running = True, isdock = False;
|
static Bool running = True, isdock = False;
|
||||||
static KeySym pressedmod = 0;
|
static KeySym pressedmod = 0;
|
||||||
|
static struct timeval pressbegin;
|
||||||
|
static int currentlayer = 0;
|
||||||
|
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 int rows = 0, ww = 0, wh = 0, wx = 0, wy = 0;
|
||||||
static char *name = "svkbd";
|
static char *name = "svkbd";
|
||||||
|
static int debug = 0;
|
||||||
|
|
||||||
|
static KeySym ispressingkeysym;
|
||||||
|
|
||||||
Bool ispressing = False;
|
Bool ispressing = False;
|
||||||
Bool baselayer = True;
|
|
||||||
Bool sigtermd = False;
|
Bool sigtermd = False;
|
||||||
|
|
||||||
/* configuration, allows nested code to access above variables */
|
/* configuration, allows nested code to access above variables */
|
||||||
@ -287,43 +308,126 @@ findkey(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
hasoverlay(KeySym keysym) {
|
||||||
|
int begin, i;
|
||||||
|
begin = 0;
|
||||||
|
for(i = 0; i < OVERLAYS; i++) {
|
||||||
|
if(overlay[i].keysym == XK_Cancel) {
|
||||||
|
begin = i+1;
|
||||||
|
} else if(overlay[i].keysym == keysym) {
|
||||||
|
return begin+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iscyclemod(KeySym keysym) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < CYCLEMODS; i++) {
|
||||||
|
if(cyclemods[i].keysym == keysym) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
leavenotify(XEvent *e) {
|
leavenotify(XEvent *e) {
|
||||||
|
if (currentoverlay != -1) {
|
||||||
|
hideoverlay();
|
||||||
|
}
|
||||||
unpress(NULL, 0);
|
unpress(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void record_press_begin(KeySym ks) {
|
||||||
|
//record the begin of the press, don't simulate the actual keypress yet
|
||||||
|
gettimeofday(&pressbegin, NULL);
|
||||||
|
ispressingkeysym = ks;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
press(Key *k, KeySym mod) {
|
press(Key *k, KeySym mod) {
|
||||||
int i;
|
int i;
|
||||||
|
int overlayidx = -1;
|
||||||
k->pressed = !k->pressed;
|
k->pressed = !k->pressed;
|
||||||
|
|
||||||
if(!IsModifierKey(k->keysym)) {
|
if (debug) { printf("Begin press: %ld\n", k->keysym); fflush(stdout); }
|
||||||
|
pressbegin.tv_sec = 0;
|
||||||
|
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)
|
||||||
|
overlayidx = hasoverlay(k->keysym);
|
||||||
|
if (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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (debug) { printf("Simulating press: %ld\n", k->keysym); fflush(stdout); }
|
||||||
for(i = 0; i < LENGTH(keys); i++) {
|
for(i = 0; i < LENGTH(keys); i++) {
|
||||||
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
||||||
XTestFakeKeyEvent(dpy,
|
simulate_keypress(keys[i].keysym);
|
||||||
XKeysymToKeycode(dpy, keys[i].keysym),
|
|
||||||
True, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pressedmod = mod;
|
pressedmod = mod;
|
||||||
if(pressedmod) {
|
if(pressedmod) {
|
||||||
XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, mod),
|
simulate_keypress(mod);
|
||||||
True, 0);
|
|
||||||
}
|
}
|
||||||
XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, k->keysym), True, 0);
|
simulate_keypress(k->keysym);
|
||||||
|
|
||||||
for(i = 0; i < LENGTH(keys); i++) {
|
for(i = 0; i < LENGTH(keys); i++) {
|
||||||
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
||||||
XTestFakeKeyEvent(dpy,
|
simulate_keyrelease(keys[i].keysym);
|
||||||
XKeysymToKeycode(dpy, keys[i].keysym),
|
}
|
||||||
False, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawkey(k);
|
drawkey(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int tmp_remap(KeySym keysym) {
|
||||||
|
XChangeKeyboardMapping(dpy, tmp_keycode, 1, &keysym, 1);
|
||||||
|
XSync(dpy, False);
|
||||||
|
return tmp_keycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
simulate_keypress(KeySym keysym) {
|
||||||
|
KeyCode code = XKeysymToKeycode(dpy, keysym);
|
||||||
|
if (code == 0)
|
||||||
|
code = tmp_remap(keysym);
|
||||||
|
XTestFakeKeyEvent(dpy, code, True, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
simulate_keyrelease(KeySym keysym) {
|
||||||
|
KeyCode code = XKeysymToKeycode(dpy, keysym);
|
||||||
|
if (code == 0)
|
||||||
|
code = tmp_remap(keysym);
|
||||||
|
XTestFakeKeyEvent(dpy, code, False, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double get_press_duration() {
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
return (double) ((now.tv_sec * 1000000L + now.tv_usec) - (pressbegin.tv_sec * 1000000L + pressbegin.tv_usec)) / (double) 1000000L;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
unpress(Key *k, KeySym mod) {
|
unpress(Key *k, KeySym mod) {
|
||||||
int i;
|
int i;
|
||||||
@ -331,7 +435,7 @@ unpress(Key *k, KeySym mod) {
|
|||||||
if(k != NULL) {
|
if(k != NULL) {
|
||||||
switch(k->keysym) {
|
switch(k->keysym) {
|
||||||
case XK_Cancel:
|
case XK_Cancel:
|
||||||
togglelayer();
|
cyclelayer();
|
||||||
break;
|
break;
|
||||||
case XK_Break:
|
case XK_Break:
|
||||||
running = False;
|
running = False;
|
||||||
@ -340,11 +444,42 @@ unpress(Key *k, KeySym mod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((pressbegin.tv_sec || pressbegin.tv_usec) && 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); }
|
||||||
|
//simulate the press event, as we postponed it earlier in press()
|
||||||
|
for(i = 0; i < LENGTH(keys); i++) {
|
||||||
|
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
||||||
|
simulate_keypress(keys[i].keysym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pressedmod = mod;
|
||||||
|
if(pressedmod) {
|
||||||
|
simulate_keypress(mod);
|
||||||
|
}
|
||||||
|
simulate_keypress(k->keysym);
|
||||||
|
pressbegin.tv_sec = 0;
|
||||||
|
pressbegin.tv_usec = 0;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
if (k) {
|
||||||
|
printf("Simulation of release: %ld\n", k->keysym); fflush(stdout);
|
||||||
|
} else {
|
||||||
|
printf("Simulation of release (all keys)"); fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for(i = 0; i < LENGTH(keys); i++) {
|
for(i = 0; i < LENGTH(keys); i++) {
|
||||||
if(keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
|
if(keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
|
||||||
XTestFakeKeyEvent(dpy,
|
simulate_keyrelease(keys[i].keysym);
|
||||||
XKeysymToKeycode(dpy, keys[i].keysym),
|
|
||||||
False, 0);
|
|
||||||
keys[i].pressed = 0;
|
keys[i].pressed = 0;
|
||||||
drawkey(&keys[i]);
|
drawkey(&keys[i]);
|
||||||
break;
|
break;
|
||||||
@ -352,22 +487,26 @@ unpress(Key *k, KeySym mod) {
|
|||||||
}
|
}
|
||||||
if(i != LENGTH(keys)) {
|
if(i != LENGTH(keys)) {
|
||||||
if(pressedmod) {
|
if(pressedmod) {
|
||||||
XTestFakeKeyEvent(dpy,
|
simulate_keyrelease(mod);
|
||||||
XKeysymToKeycode(dpy, pressedmod),
|
|
||||||
False, 0);
|
|
||||||
}
|
}
|
||||||
pressedmod = 0;
|
pressedmod = 0;
|
||||||
|
|
||||||
for(i = 0; i < LENGTH(keys); i++) {
|
for(i = 0; i < LENGTH(keys); i++) {
|
||||||
if(keys[i].pressed) {
|
if(keys[i].pressed) {
|
||||||
XTestFakeKeyEvent(dpy,
|
simulate_keyrelease(keys[i].keysym);
|
||||||
XKeysymToKeycode(dpy,
|
|
||||||
keys[i].keysym), False, 0);
|
|
||||||
keys[i].pressed = 0;
|
keys[i].pressed = 0;
|
||||||
drawkey(&keys[i]);
|
drawkey(&keys[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentoverlay != -1) {
|
||||||
|
if (releaseprotect) {
|
||||||
|
releaseprotect = 0;
|
||||||
|
} else {
|
||||||
|
hideoverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -376,11 +515,14 @@ run(void) {
|
|||||||
int xfd;
|
int xfd;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
double duration = 0.0;
|
||||||
|
int cyclemodidx;
|
||||||
|
|
||||||
|
|
||||||
xfd = ConnectionNumber(dpy);
|
xfd = ConnectionNumber(dpy);
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
tv.tv_sec = 2;
|
tv.tv_sec = 1;
|
||||||
|
|
||||||
|
|
||||||
//XSync(dpy, False);
|
//XSync(dpy, False);
|
||||||
XFlush(dpy);
|
XFlush(dpy);
|
||||||
@ -395,7 +537,25 @@ run(void) {
|
|||||||
(handler[ev.type])(&ev); /* call handler */
|
(handler[ev.type])(&ev); /* call handler */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (ispressing && ispressingkeysym) {
|
||||||
|
duration = get_press_duration();
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
pressbegin.tv_sec = 0;
|
||||||
|
pressbegin.tv_usec = 0;
|
||||||
|
ispressingkeysym = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep(100000L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,6 +593,30 @@ setup(void) {
|
|||||||
die("no fonts could be loaded.");
|
die("no fonts could be loaded.");
|
||||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
|
||||||
|
//find an unused keycode to use as a temporary keycode (derived from source: https://stackoverflow.com/questions/44313966/c-xtest-emitting-key-presses-for-every-unicode-character)
|
||||||
|
KeySym *keysyms = NULL;
|
||||||
|
int keysyms_per_keycode = 0;
|
||||||
|
int keycode_low, keycode_high;
|
||||||
|
Bool key_is_empty;
|
||||||
|
int symindex;
|
||||||
|
XDisplayKeycodes(dpy, &keycode_low, &keycode_high);
|
||||||
|
keysyms = XGetKeyboardMapping(dpy, keycode_low, keycode_high - keycode_low, &keysyms_per_keycode);
|
||||||
|
for(i = keycode_low; i <= keycode_high; i++) {
|
||||||
|
key_is_empty = True;
|
||||||
|
for(j = 0; j < keysyms_per_keycode; j++) {
|
||||||
|
symindex = (i - keycode_low) * keysyms_per_keycode + j;
|
||||||
|
if(keysyms[symindex] != 0) {
|
||||||
|
key_is_empty = False;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key_is_empty) {
|
||||||
|
tmp_keycode = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* init appearance */
|
/* init appearance */
|
||||||
for (j = 0; j < SchemeLast; j++)
|
for (j = 0; j < SchemeLast; j++)
|
||||||
scheme[j] = drw_scm_create(drw, colors[j], 2);
|
scheme[j] = drw_scm_create(drw, colors[j], 2);
|
||||||
@ -491,6 +675,7 @@ setup(void) {
|
|||||||
XSetWMProperties(dpy, win, &str, &str, NULL, 0, sizeh, wmh,
|
XSetWMProperties(dpy, win, &str, &str, NULL, 0, sizeh, wmh,
|
||||||
ch);
|
ch);
|
||||||
|
|
||||||
|
XFree(keysyms);
|
||||||
XFree(ch);
|
XFree(ch);
|
||||||
XFree(wmh);
|
XFree(wmh);
|
||||||
XFree(str.value);
|
XFree(str.value);
|
||||||
@ -534,18 +719,84 @@ updatekeys() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
usage(char *argv0) {
|
usage(char *argv0) {
|
||||||
fprintf(stderr, "usage: %s [-hdv] [-g geometry]\n", argv0);
|
fprintf(stderr, "usage: %s [-hdvD] [-g geometry] [-fn font]\n", argv0);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
togglelayer() {
|
cyclelayer() {
|
||||||
memcpy(&keys, baselayer ? &keys_symbols : &keys_en, sizeof(keys_en));
|
currentlayer++;
|
||||||
|
if (currentlayer >= LAYERS)
|
||||||
|
currentlayer = 0;
|
||||||
|
if (debug) { printf("Cycling to layer %d\n", currentlayer); fflush(stdout); }
|
||||||
|
memcpy(&keys, layers[currentlayer], sizeof(keys_en));
|
||||||
updatekeys();
|
updatekeys();
|
||||||
drawkeyboard();
|
drawkeyboard();
|
||||||
baselayer = !baselayer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
showoverlay(int idx) {
|
||||||
|
if (debug) { printf("Showing overlay %d\n", idx); fflush(stdout); }
|
||||||
|
int i,j;
|
||||||
|
//unpress existing key (visually only)
|
||||||
|
for(i = 0; i < LENGTH(keys); i++) {
|
||||||
|
if(keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
|
||||||
|
keys[i].pressed = 0;
|
||||||
|
drawkey(&keys[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = idx, j=0; i < OVERLAYS; i++, j++) {
|
||||||
|
if (overlay[i].keysym == XK_Cancel) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (keys[j].keysym == 0) j++;
|
||||||
|
keys[j].label = overlay[i].label;
|
||||||
|
keys[j].keysym = overlay[i].keysym;
|
||||||
|
}
|
||||||
|
currentoverlay = idx;
|
||||||
|
overlaykeysym = ispressingkeysym;
|
||||||
|
releaseprotect = 1;
|
||||||
|
updatekeys();
|
||||||
|
drawkeyboard();
|
||||||
|
XSync(dpy, False);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hideoverlay() {
|
||||||
|
if (debug) { printf("Hiding overlay %d\n", currentoverlay); fflush(stdout); }
|
||||||
|
currentoverlay = -1;
|
||||||
|
overlaykeysym = 0;
|
||||||
|
currentlayer = -1;
|
||||||
|
cyclelayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sigterm(int sig)
|
sigterm(int sig)
|
||||||
{
|
{
|
||||||
@ -585,6 +836,10 @@ main(int argc, char *argv[]) {
|
|||||||
if(bitm & YNegative && wy == 0)
|
if(bitm & YNegative && wy == 0)
|
||||||
wy = -1;
|
wy = -1;
|
||||||
i++;
|
i++;
|
||||||
|
} else if (!strcmp(argv[i], "-fn")) { /* font or font set */
|
||||||
|
fonts[0] = argv[++i];
|
||||||
|
} else if(!strcmp(argv[i], "-D")) {
|
||||||
|
debug = 1;
|
||||||
} else if(!strcmp(argv[i], "-h")) {
|
} else if(!strcmp(argv[i], "-h")) {
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
@ -600,4 +855,3 @@ main(int argc, char *argv[]) {
|
|||||||
XCloseDisplay(dpy);
|
XCloseDisplay(dpy);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user