From 96f7b7aa14b3af9cf26b36d21c6ec0c2c0d19453 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 3 Jan 2023 15:42:57 +0600 Subject: [PATCH] Add Wacom SD-510C tablet emulation --- src/86box.c | 4 +- src/config.c | 8 + src/device.c | 2 +- src/device/CMakeLists.txt | 3 +- src/device/mouse.c | 13 +- src/device/mouse_bus.c | 2 +- src/device/mouse_ps2.c | 2 +- src/device/mouse_serial.c | 2 +- src/device/mouse_wacom_tablet.c | 392 ++++++++++++++++++++++++++++++++ src/include/86box/device.h | 2 +- src/include/86box/mouse.h | 6 + src/include/86box/ui.h | 1 + src/qt/qt_mainwindow.cpp | 31 ++- src/qt/qt_mainwindow.hpp | 7 + src/qt/qt_mainwindow.ui | 24 ++ src/qt/qt_rendererstack.cpp | 52 ++++- src/qt/qt_rendererstack.hpp | 7 + src/qt/qt_ui.cpp | 6 + src/unix/unix.c | 5 + src/win/Makefile.mingw | 1 + src/win/win_ui.c | 6 + 21 files changed, 558 insertions(+), 18 deletions(-) create mode 100644 src/device/mouse_wacom_tablet.c diff --git a/src/86box.c b/src/86box.c index 147233b21..c98b26185 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1118,6 +1118,8 @@ pc_reset_hard_init(void) #endif update_mouse_msg(); + + ui_hard_reset_completed(); } void @@ -1265,7 +1267,7 @@ pc_run(void) } if (title_update) { - mouse_msg_idx = (mouse_type == MOUSE_TYPE_NONE) ? 2 : !!mouse_capture; + mouse_msg_idx = (mouse_type == MOUSE_TYPE_NONE || mouse_mode >= 1) ? 2 : !!mouse_capture; swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps); #ifdef __APPLE__ /* Needed due to modifying the UI on the non-main thread is a big no-no. */ diff --git a/src/config.c b/src/config.c index 8e2b5c292..49e6afca9 100644 --- a/src/config.c +++ b/src/config.c @@ -650,6 +650,8 @@ load_input_devices(void) } } } + + tablet_tool_type = !!ini_section_get_int(cat, "tablet_tool_type", 1); } /* Load "Sound" section. */ @@ -2287,6 +2289,12 @@ save_input_devices(void) } } + if (tablet_tool_type != 1) { + ini_section_set_int(cat, "tablet_tool_type", tablet_tool_type); + } else { + ini_section_delete_var(cat, "tablet_tool_type"); + } + ini_delete_section_if_empty(config, cat); } diff --git a/src/device.c b/src/device.c index a13825307..95c62624c 100644 --- a/src/device.c +++ b/src/device.c @@ -412,7 +412,7 @@ device_poll(const device_t *d, int x, int y, int z, int b) if (devices[c] != NULL) { if (devices[c] == d) { if (devices[c]->poll) - return (devices[c]->poll(x, y, z, b, device_priv[c])); + return (devices[c]->poll(x, y, z, b, 0, 0, device_priv[c])); } } } diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 7fd0b20d0..27e854387 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -17,7 +17,8 @@ add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c h hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c - mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) + mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c + mouse_wacom_tablet.c) if(ISAMEM_RAMPAGE) target_compile_definitions(dev PRIVATE USE_ISAMEM_RAMPAGE) diff --git a/src/device/mouse.c b/src/device/mouse.c index 422161a83..23046bdbc 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -37,7 +37,14 @@ int mouse_type = 0; int mouse_x, mouse_y, mouse_z, - mouse_buttons; + mouse_buttons, + mouse_mode, + mouse_tablet_in_proximity = 0, + tablet_tool_type = 0; /* 0 = Puck/Cursor, 1 = Pen */ + +double mouse_x_abs, + mouse_y_abs; + static const device_t mouse_none_device = { .name = "None", @@ -80,6 +87,7 @@ static mouse_t mouse_devices[] = { { &mouse_msserial_device }, { &mouse_ltserial_device }, { &mouse_ps2_device }, + { &mouse_wacom_device }, { NULL } // clang-format on }; @@ -146,6 +154,7 @@ mouse_reset(void) /* Clear local data. */ mouse_x = mouse_y = mouse_z = 0; mouse_buttons = 0x00; + mouse_mode = 0; /* If no mouse configured, we're done. */ if (mouse_type == 0) @@ -174,7 +183,7 @@ mouse_process(void) if ((mouse_dev_poll != NULL) || (mouse_curr->poll != NULL)) { if (mouse_curr->poll != NULL) - mouse_curr->poll(mouse_x, mouse_y, mouse_z, mouse_buttons, mouse_priv); + mouse_curr->poll(mouse_x, mouse_y, mouse_z, mouse_buttons, mouse_x_abs, mouse_y_abs, mouse_priv); else mouse_dev_poll(mouse_x, mouse_y, mouse_z, mouse_buttons, mouse_priv); diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index 802ae6d45..c0c57b7d0 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -449,7 +449,7 @@ ms_write(uint16_t port, uint8_t val, void *priv) /* The emulator calls us with an update on the host mouse device. */ static int -bm_poll(int x, int y, int z, int b, void *priv) +bm_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv) { mouse_t *dev = (mouse_t *) priv; int xor ; diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index e7670b2fc..870d9ae5f 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -261,7 +261,7 @@ mouse_reset: } static int -ps2_poll(int x, int y, int z, int b, void *priv) +ps2_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv) { mouse_t *dev = (mouse_t *) priv; diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 2edc342e9..f5e532101 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -511,7 +511,7 @@ sermouse_command_timer(void *priv) } static int -sermouse_poll(int x, int y, int z, int b, void *priv) +sermouse_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv) { mouse_t *dev = (mouse_t *) priv; diff --git a/src/device/mouse_wacom_tablet.c b/src/device/mouse_wacom_tablet.c new file mode 100644 index 000000000..0aaa4cf53 --- /dev/null +++ b/src/device/mouse_wacom_tablet.c @@ -0,0 +1,392 @@ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/mouse.h> +#include <86box/serial.h> +#include <86box/plat.h> + +#define FLAG_3BTN 0x20 /* enable 3-button mode */ + +enum wacom_modes +{ + WACOM_MODE_SUPPRESSED = 0, + WACOM_MODE_POINT = 1, + WACOM_MODE_STREAM = 2, + WACOM_MODE_SWITCH = 3, +}; + +enum { + REPORT_PHASE_PREPARE, + REPORT_PHASE_TRANSMIT +}; + +typedef struct { + const char *name; /* name of this device */ + int8_t type, /* type of this device */ + port; + uint8_t flags, but, /* device flags */ + status, format, + data_len, data[64], + data_rec[0x200]; + int abs_x, abs_y, + rel_x, rel_y, + oldb, lastb, b; + + int data_pos, data_rec_pos, mode, transmission_ongoing, transmission_format, interval; + int increment, suppressed_increment; + int transmission_stopped; + int reset; + int transmit_id, transmit_id_pending; + int pressure_mode; + int suppressed, measurement, always_report; + + int last_abs_x, last_abs_y; /* Suppressed/Increment Mode. */ + + double transmit_period, report_period; + double old_tsc; + pc_timer_t command_timer, report_timer; + + serial_t *serial; +} mouse_wacom_t; + +static double +wacom_transmit_period(mouse_wacom_t *dev, int bps, int rps) +{ + double dbps = (double) bps; + double temp = 0.0; + int word_len = 10; + + if (rps == -1) + temp = (double) word_len; + else { + temp = (double) rps; + temp = (9600.0 - (temp * 33.0)); + temp /= rps; + } + temp = (1000000.0 / dbps) * temp; + + return temp; +} + +static void +wacom_reset(mouse_wacom_t* wacom) +{ + wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1); + wacom->mode = WACOM_MODE_POINT; + wacom->data_pos = 0; + wacom->transmission_ongoing = 0; + wacom->mode = 0; + wacom->transmission_stopped = 0; + wacom->interval = 0; + wacom->transmit_id = 0; + wacom->format = 0; /* ASCII */ + wacom->measurement = 1; + + mouse_mode = 1; +} + +static void +wacom_callback(struct serial_s *serial, void *priv) +{ + mouse_wacom_t* wacom = (mouse_wacom_t*)priv; + + wacom->transmit_period = wacom_transmit_period(wacom, 9600, -1); + timer_stop(&wacom->report_timer); + timer_on_auto(&wacom->report_timer, wacom->transmit_period); +} + +static void +wacom_write(struct serial_s *serial, void *priv, uint8_t data) +{ + mouse_wacom_t* wacom = (mouse_wacom_t*)priv; + static int special_command = 0; + + if (data == '~') { + special_command = 1; + return; + } + if (special_command) { + switch (data) { + case '#': + { + if (!wacom->transmission_ongoing) wacom->transmit_id++; + break; + } + } + special_command = 0; + return; + } + if (data == '$') { + wacom_reset(wacom); + } + if (data == 0x13) { + wacom->transmission_stopped = 1; + pclog("WACOM: transmission stopped\n"); + } + if (data == 0x11) { + wacom->transmission_stopped = 0; + pclog("WACOM: transmission started\n"); + } + wacom->data_rec[wacom->data_rec_pos++] = data; + if (data == '\r') { + wacom->data_rec[wacom->data_rec_pos] = 0; + wacom->data_rec_pos = 0; + + if (!memcmp(wacom->data_rec, "AS", 2)) { + wacom->format = (wacom->data_rec[2] == '1'); + wacom->transmission_ongoing = 0; + } else if (!memcmp(wacom->data_rec, "SR", 2)) { + wacom->mode = WACOM_MODE_STREAM; + wacom->suppressed_increment = 0; + } else if (!memcmp(wacom->data_rec, "IN", 2)) { + sscanf((const char*)wacom->data_rec, "IN%d", &wacom->increment); + } else if (!memcmp(wacom->data_rec, "RE", 2)) { + wacom_reset(wacom); + } else if (!memcmp(wacom->data_rec, "IT", 2)) { + sscanf((const char*)wacom->data_rec, "IT%d", &wacom->interval); + } else if (!memcmp(wacom->data_rec, "DE", 2)) { + sscanf((const char*)wacom->data_rec, "DE%d", &mouse_mode); + mouse_mode = !mouse_mode; + plat_mouse_capture(0); + } else if (!memcmp(wacom->data_rec, "SU", 2)) { + sscanf((const char*)wacom->data_rec, "SU%d", &wacom->suppressed_increment); + } else if (!memcmp(wacom->data_rec, "PH", 2)) { + sscanf((const char*)wacom->data_rec, "PH%d", &wacom->pressure_mode); + } else if (!memcmp(wacom->data_rec, "IC", 2)) { + sscanf((const char*)wacom->data_rec, "IC%d", &wacom->measurement); + } else if (!memcmp(wacom->data_rec, "AL", 2)) { + sscanf((const char*)wacom->data_rec, "AL%d", &wacom->always_report); + } else { + pclog("Unknown command: %s\n", wacom->data_rec); + } + } +} + +static int +wacom_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv) +{ + mouse_wacom_t* wacom = (mouse_wacom_t*)priv; + if (abs_x > 1.0l) abs_x = 1.0l; + if (abs_y > 1.0l) abs_y = 1.0l; + if (abs_x < 0.l) abs_x = 0.l; + if (abs_y < 0.l) abs_y = 0.l; + wacom->abs_x = abs_x * (wacom->measurement ? 4566. : 5800.); + wacom->abs_y = abs_y * (wacom->measurement ? 2972. : 3774.); + wacom->rel_x = x; + wacom->rel_y = y; + if (wacom->b != b) wacom->oldb = wacom->b; + wacom->b = b; + return (0); +} + +static int +wacom_switch_off_to_on(int b, int oldb) +{ + if (!(oldb & 0x1) && (b & 1)) return 1; + if (!(oldb & 0x2) && (b & 2)) return 1; + if (!(oldb & 0x4) && (b & 4)) return 1; + + return 0; +} + +static uint8_t +wacom_get_switch(int b) +{ + if (b & 0x4) return 0x23; + if (b & 0x2) return 0x22; + if (b & 0x1) return 0x21; + + return 0x00; +} + +extern double cpuclock; +static void +sermouse_report_timer(void *priv) +{ + mouse_wacom_t* wacom = (mouse_wacom_t*)priv; + uint32_t transmitted = 0; + double milisecond_diff = ((double)(tsc - wacom->old_tsc)) / cpuclock * 1000.0; + int x = (mouse_mode == 0 ? wacom->rel_x : wacom->abs_x), y = (mouse_mode == 0 ? wacom->rel_y : wacom->abs_y); + + timer_on_auto(&wacom->report_timer, wacom->transmit_id ? (wacom->transmit_period / 8.0) : wacom->transmit_period); + if (wacom->transmit_id && !wacom->transmission_ongoing) + goto transmit_prepare; + if (wacom->transmission_ongoing) + goto transmit; + else { + int x_diff = (mouse_mode == 0 ? wacom->rel_x : (wacom->last_abs_x - wacom->abs_x)); + int y_diff = (mouse_mode == 0 ? wacom->rel_y : (wacom->last_abs_y - wacom->abs_y)); + + if (wacom->transmission_stopped || (!mouse_tablet_in_proximity && !wacom->always_report)) return; + if (milisecond_diff >= (wacom->interval * 5)) { + transmitted = 1; + wacom->old_tsc = tsc; + } else transmitted = 0; + if (!transmitted) + return; + if (wacom->increment && !(x_diff >= wacom->increment || y_diff >= wacom->increment || wacom_switch_off_to_on(wacom->b, wacom->oldb))) + return; + + if (wacom->suppressed_increment && !(x_diff >= wacom->suppressed_increment || y_diff >= wacom->suppressed_increment || (wacom->b != wacom->oldb))) + return; + + switch (wacom->mode) { + case WACOM_MODE_STREAM: + default: + break; + + case WACOM_MODE_POINT: + { + if (!(wacom_switch_off_to_on(wacom->b, wacom->oldb))) + return; + break; + } + + case WACOM_MODE_SWITCH: + { + if (!wacom->b) + return; + + break; + } + } + } + +transmit_prepare: + if (wacom->transmit_id) { + wacom->transmission_format = 0; + wacom->transmission_ongoing = 1; + wacom->data_pos = 0; + memset(wacom->data, 0, sizeof(wacom->data)); + strcat((char*)wacom->data, "~#SD51C V3.2.1.01\r"); + goto transmit; + } + wacom->transmission_ongoing = 1; + wacom->transmission_format = wacom->format; + wacom->data_pos = 0; + wacom->last_abs_x = wacom->abs_x; + wacom->last_abs_y = wacom->abs_y; + wacom->oldb = wacom->b; + if (wacom->format == 1) { + memset(wacom->data, 0, 7); + wacom->data[0] = 0xC0; + wacom->data[6] = wacom->pressure_mode ? ((wacom->b & 0x1) ? (uint8_t)31 : (uint8_t)-31) : wacom_get_switch(wacom->b); + + wacom->data[5] = (y & 0x7F); + wacom->data[4] = ((y & 0x3F80) >> 7) & 0x7F; + wacom->data[3] = (((y & 0xC000) >> 14) & 3); + + wacom->data[2] = (x & 0x7F); + wacom->data[1] = ((x & 0x3F80) >> 7) & 0x7F; + wacom->data[0] |= (((x & 0xC000) >> 14) & 3); + + if (mouse_mode == 0) { + wacom->data[0] |= (!!(x < 0)) << 2; + wacom->data[3] |= (!!(y < 0)) << 2; + } + if (wacom->pressure_mode) { + wacom->data[0] |= 0x10; + wacom->data[6] &= 0x7F; + } + if (tablet_tool_type == 1) { + wacom->data[0] |= 0x20; + } + + if (!mouse_tablet_in_proximity) { + wacom->data[0] &= ~0x40; + } + } else { + wacom->data[0] = 0; + snprintf((char*)wacom->data, sizeof(wacom->data), "*,%05d,%05d,%d\r\n", wacom->abs_x, wacom->abs_y, wacom->pressure_mode ? ((wacom->b & 0x1) ? (uint8_t)-31 : (uint8_t)15) : ((wacom->b & 0x1) ? 0x21 : 0x00)); + } +transmit: + serial_write_fifo(wacom->serial, wacom->data[wacom->data_pos++]); + if ((wacom->transmission_format == 0 && wacom->data[wacom->data_pos] == 0) + || (wacom->transmission_format == 1 && wacom->data_pos == 7)) { + wacom->transmission_ongoing = 0; + wacom->transmit_id = 0; + wacom->data_pos = 0; + wacom->old_tsc = tsc; + } + return; +} + +static void * +wacom_init(const device_t *info) +{ + mouse_wacom_t *dev; + + dev = (mouse_wacom_t *) calloc(1, sizeof(mouse_wacom_t)); + dev->name = info->name; + dev->but = 3; + + dev->port = device_get_config_int("port"); + + dev->serial = serial_attach(dev->port, wacom_callback, wacom_write, dev); + timer_add(&dev->report_timer, sermouse_report_timer, dev, 0); + mouse_set_buttons(dev->but); + + wacom_reset(dev); + + return dev; +} + +static void +wacom_speed_changed(void *priv) +{ + mouse_wacom_t *dev = (mouse_wacom_t *) priv; + + wacom_callback(dev->serial, dev); +} + +static void +wacom_close(void *priv) +{ + mouse_wacom_t *dev = (mouse_wacom_t *) priv; + + /* Detach serial port from the mouse. */ + if (dev && dev->serial && dev->serial->sd) + memset(dev->serial->sd, 0, sizeof(serial_device_t)); + + free(dev); +} + +static const device_config_t wacom_config[] = { + // clang-format off + { + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "COM1", .value = 0 }, + { .description = "COM2", .value = 1 }, + { .description = "COM3", .value = 2 }, + { .description = "COM4", .value = 3 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t mouse_wacom_device = { + .name = "Wacom SD-510C", + .internal_name = "wacom_serial", + .flags = DEVICE_COM, + .local = MOUSE_TYPE_WACOM, + .init = wacom_init, + .close = wacom_close, + .reset = NULL, + { .poll = wacom_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wacom_config +}; diff --git a/src/include/86box/device.h b/src/include/86box/device.h index ca4e6bdf2..18e2a4455 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -122,7 +122,7 @@ typedef struct _device_ { void (*reset)(void *priv); union { int (*available)(void); - int (*poll)(int x, int y, int z, int b, void *priv); + int (*poll)(int x, int y, int z, int b, double abs_x, double abs_y, void *priv); void (*register_pci_slot)(int device, int type, int inta, int intb, int intc, int intd, void *priv); }; void (*speed_changed)(void *priv); diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index 434360589..5e56a365e 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -34,6 +34,7 @@ #define MOUSE_TYPE_LOGITECH 9 /* Logitech 2-button Serial Mouse */ #define MOUSE_TYPE_LT3BUTTON 10 /* Logitech 3-button Serial Mouse */ #define MOUSE_TYPE_PS2 11 /* PS/2 series Bus Mouse */ +#define MOUSE_TYPE_WACOM 12 /* WACOM tablet */ #define MOUSE_TYPE_ONBOARD 0x80 /* Mouse is an on-board version of one of the above. */ @@ -43,7 +44,11 @@ extern "C" { extern int mouse_type; extern int mouse_x, mouse_y, mouse_z; +extern int mouse_mode; /* 1 = Absolute, 0 = Relative */ +extern int mouse_tablet_in_proximity; +extern double mouse_x_abs, mouse_y_abs; extern int mouse_buttons; +extern int tablet_tool_type; #ifdef EMU_DEVICE_H extern const device_t *mouse_get_device(int mouse); @@ -59,6 +64,7 @@ extern const device_t mouse_mssystems_device; extern const device_t mouse_msserial_device; extern const device_t mouse_ltserial_device; extern const device_t mouse_ps2_device; +extern const device_t mouse_wacom_device; #endif extern void mouse_init(void); diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index 5eb15a08d..70971ce19 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -61,6 +61,7 @@ extern void ui_check_menu_item(int id, int checked); extern wchar_t *ui_window_title(wchar_t *s); extern void ui_status_update(void); +extern void ui_hard_reset_completed(void); extern void ui_init_monitor(int monitor_index); extern void ui_deinit_monitor(int monitor_index); extern int ui_sb_find_part(int tag); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1c2ae6097..f3072706d 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -42,6 +42,7 @@ extern "C" { #include <86box/discord.h> #include <86box/device.h> #include <86box/video.h> +#include <86box/mouse.h> #include <86box/machine.h> #include <86box/vid_ega.h> #include <86box/version.h> @@ -188,6 +189,12 @@ MainWindow::MainWindow(QWidget *parent) vmname.truncate(vmname.size() - 1); this->setWindowTitle(QString("%1 - %2 %3").arg(vmname, EMU_NAME, EMU_VERSION_FULL)); + connect(this, &MainWindow::hardResetCompleted, this, [this]() { + ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); + QApplication::setOverrideCursor(Qt::ArrowCursor); + ui->menuTablet_tool->menuAction()->setVisible(mouse_mode >= 1); + }); + connect(this, &MainWindow::showMessageForNonQtThread, this, &MainWindow::showMessage_, Qt::BlockingQueuedConnection); connect(this, &MainWindow::setTitle, this, [this, toolbar_label](const QString &title) { @@ -622,6 +629,16 @@ MainWindow::MainWindow(QWidget *parent) } }); #endif + + actGroup = new QActionGroup(this); + actGroup->addAction(ui->actionCursor_Puck); + actGroup->addAction(ui->actionPen); + + if (tablet_tool_type == 1) { + ui->actionPen->setChecked(true); + } else { + ui->actionCursor_Puck->setChecked(true); + } } void @@ -1671,7 +1688,6 @@ MainWindow::refreshMediaMenu() { mm->refresh(ui->menuMedia); status->refresh(ui->statusbar); - ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); } void @@ -2411,3 +2427,16 @@ MainWindow::on_actionApply_fullscreen_stretch_mode_when_maximized_triggered(bool device_force_redraw(); config_save(); } + +void MainWindow::on_actionCursor_Puck_triggered() +{ + tablet_tool_type = 0; + config_save(); +} + +void MainWindow::on_actionPen_triggered() +{ + tablet_tool_type = 1; + config_save(); +} + diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 6ad4c9beb..fb05a4588 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -50,6 +50,7 @@ signals: void destroyRendererMonitor(int monitor_index); void initRendererMonitorForNonQtThread(int monitor_index); void destroyRendererMonitorForNonQtThread(int monitor_index); + void hardResetCompleted(); void setTitle(const QString &title); void setFullscreen(bool state); @@ -134,6 +135,12 @@ protected: void closeEvent(QCloseEvent *event) override; void changeEvent(QEvent *event) override; +private slots: + void on_actionPen_triggered(); + +private slots: + void on_actionCursor_Puck_triggered(); + private slots: void on_actionShow_non_primary_monitors_triggered(); diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index 6a86b632e..1a00df27a 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -61,8 +61,16 @@ &Action + + + Tablet tool + + + + + @@ -851,6 +859,22 @@ Apply fullscreen stretch mode when maximized + + + true + + + Cursor/Puck + + + + + true + + + Pen + + diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index d36a88f86..0436112d1 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -58,8 +58,10 @@ double mouse_x_error = 0.0, mouse_y_error = 0.0; } struct mouseinputdata { - atomic_int deltax, deltay, deltaz; - atomic_int mousebuttons; + atomic_int deltax, deltay, deltaz; + atomic_int mousebuttons; + atomic_bool mouse_tablet_in_proximity; + std::atomic x_abs, y_abs; }; static mouseinputdata mousedata; @@ -116,6 +118,7 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) RendererStack::~RendererStack() { + QApplication::restoreOverrideCursor(); delete ui; } @@ -142,9 +145,12 @@ void RendererStack::mousePoll() { #ifndef __APPLE__ - mouse_x = mousedata.deltax; - mouse_y = mousedata.deltay; - mouse_z = mousedata.deltaz; + mouse_x = mousedata.deltax; + mouse_y = mousedata.deltay; + mouse_z = mousedata.deltaz; + mouse_x_abs = mousedata.x_abs; + mouse_y_abs = mousedata.y_abs; + mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; mouse_buttons = mousedata.mousebuttons; @@ -166,7 +172,7 @@ int ignoreNextMouseEvent = 1; void RendererStack::mouseReleaseEvent(QMouseEvent *event) { - if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1) && (mouse_get_buttons() != 0)) { + if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1) && (mouse_get_buttons() != 0) && mouse_mode == 0) { plat_mouse_capture(1); this->setCursor(Qt::BlankCursor); if (!ignoreNextMouseEvent) @@ -180,7 +186,7 @@ RendererStack::mouseReleaseEvent(QMouseEvent *event) isMouseDown &= ~1; return; } - if (mouse_capture) { + if (mouse_capture || mouse_mode >= 1) { mousedata.mousebuttons &= ~event->button(); } isMouseDown &= ~1; @@ -190,7 +196,7 @@ void RendererStack::mousePressEvent(QMouseEvent *event) { isMouseDown |= 1; - if (mouse_capture) { + if (mouse_capture || mouse_mode >= 1) { mousedata.mousebuttons |= event->button(); } event->accept(); @@ -238,9 +244,26 @@ RendererStack::mouseMoveEvent(QMouseEvent *event) #endif } + +void +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +RendererStack::enterEvent(QEnterEvent *event) +#else +RendererStack::enterEvent(QEvent *event) +#endif +{ + mousedata.mouse_tablet_in_proximity = 1; + + if (mouse_mode == 1) + QApplication::setOverrideCursor(Qt::BlankCursor); +} + void RendererStack::leaveEvent(QEvent *event) { + mousedata.mouse_tablet_in_proximity = 0; + if (mouse_mode == 1) + QApplication::setOverrideCursor(Qt::ArrowCursor); if (QApplication::platformName().contains("wayland")) { event->accept(); return; @@ -501,3 +524,16 @@ RendererStack::changeEvent(QEvent *event) config_save(); } } + +bool +RendererStack::event(QEvent* event) +{ + if (event->type() == QEvent::MouseMove) { + QMouseEvent* mouse_event = (QMouseEvent*)event; + if (mouse_mode >= 1) { + mousedata.x_abs = (mouse_event->localPos().x()) / (long double)width(); + mousedata.y_abs = (mouse_event->localPos().y()) / (long double)height(); + } + } + return QStackedWidget::event(event); +} diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index baee5ea9f..27e07747c 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,11 @@ public: void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + void enterEvent(QEnterEvent *event) override; +#else + void enterEvent(QEvent *event) override; +#endif void leaveEvent(QEvent *event) override; void closeEvent(QCloseEvent *event) override; void changeEvent(QEvent *event) override; @@ -45,6 +51,7 @@ public: { event->ignore(); } + bool event(QEvent* event) override; enum class Renderer { Software, diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index a2864f3ea..305ec9ed5 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -74,6 +74,12 @@ ui_window_title(wchar_t *str) return str; } +void +ui_hard_reset_completed() +{ + emit main_window->hardResetCompleted(); +} + extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index) { diff --git a/src/unix/unix.c b/src/unix/unix.c index 296da5e14..04c9de48b 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -1319,3 +1319,8 @@ void ui_sb_mt32lcd(char *str) { } + +void +ui_hard_reset_completed(void) +{ +} diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 040b14aee..a743db40c 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -596,6 +596,7 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm mouse.o \ mouse_bus.o \ mouse_serial.o mouse_ps2.o \ + mouse_wacom_tablet.o \ phoenix_486_jumper.o SIOOBJ := sio_acc3221.o sio_ali5123.o \ diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 38d7e161c..0e1ca6700 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -1582,7 +1582,13 @@ void ui_init_monitor(int monitor_index) { } + void ui_deinit_monitor(int monitor_index) { } + +void +ui_hard_reset_completed(void) +{ +}