Prevent spurious modifier key presses (#128)

Some applications make use of the alt (e.g firefox) and meta (e.g gnome)
keys in isolation. Thus it is necessary to interpose additional events
to prevent the likes of '<alt down> <alt up>' from being interpreted as
key presses.

E.G

	[alt]

	a = x

will currently cause 'alt+a' to produce:

	<alt down>
	<alt up>

	<x down>
	<x up>

In most cases this is identical to '<x>', however in some contexts the
additional alt keypress is meaningful.

To prevent this, we intelligently emit '<alt>+<control>' instead by sandwiching the
'<alt up>' event like so: '<control down> <alt up> <control up>'

The full sequence thus becomes:

	<alt down>
	<control down>
	<alt up>
	<control up>

	<x down>
	<x up>
master
Raheman Vaiya 4 years ago
parent f3b33f3a5b
commit 076a1868e5
  1. 125
      src/keyboard.c
  2. 1
      src/keyboard.h
  3. 9
      t/disarm.t
  4. 5
      t/disarm2.t
  5. 15
      t/disarm3.t
  6. 8
      t/meta.t
  7. 2
      t/swap.t
  8. 2
      t/swap2.t
  9. 4
      t/swap4.t
  10. 4
      t/swap5.t
  11. 2
      t/swap7.t
  12. 1
      t/test.conf

@ -32,6 +32,13 @@
#define MACRO_REPEAT_TIMEOUT 400 /* In ms */ #define MACRO_REPEAT_TIMEOUT 400 /* In ms */
#define MACRO_REPEAT_INTERVAL 20 /* In ms */ #define MACRO_REPEAT_INTERVAL 20 /* In ms */
static long get_time_ms()
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return (tv.tv_sec*1E3)+tv.tv_nsec/1E6;
}
static void send_mods(uint16_t mods, int press) static void send_mods(uint16_t mods, int press)
{ {
size_t i; size_t i;
@ -45,6 +52,30 @@ static void send_mods(uint16_t mods, int press)
} }
} }
/* Intelligently disarm active mods to avoid spurious key press events. */
static void disarm_mods(uint16_t mods)
{
uint16_t dmods = (MOD_ALT|MOD_SUPER) & mods;
/*
* We interpose a control sequence to prevent '<alt down> <alt up>'
* from being interpreted as an alt keypress.
*/
if (dmods) {
if (keystate[KEY_LEFTCTRL])
send_mods(dmods, 0);
else {
send_key(KEY_LEFTCTRL, 1);
send_mods(dmods, 0);
send_key(KEY_LEFTCTRL, 0);
}
mods &= ~dmods;
}
send_mods(mods, 0);
}
static void kbd_lookup_descriptor(struct keyboard *kbd, static void kbd_lookup_descriptor(struct keyboard *kbd,
uint16_t code, uint16_t code,
@ -114,7 +145,7 @@ static void kbd_lookup_descriptor(struct keyboard *kbd,
*descriptor_layer = dl; *descriptor_layer = dl;
} }
/* Compute the current modifier state based on the activated layers. */ /* Compute the current modifier set based on the activated layers. */
static uint16_t kbd_compute_mods(struct keyboard *kbd) static uint16_t kbd_compute_mods(struct keyboard *kbd)
{ {
size_t i; size_t i;
@ -128,12 +159,6 @@ static uint16_t kbd_compute_mods(struct keyboard *kbd)
return mods; return mods;
} }
/* Compute and apply the current mod state to the virtual keyboard. */
static void kbd_reify_mods(struct keyboard *kbd)
{
set_mods(kbd_compute_mods(kbd));
}
/* Returns the active_layer struct associated with the given layer index. */ /* Returns the active_layer struct associated with the given layer index. */
static const struct active_layer *kbd_lookup_active_layer(struct keyboard *kbd, int layer) static const struct active_layer *kbd_lookup_active_layer(struct keyboard *kbd, int layer)
{ {
@ -149,7 +174,7 @@ static const struct active_layer *kbd_lookup_active_layer(struct keyboard *kbd,
return NULL; return NULL;
} }
static void kbd_deactivate_layer(struct keyboard *kbd, int layer_idx) static void kbd_deactivate_layer(struct keyboard *kbd, int layer_idx, int disarm_mods_p)
{ {
int i; int i;
int n = kbd->nr_active_layers; int n = kbd->nr_active_layers;
@ -168,7 +193,10 @@ static void kbd_deactivate_layer(struct keyboard *kbd, int layer_idx)
} }
} }
send_mods(layer->mods & ~active_mods, 0); if (disarm_mods_p)
disarm_mods(layer->mods & ~active_mods);
else
send_mods(layer->mods & ~active_mods, 0);
} }
static void kbd_clear_oneshots(struct keyboard *kbd) static void kbd_clear_oneshots(struct keyboard *kbd)
@ -234,7 +262,7 @@ static void kbd_swap_layer(struct keyboard *kbd,
struct active_key *ak = &kbd->active_keys[i]; struct active_key *ak = &kbd->active_keys[i];
if((ak->d.op == OP_LAYER || ak->d.op == OP_OVERLOAD || ak->d.op == OP_SWAP) && ak->d.args[0].idx == dl) { if((ak->d.op == OP_LAYER || ak->d.op == OP_OVERLOAD || ak->d.op == OP_SWAP) && ak->d.args[0].idx == dl) {
kbd_deactivate_layer(kbd, dl); kbd_deactivate_layer(kbd, dl, 1);
kbd_activate_layer(kbd, replacment_layer, 0); kbd_activate_layer(kbd, replacment_layer, 0);
ak->d = new_descriptor; ak->d = new_descriptor;
@ -304,33 +332,36 @@ void kbd_reset(struct keyboard *kbd)
kbd->config = kbd->original_config; kbd->config = kbd->original_config;
} }
static long get_time_ms() static void kbd_start_sequence(struct keyboard *kbd, const struct key_sequence *sequence, int literally)
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return (tv.tv_sec*1E3)+tv.tv_nsec/1E6;
}
void kbd_execute_sequence(struct keyboard *kbd, const struct key_sequence *sequence, int literally)
{ {
uint16_t active_mods = kbd_compute_mods(kbd); uint16_t active_mods = kbd_compute_mods(kbd);
/* Avoid spurious key up actions */
if (!sequence->code && !sequence->mods) if (!sequence->code && !sequence->mods)
return; return;
if (literally) if (literally)
send_mods(active_mods, 0); disarm_mods(active_mods);
send_mods(sequence->mods, 1); send_mods(sequence->mods, 1);
send_key(sequence->code, 1); send_key(sequence->code, 1);
}
static void kbd_end_sequence(struct keyboard *kbd, const struct key_sequence *sequence)
{
uint16_t active_mods = kbd_compute_mods(kbd);
send_key(sequence->code, 0); send_key(sequence->code, 0);
send_mods(sequence->mods, 0); send_mods(sequence->mods, 0);
send_mods(active_mods, 1);
}
if (literally) static void kbd_execute_sequence(struct keyboard *kbd, const struct key_sequence *sequence, int literally)
send_mods(active_mods, 1); {
kbd_start_sequence(kbd, sequence, literally);
kbd_end_sequence(kbd, sequence);
} }
/* /*
* Here be tiny dragons. * Here be tiny dragons.
* *
@ -347,9 +378,10 @@ long kbd_process_key_event(struct keyboard *kbd,
int dl; int dl;
struct descriptor d; struct descriptor d;
int timeout = 0; int timeout = 0;
int disarm = 1;
static struct key_sequence active_sequence = {0};
static int oneshot_latch = 0; static int oneshot_latch = 0;
static int last_pressed_keycode = 0;
static const struct macro *active_macro = NULL; static const struct macro *active_macro = NULL;
static struct { static struct {
@ -361,6 +393,11 @@ long kbd_process_key_event(struct keyboard *kbd,
uint8_t is_active; uint8_t is_active;
} pending_overload = {0}; } pending_overload = {0};
if (active_sequence.code) {
kbd_end_sequence(kbd, &active_sequence);
active_sequence.code = 0;
}
if (active_macro) { if (active_macro) {
if (!code) { if (!code) {
kbd_execute_macro(kbd, active_macro); kbd_execute_macro(kbd, active_macro);
@ -397,13 +434,17 @@ long kbd_process_key_event(struct keyboard *kbd,
const struct macro *macro; const struct macro *macro;
case OP_KEYSEQ: case OP_KEYSEQ:
/* TODO: distinguish between key codes and key sequences at the config level. */
sequence = &d.args[0].sequence; sequence = &d.args[0].sequence;
is_sequence = sequence->mods || dl != kbd->layout; is_sequence = sequence->mods || dl != kbd->layout;
if (is_sequence) { if (is_sequence) {
if (pressed) if (pressed) {
kbd_execute_sequence(kbd, sequence, 1); active_sequence = *sequence;
kbd_start_sequence(kbd, sequence, 1);
}
} else { } else {
disarm = 0;
send_key(sequence->code, pressed); send_key(sequence->code, pressed);
} }
@ -424,7 +465,7 @@ long kbd_process_key_event(struct keyboard *kbd,
if (al->oneshot) /* Allow oneshot layers to toggle themselves. */ if (al->oneshot) /* Allow oneshot layers to toggle themselves. */
kbd_activate_layer(kbd, layer, 0); kbd_activate_layer(kbd, layer, 0);
else else
kbd_deactivate_layer(kbd, layer); kbd_deactivate_layer(kbd, layer, 1);
} else } else
kbd_activate_layer(kbd, layer, 0); kbd_activate_layer(kbd, layer, 0);
} }
@ -440,8 +481,13 @@ long kbd_process_key_event(struct keyboard *kbd,
if (pressed) if (pressed)
kbd_activate_layer(kbd, layer, 0); kbd_activate_layer(kbd, layer, 0);
else else {
kbd_deactivate_layer(kbd, layer); int disarm = kbd->disarm_flag;
if (kbd->last_pressed_keycode == code)
disarm = 0;
kbd_deactivate_layer(kbd, layer, disarm);
}
break; break;
case OP_ONESHOT: case OP_ONESHOT:
@ -453,7 +499,7 @@ long kbd_process_key_event(struct keyboard *kbd,
} else if (oneshot_latch) /* No interposed KEYSEQ since key down (other modifiers don't interfere with this). */ } else if (oneshot_latch) /* No interposed KEYSEQ since key down (other modifiers don't interfere with this). */
kbd_activate_layer(kbd, layer, 1); kbd_activate_layer(kbd, layer, 1);
else else
kbd_deactivate_layer(kbd, layer); kbd_deactivate_layer(kbd, layer, 1);
break; break;
case OP_SWAP: case OP_SWAP:
@ -463,8 +509,8 @@ long kbd_process_key_event(struct keyboard *kbd,
if (pressed) { if (pressed) {
kbd_execute_sequence(kbd, sequence, 1); kbd_execute_sequence(kbd, sequence, 1);
kbd_swap_layer(kbd, dl, layer, d); kbd_swap_layer(kbd, dl, layer, d);
} else if (last_pressed_keycode != code) { /* We only reach this from the remapped dl activate key. */ } else if (kbd->last_pressed_keycode != code) { /* We only reach this from the remapped dl activate key. */
kbd_deactivate_layer(kbd, layer); kbd_deactivate_layer(kbd, layer, 1);
} }
break; break;
@ -474,12 +520,13 @@ long kbd_process_key_event(struct keyboard *kbd,
if (pressed) { if (pressed) {
kbd_activate_layer(kbd, layer, 0); kbd_activate_layer(kbd, layer, 0);
} else if (last_pressed_keycode == code) { } else if (kbd->last_pressed_keycode == code) {
kbd_deactivate_layer(kbd, layer); kbd_deactivate_layer(kbd, layer, 1);
/* TODO: enforce this as a code in the config. */
kbd_execute_sequence(kbd, sequence, dl != kbd->layout); kbd_execute_sequence(kbd, sequence, dl != kbd->layout);
} else { } else {
kbd_deactivate_layer(kbd, layer); kbd_deactivate_layer(kbd, layer, 1);
} }
break; break;
@ -495,7 +542,7 @@ long kbd_process_key_event(struct keyboard *kbd,
pending_overload.is_active = 1; pending_overload.is_active = 1;
} else { } else {
kbd_deactivate_layer(kbd, layer); kbd_deactivate_layer(kbd, layer, 0);
} }
break; break;
@ -514,9 +561,6 @@ long kbd_process_key_event(struct keyboard *kbd,
break; break;
} }
if (pressed)
last_pressed_keycode = code;
if (!d.op || if (!d.op ||
(pressed && (pressed &&
(d.op == OP_KEYSEQ || (d.op == OP_KEYSEQ ||
@ -526,6 +570,11 @@ long kbd_process_key_event(struct keyboard *kbd,
kbd_clear_oneshots(kbd); kbd_clear_oneshots(kbd);
} }
if (pressed) {
kbd->last_pressed_keycode = code;
kbd->disarm_flag = disarm;
}
return timeout; return timeout;
} }

@ -38,6 +38,7 @@ struct keyboard {
size_t nr_active_keys; size_t nr_active_keys;
uint16_t last_pressed_keycode; uint16_t last_pressed_keycode;
int disarm_flag;
struct keyboard *next; struct keyboard *next;
}; };

@ -0,0 +1,9 @@
alt down
a down
a up
alt up
alt down
a down
a up
alt up

@ -0,0 +1,5 @@
alt down
alt up
alt down
alt up

@ -0,0 +1,15 @@
alt down
m down
m up
alt up
alt down
control down
alt up
control up
x down
x up
alt down
control down
alt up
control up

@ -9,14 +9,22 @@ rightmeta up
meta down meta down
control down
meta up meta up
control up
b down b down
b up b up
meta down meta down
control down
meta up meta up
control up
meta down meta down
control down
meta up meta up
control up
b down b down
b up b up
meta down meta down
control down
meta up meta up
control up

@ -10,7 +10,9 @@ a up
alt up alt up
alt down alt down
control down
alt up alt up
control up
shift down shift down
x down x down
x up x up

@ -12,7 +12,9 @@ a up
alt up alt up
alt down alt down
control down
alt up alt up
control up
shift down shift down
x down x down
x up x up

@ -12,11 +12,15 @@ x up
alt up alt up
alt down alt down
control down
alt up alt up
control up
tab down tab down
tab up tab up
alt down alt down
control down
alt up alt up
control up
shift down shift down
x down x down
x up x up

@ -9,13 +9,17 @@ meta up
meta down meta down
alt down alt down
control down
meta up meta up
alt up alt up
control up
tab down tab down
tab up tab up
meta down meta down
alt down alt down
control down
alt up alt up
control up
control down control down
a down a down
a up a up

@ -10,7 +10,9 @@ a up
alt up alt up
alt down alt down
control down
alt up alt up
control up
b down b down
b up b up
c down c down

@ -66,6 +66,7 @@ a = b
[myalt:A] [myalt:A]
m = x
s = swap(swapped1) s = swap(swapped1)
` = swap(tablayer) ` = swap(tablayer)
1 = swap(tablayer, tab) 1 = swap(tablayer, tab)

Loading…
Cancel
Save