support stealing the keyboard from the input layer

this change uses an ioctl to disconnect the keyboard event device from
the input layer, meaning input no longer affects the pi and will
entirely be consumed by the pistorm emulator process.
This commit is contained in:
just nine
2021-04-14 22:29:41 +01:00
parent 975ce97643
commit 5fa4ab5cf4
6 changed files with 51 additions and 18 deletions

View File

@@ -355,9 +355,11 @@ struct emulator_config *load_config_file(char *filename) {
break;
case CONFITEM_KEYBOARD:
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
cfg->keyboard_file = (char *)calloc(1, strlen(cur_cmd) + 1);
cfg->keyboard_toggle_key = cur_cmd[0];
printf("Enabled keyboard event forwarding, toggle key %c.\n", cfg->keyboard_toggle_key);
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
cfg->keyboard_grab = (strcmp(cur_cmd, "grab") == 0) ? 1 : 0;
printf("Enabled keyboard event forwarding, toggle key %c, %slocking from host.\n",
cfg->keyboard_toggle_key, cfg->keyboard_grab ? "" : "not ");
break;
case CONFITEM_KBFILE:
get_next_string(parse_line, cur_cmd, &str_pos, ' ');

View File

@@ -68,7 +68,7 @@ struct emulator_config {
char *mouse_file, *keyboard_file;
char mouse_toggle_key, keyboard_toggle_key;
unsigned char mouse_enabled, keyboard_enabled;
unsigned char mouse_enabled, keyboard_enabled, keyboard_grab;
unsigned int loop_cycles;
unsigned int mapped_low, mapped_high;

View File

@@ -46,7 +46,9 @@ platform amiga
# Syntax is mouse [device] [toggle key]
#mouse /dev/input/mouse0 m
# Forward keyboard events to host system, defaults to off unless toggle key is pressed, toggled off using F12.
#keyboard k
# Add the keyword "grab" to steal the keyboard from the Pi, so Amiga input does not appear on the console or in X11.
# (also helps prevent sending any ctrl-alt-del to the Amiga from resetting the Pi)
keyboard k grab
# Select a specific filename for the keyboard event source.
# This is typically /dev/input/event1 or event0, but it may be event3 with for instance a wireless keyboard.
# Use ls /dev/input/event* to check which event files are available and try until you find the one that works.

View File

@@ -263,39 +263,53 @@ cpu_loop:
}
void *keyboard_task() {
struct pollfd kbdfd[1];
int kpoll;
struct pollfd kbdpoll[1];
int kpollrc;
char grab_message[] = "[KBD] Grabbing keyboard from input layer\n",
ungrab_message[] = "[KBD] Ungrabbing keyboard\n";
printf("[KBD] Keyboard thread started\n");
kbdfd[0].fd = keyboard_fd;
kbdfd[0].events = POLLIN;
// because we permit the keyboard to be grabbed on startup, quickly check if we need to grab it
if (kb_hook_enabled && cfg->keyboard_grab) {
printf(grab_message);
grab_device(keyboard_fd);
}
kbdpoll[0].fd = keyboard_fd;
kbdpoll[0].events = POLLIN;
key_loop:
kpoll = poll(kbdfd, 1, KEY_POLL_INTERVAL_MSEC);
if ((kpoll > 0) && (kbdfd[0].revents & POLLHUP)) {
kpollrc = poll(kbdpoll, 1, KEY_POLL_INTERVAL_MSEC);
if ((kpollrc > 0) && (kbdpoll[0].revents & POLLHUP)) {
// in the event that a keyboard is unplugged, keyboard_task will whiz up to 100% utilisation
// this is undesired, so if the keyboard HUPs, end the thread without ending the emulation
printf("[KBD] Keyboard node returned HUP (unplugged?)\n");
goto key_end;
}
// if kpoll > 0 then it contains number of events to pull, also check if POLLIN is set in revents
if ((kpoll <= 0) || !(kbdfd[0].revents & POLLIN)) {
// if kpollrc > 0 then it contains number of events to pull, also check if POLLIN is set in revents
if ((kpollrc <= 0) || !(kbdpoll[0].revents & POLLIN)) {
goto key_loop;
}
while (get_key_char(&c, &c_code, &c_type)) {
if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
kb_hook_enabled = 1;
printf("Keyboard hook enabled.\n");
}
else if (kb_hook_enabled) {
printf("[KBD] Keyboard hook enabled.\n");
if (cfg->keyboard_grab) {
grab_device(keyboard_fd);
printf(grab_message);
}
} else if (kb_hook_enabled) {
if (c == 0x1B && c_type) {
kb_hook_enabled = 0;
printf("Keyboard hook disabled.\n");
}
else {
printf("[KBD] Keyboard hook disabled.\n");
if (cfg->keyboard_grab) {
release_device(keyboard_fd);
printf(ungrab_message);
}
} else {
if (queue_keypress(c_code, c_type, cfg->platform->id) && int2_enabled && last_irq != 2) {
//last_irq = 0;
//M68K_SET_IRQ(2);

View File

@@ -1,4 +1,5 @@
#include <linux/input.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
@@ -211,3 +212,15 @@ void pop_queued_key(uint8_t *c, uint8_t *t) {
queued_keypresses--;
return;
}
int grab_device(int fd) {
int rc = 0;
rc = ioctl(fd, EVIOCGRAB, (void *)1);
return rc;
}
int release_device(int fd) {
int rc = 0;
rc = ioctl(fd, EVIOCGRAB, (void *)0);
return rc;
}

View File

@@ -11,3 +11,5 @@ int get_key_char(char *c, char *code, char *event_type);
int queue_keypress(uint8_t keycode, uint8_t event_type, uint8_t platform);
int get_num_kb_queued();
void pop_queued_key(uint8_t *c, uint8_t *t);
int grab_device(int fd);
int release_device(int fd);