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 int fontsize = 16;
|
||||
static int fontsize = 20;
|
||||
static double overlay_delay = 1.0;
|
||||
static const char *fonts[] = {
|
||||
"monospace:size=16"
|
||||
"DejaVu Sans:bold:size=20"
|
||||
};
|
||||
static const char *colors[SchemeLast][2] = {
|
||||
/* fg bg */
|
||||
[SchemeNorm] = { "#58a7c6", "#14313d" },
|
||||
[SchemePress] = { "#ffffff", "#005577" },
|
||||
[SchemeNorm] = { "#ffffff", "#14313d" },
|
||||
[SchemePress] = { "#ffffff", "#000000" },
|
||||
[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_w, 1 },
|
||||
{ 0, XK_e, 1 },
|
||||
@ -23,7 +24,7 @@ static Key keys_en[40] = {
|
||||
{ 0, XK_j, 1 },
|
||||
{ 0, XK_k, 1 },
|
||||
{ 0, XK_l, 1 },
|
||||
{ ";:", XK_colon, 1 },
|
||||
{ "/?", XK_slash, 1 },
|
||||
/*{ "'", XK_apostrophe, 2 },*/
|
||||
|
||||
{ 0 }, /* New row */
|
||||
@ -37,7 +38,7 @@ static Key keys_en[40] = {
|
||||
{ 0, XK_m, 1 },
|
||||
/*{ "/?", XK_slash, 1 },*/
|
||||
{ "Tab", XK_Tab, 1 },
|
||||
{ "⇍ Bksp", XK_BackSpace, 2 },
|
||||
{ "⌫Bksp", XK_BackSpace, 2 },
|
||||
|
||||
{ 0 }, /* New row */
|
||||
{ "↺", XK_Cancel, 1},
|
||||
@ -53,7 +54,214 @@ static Key keys_en[40] = {
|
||||
{ "↲ 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 },
|
||||
{ "2@", XK_2, 1 },
|
||||
{ "3#", XK_3, 1 },
|
||||
@ -80,7 +288,55 @@ static Key keys_symbols[40] = {
|
||||
|
||||
{ 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_Left, 1 },
|
||||
{ "→", XK_Right, 1 },
|
||||
@ -88,22 +344,37 @@ static Key keys_symbols[40] = {
|
||||
{ "⇊", XK_Next, 1 },
|
||||
{ "⇈", XK_Prior, 1 },
|
||||
{ "Tab", XK_Tab, 1 },
|
||||
{ "⇍ Bksp", XK_BackSpace, 2 },
|
||||
{ "⌫Bksp", XK_BackSpace, 2 },
|
||||
|
||||
{ 0 }, /* New row */
|
||||
{ "↺", XK_Cancel, 1},
|
||||
{ "Shft", XK_Shift_L, 1 },
|
||||
/*{ "L", XK_Left, 1 },*/
|
||||
{ "↓", 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 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[] = {
|
||||
{ XK_Shift_L, Button2 },
|
||||
{ XK_Alt_L, Button3 },
|
||||
|
312
svkbd.c
312
svkbd.c
@ -8,6 +8,8 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/keysymdef.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
@ -18,16 +20,19 @@
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
|
||||
/* macros */
|
||||
#define LENGTH(x) (sizeof x / sizeof x[0])
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)))
|
||||
#define STRINGTOKEYSYM(X) (XStringToKeySym(X))
|
||||
|
||||
/* enums */
|
||||
enum { SchemeNorm, SchemePress, SchemeHighlight, SchemeLast };
|
||||
@ -62,11 +67,18 @@ 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();
|
||||
static void run(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 updatekeys();
|
||||
|
||||
@ -87,11 +99,20 @@ static Window root, win;
|
||||
static Clr* scheme[SchemeLast];
|
||||
static Bool running = True, isdock = False;
|
||||
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 char *name = "svkbd";
|
||||
static int debug = 0;
|
||||
|
||||
static KeySym ispressingkeysym;
|
||||
|
||||
Bool ispressing = False;
|
||||
Bool baselayer = True;
|
||||
Bool sigtermd = False;
|
||||
|
||||
/* 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
|
||||
leavenotify(XEvent *e) {
|
||||
if (currentoverlay != -1) {
|
||||
hideoverlay();
|
||||
}
|
||||
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
|
||||
press(Key *k, KeySym mod) {
|
||||
int i;
|
||||
int overlayidx = -1;
|
||||
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++) {
|
||||
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
||||
XTestFakeKeyEvent(dpy,
|
||||
XKeysymToKeycode(dpy, keys[i].keysym),
|
||||
True, 0);
|
||||
simulate_keypress(keys[i].keysym);
|
||||
}
|
||||
}
|
||||
pressedmod = mod;
|
||||
if(pressedmod) {
|
||||
XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, mod),
|
||||
True, 0);
|
||||
simulate_keypress(mod);
|
||||
}
|
||||
XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, k->keysym), True, 0);
|
||||
simulate_keypress(k->keysym);
|
||||
|
||||
for(i = 0; i < LENGTH(keys); i++) {
|
||||
if(keys[i].pressed && IsModifierKey(keys[i].keysym)) {
|
||||
XTestFakeKeyEvent(dpy,
|
||||
XKeysymToKeycode(dpy, keys[i].keysym),
|
||||
False, 0);
|
||||
simulate_keyrelease(keys[i].keysym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
unpress(Key *k, KeySym mod) {
|
||||
int i;
|
||||
@ -331,7 +435,7 @@ unpress(Key *k, KeySym mod) {
|
||||
if(k != NULL) {
|
||||
switch(k->keysym) {
|
||||
case XK_Cancel:
|
||||
togglelayer();
|
||||
cyclelayer();
|
||||
break;
|
||||
case XK_Break:
|
||||
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++) {
|
||||
if(keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
|
||||
XTestFakeKeyEvent(dpy,
|
||||
XKeysymToKeycode(dpy, keys[i].keysym),
|
||||
False, 0);
|
||||
simulate_keyrelease(keys[i].keysym);
|
||||
keys[i].pressed = 0;
|
||||
drawkey(&keys[i]);
|
||||
break;
|
||||
@ -352,22 +487,26 @@ unpress(Key *k, KeySym mod) {
|
||||
}
|
||||
if(i != LENGTH(keys)) {
|
||||
if(pressedmod) {
|
||||
XTestFakeKeyEvent(dpy,
|
||||
XKeysymToKeycode(dpy, pressedmod),
|
||||
False, 0);
|
||||
simulate_keyrelease(mod);
|
||||
}
|
||||
pressedmod = 0;
|
||||
|
||||
for(i = 0; i < LENGTH(keys); i++) {
|
||||
if(keys[i].pressed) {
|
||||
XTestFakeKeyEvent(dpy,
|
||||
XKeysymToKeycode(dpy,
|
||||
keys[i].keysym), False, 0);
|
||||
simulate_keyrelease(keys[i].keysym);
|
||||
keys[i].pressed = 0;
|
||||
drawkey(&keys[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentoverlay != -1) {
|
||||
if (releaseprotect) {
|
||||
releaseprotect = 0;
|
||||
} else {
|
||||
hideoverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -376,11 +515,14 @@ run(void) {
|
||||
int xfd;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
double duration = 0.0;
|
||||
int cyclemodidx;
|
||||
|
||||
|
||||
xfd = ConnectionNumber(dpy);
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = 2;
|
||||
tv.tv_sec = 1;
|
||||
|
||||
|
||||
//XSync(dpy, False);
|
||||
XFlush(dpy);
|
||||
@ -395,7 +537,25 @@ run(void) {
|
||||
(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.");
|
||||
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 */
|
||||
for (j = 0; j < SchemeLast; j++)
|
||||
scheme[j] = drw_scm_create(drw, colors[j], 2);
|
||||
@ -491,6 +675,7 @@ setup(void) {
|
||||
XSetWMProperties(dpy, win, &str, &str, NULL, 0, sizeh, wmh,
|
||||
ch);
|
||||
|
||||
XFree(keysyms);
|
||||
XFree(ch);
|
||||
XFree(wmh);
|
||||
XFree(str.value);
|
||||
@ -534,18 +719,84 @@ updatekeys() {
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
togglelayer() {
|
||||
memcpy(&keys, baselayer ? &keys_symbols : &keys_en, sizeof(keys_en));
|
||||
cyclelayer() {
|
||||
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();
|
||||
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
|
||||
sigterm(int sig)
|
||||
{
|
||||
@ -585,6 +836,10 @@ main(int argc, char *argv[]) {
|
||||
if(bitm & YNegative && wy == 0)
|
||||
wy = -1;
|
||||
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")) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
@ -600,4 +855,3 @@ main(int argc, char *argv[]) {
|
||||
XCloseDisplay(dpy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user