Clear oneshot on click

This patch passively monitors mouse events and passes them
through to the active keyboard in order to facilitate
clearing oneshot modifiers on click.

A byproduct of this is an increase the number of spurious wakeups
(caused by mouse movement since we can't exclusively monitor click
events) , but this seems to have an minimal performance impact
in practice.
master
Raheman Vaiya 4 years ago
parent de7561cc2d
commit 9097368672
  1. 33
      src/device.c
  2. 1
      src/device.h
  3. 4
      src/keyboard.c
  4. 23
      src/keyd.c
  5. 16
      src/keys.h
  6. 2
      t/oneshot.t
  7. 2
      t/oneshot11.t
  8. 2
      t/oneshot14.t
  9. 2
      t/oneshot5.t
  10. 2
      t/oneshot6.t
  11. 2
      t/oneshot9.t
  12. 2
      t/oneshotn.t
  13. 2
      t/oneshotn3.t

@ -26,44 +26,56 @@
*
* We could make this cleaner by creating a single file descriptor via epoll
* but this would break FreeBSD compatibility without a dedicated kqueue
* implementation. A thread based approach was also considered,
* but inter-thread communication adds too much overhead (~100us).
* implementation. A thread based approach was also considered, but
* inter-thread communication adds too much overhead (~100us).
*
* Overview:
*
* A 'devmon' is a file descriptor which can be created with devmon_create()
* and subsequently monitored for new devices read with devmon_read_device().
*
* A 'device' always corresponds to a keyboard from which activity can be
* monitored with device->fd and events subsequently read using
* A 'device' always corresponds to a keyboard or mouse from which activity can
* be monitored with device->fd and events subsequently read using
* device_read_event().
*
* If the event returned by device_read_event() is of type DEV_REMOVED then the
* corresponding device should be considered invalid by the caller.
*/
static int is_keyboard(int fd)
/*
* returns 1 if keyboard, 2 if mouse, and 0 if neither.
*/
static int device_type(int fd)
{
uint32_t keymask;
uint32_t mask[BTN_LEFT/32+1] = {0};
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof keymask), &keymask) < 0) {
if (ioctl(fd, EVIOCGBIT(EV_KEY, (BTN_LEFT/32+1)*4), mask) < 0) {
perror("ioctl");
return 0;
}
/* The first 31 bits correspond to [KEY_ESC-KEY_S] */
return keymask == 0xFFFFFFFE;
if (mask[0] == 0xFFFFFFFE)
return 1;
else if (mask[BTN_LEFT/32] >> BTN_LEFT%32)
return 2;
else
return 0;
}
static int device_init(const char *path, struct device *dev)
{
int fd;
int type;
if ((fd = open(path, O_RDONLY | O_NONBLOCK, 0600)) < 0) {
fprintf(stderr, "failed to open %s\n", path);
return -1;
}
if (is_keyboard(fd)) {
type = device_type(fd);
if (type) {
struct input_id info;
if (ioctl(fd, EVIOCGNAME(sizeof(dev->name)), dev->name) == -1) {
@ -80,6 +92,7 @@ static int device_init(const char *path, struct device *dev)
dev->path[sizeof(dev->path)-1] = 0;
dev->fd = fd;
dev->is_keyboard = type == 1;
dev->vendor_id = info.vendor;
dev->product_id = info.product;
@ -254,6 +267,8 @@ struct device_event *device_read_event(struct device *dev)
ev.code = KEYD_MOUSE_2;
else if (ev.code == KEY_FN)
ev.code = KEYD_FN;
else if (ev.code >= BTN_DIGI && ev.code <= BTN_TOOL_QUADTAP)
;
else {
fprintf(stderr, "ERROR: unsupported evdev code: 0x%x\n", ev.code);
return NULL;

@ -21,6 +21,7 @@ struct device {
*/
int fd;
uint8_t is_keyboard;
uint16_t product_id;
uint16_t vendor_id;
char name[64];

@ -30,7 +30,7 @@ static long get_time()
static void kbd_send_key(struct keyboard *kbd, uint8_t code, uint8_t pressed)
{
if (code == KEYD_NOOP)
if (code == KEYD_NOOP || code == KEYD_EXTERNAL_MOUSE_BUTTON)
return;
if (pressed)
@ -377,10 +377,10 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code, struct descri
} else {
kbd_send_key(kbd, d->args[0].code, 0);
send_mods(kbd, descriptor_layer_mods, 1);
clear_oneshot = 1;
}
oneshot_latch = 0;
clear_oneshot = 1;
break;
case OP_LAYER:
layer = &layers[d->args[0].idx];

@ -55,6 +55,16 @@ static void daemon_add_cb(struct device *dev)
dev->data = NULL;
/*
* NOTE: Some mice can emit keys and consequently appear as keyboards.
* Conversely, some keyboards with a builtin trackpad can emit mouse
* events. There doesn't appear to be a reliable way to distinguish
* between these two, so we take a permissive approach and leave it up to
* the user to blacklist mice which emit key events.
*/
if (!dev->is_keyboard)
return;
printf("device added: %04x:%04x %s (%s)\n",
dev->vendor_id,
dev->product_id,
@ -106,7 +116,18 @@ static void panic_check(uint8_t code, uint8_t pressed)
static int daemon_event_cb(struct device *dev, uint8_t code, uint8_t pressed)
{
struct keyboard *kbd = dev ? dev->data : active_kbd;
struct keyboard *kbd = NULL;
if (!dev) {
/* timeout */
kbd = active_kbd;
} else if (dev->data) {
kbd = dev->data;
} else if (code >= KEYD_LEFT_MOUSE && code <= KEYD_MOUSE_2) {
code = KEYD_EXTERNAL_MOUSE_BUTTON;
kbd = active_kbd;
}
if (!kbd)
return 0;

@ -281,13 +281,15 @@ struct modifier_table_ent {
/* These deviate from uinput codes. */
#define KEYD_NOOP 195
#define KEYD_LEFT_MOUSE 249
#define KEYD_RIGHT_MOUSE 250
#define KEYD_MIDDLE_MOUSE 251
#define KEYD_MOUSE_1 252
#define KEYD_MOUSE_2 253
#define KEYD_FN 254
#define KEYD_EXTERNAL_MOUSE_BUTTON 196
#define KEYD_NOOP 195
#define KEYD_LEFT_MOUSE 249
#define KEYD_MIDDLE_MOUSE 250
#define KEYD_RIGHT_MOUSE 251
#define KEYD_MOUSE_1 252
#define KEYD_MOUSE_2 253
#define KEYD_FN 254
extern const struct modifier_table_ent modifier_table[MAX_MOD];
extern const struct keycode_table_ent keycode_table[256];

@ -5,5 +5,5 @@ b up
control down
b down
control up
b up
control up

@ -9,7 +9,7 @@ a up
control down
j down
control up
j up
control up
a down
a up

@ -11,5 +11,7 @@ shift down
shift up
a down
a up
shift down
shift up
b down
b up

@ -8,6 +8,6 @@ i up
shift down
control down
i down
i up
control up
shift up
i up

@ -8,6 +8,6 @@ i up
shift down
control down
i down
i up
control up
shift up
i up

@ -5,5 +5,5 @@ i up
control down
i down
control up
i up
control up

@ -7,3 +7,5 @@ control down
control up
b down
b up
control down
control up

@ -8,6 +8,6 @@ i up
control down
shift down
i down
i up
control up
shift up
i up

Loading…
Cancel
Save