Merge pull request #7 from borb/feature/fixes-and-keyb-mouse-autoconnect-and-grab

Fixes; keyboard and mouse autoconnect and keyboard grab (steal from the Pi).
This commit is contained in:
beeanyew 2021-04-15 05:17:03 +02:00 committed by GitHub
commit 9ef4a891f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 49 deletions

View File

@ -61,12 +61,12 @@ int get_config_item_type(char *cmd) {
unsigned int get_m68k_cpu_type(char *name) {
for (int i = 0; i < M68K_CPU_TYPES; i++) {
if (strcmp(name, cpu_types[i]) == 0) {
printf("Set CPU type to %s.\n", cpu_types[i]);
printf("[CFG] Set CPU type to %s.\n", cpu_types[i]);
return i + 1;
}
}
printf ("Invalid CPU type %s specified, defaulting to 68000.\n", name);
printf("[CFG] Invalid CPU type %s specified, defaulting to 68000.\n", name);
return M68K_CPU_TYPE_68000;
}
@ -119,7 +119,7 @@ unsigned int get_int(char *str) {
case 'M': ret_int = ret_int * SIZE_MEGA; break;
case 'G': ret_int = ret_int * SIZE_GIGA; break;
default:
printf("Unknown character %c in hex value.\n", str[i]);
printf("[CFG] Unknown character %c in hex value.\n", str[i]);
break;
}
}
@ -179,7 +179,7 @@ void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int ad
index++;
}
if (index == MAX_NUM_MAPPED_ITEMS) {
printf("Unable to map item, only %d items can be mapped with current binary.\n", MAX_NUM_MAPPED_ITEMS);
printf("[CFG] Unable to map item, only %d items can be mapped with current binary.\n", MAX_NUM_MAPPED_ITEMS);
return;
}
@ -195,10 +195,10 @@ void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int ad
switch(type) {
case MAPTYPE_RAM:
printf("Allocating %d bytes for RAM mapping (%d MB)...\n", size, size / 1024 / 1024);
printf("[CFG] Allocating %d bytes for RAM mapping (%d MB)...\n", size, size / 1024 / 1024);
cfg->map_data[index] = (unsigned char *)malloc(size);
if (!cfg->map_data[index]) {
printf("ERROR: Unable to allocate memory for mapped RAM!\n");
printf("[CFG] ERROR: Unable to allocate memory for mapped RAM!\n");
goto mapping_failed;
}
memset(cfg->map_data[index], 0x00, size);
@ -206,7 +206,7 @@ void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int ad
case MAPTYPE_ROM:
in = fopen(filename, "rb");
if (!in) {
printf("Failed to open file %s for ROM mapping.\n", filename);
printf("[CFG] Failed to open file %s for ROM mapping.\n", filename);
goto mapping_failed;
}
fseek(in, 0, SEEK_END);
@ -219,7 +219,7 @@ void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int ad
cfg->map_data[index] = (unsigned char *)calloc(1, cfg->map_size[index]);
cfg->rom_size[index] = (cfg->map_size[index] <= file_size) ? cfg->map_size[index] : file_size;
if (!cfg->map_data[index]) {
printf("ERROR: Unable to allocate memory for mapped ROM!\n");
printf("[CFG] ERROR: Unable to allocate memory for mapped ROM!\n");
goto mapping_failed;
}
memset(cfg->map_data[index], 0x00, cfg->map_size[index]);
@ -231,7 +231,7 @@ void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int ad
break;
}
printf("[MAP %d] Added %s mapping for range %.8lX-%.8lX ID: %s\n", index, map_type_names[type], cfg->map_offset[index], cfg->map_high[index] - 1, cfg->map_id[index] ? cfg->map_id[index] : "None");
printf("[CFG] [MAP %d] Added %s mapping for range %.8lX-%.8lX ID: %s\n", index, map_type_names[type], cfg->map_offset[index], cfg->map_high[index] - 1, cfg->map_id[index] ? cfg->map_id[index] : "None");
if (cfg->map_size[index] == cfg->rom_size[index])
m68k_add_rom_range(cfg->map_offset[index], cfg->map_high[index], cfg->map_data[index]);
@ -246,7 +246,7 @@ void add_mapping(struct emulator_config *cfg, unsigned int type, unsigned int ad
struct emulator_config *load_config_file(char *filename) {
FILE *in = fopen(filename, "rb");
if (in == NULL) {
printf("Failed to open config file %s for reading.\n", filename);
printf("[CFG] Failed to open config file %s for reading.\n", filename);
return NULL;
}
@ -257,12 +257,12 @@ struct emulator_config *load_config_file(char *filename) {
parse_line = (char *)calloc(1, 512);
if (!parse_line) {
printf("Failed to allocate memory for config file line buffer.\n");
printf("[CFG] Failed to allocate memory for config file line buffer.\n");
return NULL;
}
cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
if (!cfg) {
printf("Failed to allocate memory for temporary emulator config.\n");
printf("[CFG] Failed to allocate memory for temporary emulator config.\n");
goto load_failed;
}
@ -332,7 +332,7 @@ struct emulator_config *load_config_file(char *filename) {
mirraddr = get_int(cur_cmd);
break;
default:
printf("Unknown/unhandled map argument %s on line %d.\n", cur_cmd, cur_line);
printf("[CFG] Unknown/unhandled map argument %s on line %d.\n", cur_cmd, cur_line);
break;
}
}
@ -342,7 +342,7 @@ struct emulator_config *load_config_file(char *filename) {
}
case CONFITEM_LOOPCYCLES:
cfg->loop_cycles = get_int(parse_line + str_pos);
printf("Set CPU loop cycles to %d.\n", cfg->loop_cycles);
printf("[CFG] Set CPU loop cycles to %d.\n", cfg->loop_cycles);
break;
case CONFITEM_MOUSE:
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
@ -350,27 +350,37 @@ struct emulator_config *load_config_file(char *filename) {
strcpy(cfg->mouse_file, cur_cmd);
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
cfg->mouse_toggle_key = cur_cmd[0];
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
cfg->mouse_autoconnect = (strcmp(cur_cmd, "autoconnect") == 0) ? 1 : 0;
cfg->mouse_enabled = 1;
printf("Enabled mouse event forwarding from file %s, toggle key %c.\n", cfg->mouse_file, cfg->mouse_toggle_key);
printf("[CFG] Enabled mouse event forwarding from file %s, toggle key %c.\n", cfg->mouse_file, cfg->mouse_toggle_key);
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;
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
cfg->keyboard_autoconnect = (strcmp(cur_cmd, "autoconnect") == 0) ? 1 : 0;
printf("[CFG] Enabled keyboard event forwarding, toggle key %c", cfg->keyboard_toggle_key);
if (cfg->keyboard_grab)
printf(", locking from host when connected");
if (cfg->keyboard_autoconnect)
printf(", connected to guest at startup");
printf(".\n");
break;
case CONFITEM_KBFILE:
get_next_string(parse_line, cur_cmd, &str_pos, ' ');
cfg->keyboard_file = (char *)calloc(1, strlen(cur_cmd) + 1);
strcpy(cfg->keyboard_file, cur_cmd);
printf("Set keyboard event source file to %s.\n", cfg->keyboard_file);
printf("[CFG] Set keyboard event source file to %s.\n", cfg->keyboard_file);
break;
case CONFITEM_PLATFORM: {
char platform_name[128], platform_sub[128];
memset(platform_name, 0x00, 128);
memset(platform_sub, 0x00, 128);
get_next_string(parse_line, platform_name, &str_pos, ' ');
printf("Setting platform to %s", platform_name);
printf("[CFG] Setting platform to %s", platform_name);
get_next_string(parse_line, platform_sub, &str_pos, ' ');
if (strlen(platform_sub))
printf(" (sub: %s)", platform_sub);
@ -380,7 +390,7 @@ struct emulator_config *load_config_file(char *filename) {
}
case CONFITEM_SETVAR: {
if (!cfg->platform) {
printf("Warning: esetvar used in config file with no platform specified.\n");
printf("[CFG] Warning: setvar used in config file with no platform specified.\n");
break;
}
@ -395,11 +405,11 @@ struct emulator_config *load_config_file(char *filename) {
}
case CONFITEM_NONE:
default:
printf("Unknown config item %s on line %d.\n", cur_cmd, cur_line);
printf("[CFG] Unknown config item %s on line %d.\n", cur_cmd, cur_line);
break;
}
skip_line:;
skip_line:
cur_line++;
}
goto load_successful;

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, mouse_autoconnect, keyboard_enabled, keyboard_grab, keyboard_autoconnect;
unsigned int loop_cycles;
unsigned int mapped_low, mapped_high;

View File

@ -42,12 +42,18 @@ platform amiga
# Uncomment this line to enable the (currently non-working) Pi-Net interface.
#setvar pi-net
# Forward mouse events to host system, defaults to off unless toggle key is pressed on the Pi.
# 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
# Syntax: keyboard [grab key] [grab|nograb] [autoconnect|noautoconnect]
# "grab" steals the keyboard from the Pi so Amiga/etc. input is not sent to the Pi
# (also helps prevent sending any ctrl-alt-del to the Amiga from resetting the Pi)
#
# "autoconnect" connects the keyboard to the Amiga/etc. on startup
keyboard k nograb noautoconnect
# 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.
#kbfile /dev/input/event1
# Forward mouse events to host system, defaults to off unless toggle key is pressed on the Pi.
# Syntax is mouse [device] [toggle key] [autoconnect|noautoconnect]
# (see "keyboard" above for autoconnect description)
mouse /dev/input/mice m noautoconnect

View File

@ -59,9 +59,10 @@ extern volatile uint16_t srdata;
extern uint8_t realtime_graphics_debug;
uint8_t realtime_disassembly, int2_enabled = 0;
uint32_t do_disasm = 0, old_level;
char c = 0, c_code = 0, c_type = 0; // @todo temporary main/cpu_task scope workaround until input moved to a thread
uint32_t last_irq = 8, last_last_irq = 8;
uint8_t end_signal = 0;
char disasm_buf[4096];
#define KICKBASE 0xF80000
@ -239,7 +240,6 @@ cpu_loop:
// printf("CPU emulation reset.\n");
}
if (mouse_hook_enabled && (mouse_extra != 0x00)) {
// mouse wheel events have occurred; unlike l/m/r buttons, these are queued as keypresses, so add to end of buffer
switch (mouse_extra) {
@ -256,46 +256,66 @@ cpu_loop:
// dampen the scroll wheel until next while loop iteration
mouse_extra = 0x00;
}
if (end_signal)
goto stop_cpu_emulation;
goto cpu_loop;
//stop_cpu_emulation:
stop_cpu_emulation:
printf("[CPU] End of CPU thread\n");
return (void *)NULL;
}
void *keyboard_task() {
struct pollfd kbdfd[1];
int kpoll;
struct pollfd kbdpoll[1];
int kpollrc;
char c = 0, c_code = 0, c_type = 0;
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);
@ -328,11 +348,11 @@ key_loop:
//m68k_pulse_reset();
printf("CPU emulation reset.\n");
}
// @todo work out how to signal the main process that we want to quit
// if (c == 'q') {
// printf("Quitting and exiting emulator.\n");
// goto stop_cpu_emulation;
// }
if (c == 'q') {
printf("Quitting and exiting emulator.\n");
end_signal = 1;
goto key_end;
}
if (c == 'd') {
realtime_disassembly ^= 1;
do_disasm = 1;
@ -360,6 +380,10 @@ key_loop:
key_end:
printf("[KBD] Keyboard thread ending\n");
if (cfg->keyboard_grab) {
printf(ungrab_message);
release_device(keyboard_fd);
}
return (void*)NULL;
}
@ -496,6 +520,12 @@ int main(int argc, char *argv[]) {
printf("Failed to open keyboard event source.\n");
}
if (cfg->mouse_autoconnect)
mouse_hook_enabled = 1;
if (cfg->keyboard_autoconnect)
kb_hook_enabled = 1;
InitGayle();
signal(SIGINT, sigint_handler);

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);