From c695cb8ded25967b64910b49879a44a116bb7370 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Aug 2023 18:49:58 +0200 Subject: [PATCH] Completely reworked mouse handling - should now be smoother due to there no longer being a multi-layered game of telephone going on with all the various interim coordinate counters, also rewritten the serial mouse emulation ground ground up. --- src/86box.c | 8 +- src/device/mouse.c | 92 ++- src/device/mouse_bus.c | 84 +- src/device/mouse_ps2.c | 91 +- src/device/mouse_serial.c | 1369 ++++++++++++++++++------------- src/include/86box/mouse.h | 26 +- src/io.c | 61 +- src/qt/evdev_mouse.cpp | 21 +- src/qt/evdev_mouse.hpp | 1 - src/qt/macos_event_filter.mm | 42 +- src/qt/qt_main.cpp | 1 - src/qt/qt_mainwindow.cpp | 6 +- src/qt/qt_mainwindow.hpp | 1 - src/qt/qt_rendererstack.cpp | 77 +- src/qt/qt_rendererstack.hpp | 2 +- src/qt/qt_sdl.c | 32 +- src/qt/qt_sdl.h | 1 - src/qt/qt_ui.cpp | 6 - src/qt/qt_winrawinputfilter.cpp | 80 +- src/qt/qt_winrawinputfilter.hpp | 3 - src/qt/wl_mouse.cpp | 19 +- src/qt/wl_mouse.hpp | 1 - src/qt/xinput2_mouse.cpp | 21 +- src/unix/unix.c | 26 +- src/win/win_mouse.c | 74 +- 25 files changed, 1155 insertions(+), 990 deletions(-) diff --git a/src/86box.c b/src/86box.c index 49da06224..8f71b9ffa 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1279,10 +1279,12 @@ pc_run(void) startblit(); cpu_exec(cpu_s->rspeed / 100); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ - // if (gdbstub_step == GDBSTUB_EXEC) + if (gdbstub_step == GDBSTUB_EXEC) { #endif -#if 0 - mouse_process(); + if (!mouse_timed) + mouse_process(); +#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ + } #endif joystick_process(); endblit(); diff --git a/src/device/mouse.c b/src/device/mouse.c index 2acfd905e..8b22b0696 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -19,7 +19,9 @@ * Copyright 2016-2018 Miran Grca. * Copyright 2017-2018 Fred N. van Kempen. */ +#include #include +#include #include #include #include @@ -37,17 +39,22 @@ typedef struct mouse_t { } mouse_t; int mouse_type = 0; -int mouse_x; -int mouse_y; -int mouse_z; -int mouse_buttons; +atomic_int mouse_x; +atomic_int mouse_y; +atomic_int mouse_z; +atomic_int mouse_buttons; int mouse_mode; +int mouse_timed = 1; int mouse_tablet_in_proximity = 0; int tablet_tool_type = 1; /* 0 = Puck/Cursor, 1 = Pen */ double mouse_x_abs; double mouse_y_abs; +double mouse_sensitivity = 1.0; +double mouse_x_error = 0.0; +double mouse_y_error = 0.0; + pc_timer_t mouse_timer; /* mouse event timer */ static const device_t mouse_none_device = { @@ -155,22 +162,81 @@ mouse_close(void) static void mouse_timer_poll(UNUSED(void *priv)) { - /* Poll at 255 Hz, maximum supported by PS/2 mic. */ + /* Poll at the specified sample rate. */ timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ - if (gdbstub_step == GDBSTUB_EXEC) + if (gdbstub_step == GDBSTUB_EXEC) { #endif - mouse_process(); + if (mouse_timed) + mouse_process(); +#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ + } +#endif +} + +void +mouse_scale(int x, int y) +{ + pclog("mouse_scale()\n"); + double scaled_x = (((double) x) * mouse_sensitivity) + mouse_x_error; + double scaled_y = (((double) y) * mouse_sensitivity) + mouse_y_error; + + mouse_x += (int) scaled_x; + mouse_y += (int) scaled_y; + + mouse_x_error = scaled_x - floor(scaled_x); + mouse_y_error = scaled_y - floor(scaled_y); +} + +void +mouse_scale_x(int x) +{ + double scaled_x = ((double) x) * mouse_sensitivity + mouse_x_error; + + mouse_x += (int) scaled_x; + + mouse_x_error = scaled_x - ((double) mouse_x); +} + +void +mouse_scale_y(int y) +{ + double scaled_y = ((double) y) * mouse_sensitivity + mouse_y_error; + + mouse_y += (int) scaled_y; + + mouse_y_error = scaled_y - ((double) mouse_y); +} + +void +mouse_set_z(int z) +{ + mouse_z += z; +} + +void +mouse_set_buttons_ex(int b) +{ + mouse_buttons = b; +} + +int +mouse_get_buttons_ex(void) +{ + return mouse_buttons; } void mouse_set_sample_rate(double new_rate) { + mouse_timed = (new_rate > 0.0); + timer_stop(&mouse_timer); sample_rate = new_rate; - timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); + if (mouse_timed) + timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); } void @@ -186,6 +252,9 @@ mouse_reset(void) mouse_x = mouse_y = mouse_z = 0; mouse_buttons = 0x00; mouse_mode = 0; + mouse_timed = 1; + + mouse_x_error = mouse_y_error = 0.0; /* If no mouse configured, we're done. */ if (mouse_type == 0) @@ -222,19 +291,14 @@ mouse_process(void) if (mouse_curr == NULL) return; - if (mouse_poll_ex) + if ((mouse_mode >= 1) && mouse_poll_ex) mouse_poll_ex(); - else - mouse_poll(); 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_x_abs, mouse_y_abs, mouse_priv); else mouse_dev_poll(mouse_x, mouse_y, mouse_z, mouse_buttons, mouse_priv); - - /* Reset mouse deltas. */ - mouse_x = mouse_y = mouse_z = 0; } } diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index 0537c0cb4..33ac2ded3 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -68,6 +68,7 @@ */ #include #include +#include #include #include #include @@ -80,6 +81,7 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/mouse.h> +#include <86box/plat.h> #include <86box/plat_unused.h> #include <86box/random.h> @@ -147,8 +149,6 @@ typedef struct mouse { int irq; int bn; int flags; - int mouse_delayed_dx; - int mouse_delayed_dy; int mouse_buttons; int mouse_buttons_last; int toggle_counter; @@ -480,10 +480,13 @@ bm_poll(int x, int y, UNUSED(int z), int b, UNUSED(double abs_x), UNUSED(double mouse_t *dev = (mouse_t *) priv; int xor ; + if (!mouse_capture && !video_fullscreen) + return 1; + if (!(dev->flags & FLAG_ENABLED)) return 1; /* Mouse is disabled, do nothing. */ - if (!x && !y && !((b ^ dev->mouse_buttons_last) & 0x07)) { + if (!mouse_x && !mouse_y && !((b ^ dev->mouse_buttons_last) & 0x07)) { dev->mouse_buttons_last = b; return 1; /* State has not changed, do nothing. */ } @@ -498,7 +501,7 @@ bm_poll(int x, int y, UNUSED(int z), int b, UNUSED(double abs_x), UNUSED(double so update bits 6-3 here. */ /* If the mouse has moved, set bit 6. */ - if (x || y) + if (mouse_x || mouse_y) dev->mouse_buttons |= 0x40; /* Set bits 3-5 according to button state changes. */ @@ -508,26 +511,30 @@ bm_poll(int x, int y, UNUSED(int z), int b, UNUSED(double abs_x), UNUSED(double dev->mouse_buttons_last = b; - /* Clamp x and y to between -128 and 127 (int8_t range). */ - if (x > 127) - x = 127; - if (x < -128) - x = -128; - - if (y > 127) - y = 127; - if (y < -128) - y = -128; - - if (dev->timer_enabled) { - /* Update delayed coordinates. */ - dev->mouse_delayed_dx += x; - dev->mouse_delayed_dy += y; - } else { + if (!dev->timer_enabled) { /* If the counters are not frozen, update them. */ if (!(dev->flags & FLAG_HOLD)) { - dev->current_x = (int8_t) x; - dev->current_y = (int8_t) y; + if (mouse_x > 127) { + dev->current_x = 127; + mouse_x -= 127; + } else if (mouse_x < 1-128) { + dev->current_x = -128; + mouse_x += 128; + } else { + dev->current_x = mouse_x; + mouse_x = 0; + } + + if (mouse_y > 127) { + dev->current_y = 127; + mouse_y -= 127; + } else if (mouse_y < 1-128) { + dev->current_y = -128; + mouse_y += 128; + } else { + dev->current_y = mouse_y; + mouse_y = 0; + } dev->current_b = dev->mouse_buttons; } @@ -538,6 +545,7 @@ bm_poll(int x, int y, UNUSED(int z), int b, UNUSED(double abs_x), UNUSED(double bm_log("DEBUG: Data Interrupt Fired...\n"); } } + return 0; } @@ -548,31 +556,31 @@ bm_update_data(mouse_t *dev) { int delta_x; int delta_y; - int xor ; + int xor; /* If the counters are not frozen, update them. */ - if (!(dev->flags & FLAG_HOLD)) { + if ((mouse_capture || video_fullscreen) && !(dev->flags & FLAG_HOLD)) { /* Update the deltas and the delays. */ - if (dev->mouse_delayed_dx > 127) { + if (mouse_x > 127) { delta_x = 127; - dev->mouse_delayed_dx -= 127; - } else if (dev->mouse_delayed_dx < -128) { + mouse_x -= 127; + } else if (mouse_x < -128) { delta_x = -128; - dev->mouse_delayed_dx += 128; + mouse_x += 128; } else { - delta_x = dev->mouse_delayed_dx; - dev->mouse_delayed_dx = 0; + delta_x = mouse_x; + mouse_x = 0; } - if (dev->mouse_delayed_dy > 127) { + if (mouse_y > 127) { delta_y = 127; - dev->mouse_delayed_dy -= 127; - } else if (dev->mouse_delayed_dy < -128) { + mouse_y -= 127; + } else if (mouse_y < -128) { delta_y = -128; - dev->mouse_delayed_dy += 128; + mouse_y += 128; } else { - delta_y = dev->mouse_delayed_dy; - dev->mouse_delayed_dy = 0; + delta_y = mouse_y; + mouse_y = 0; } dev->current_x = (int8_t) delta_x; @@ -659,8 +667,6 @@ bm_init(const device_t *info) } mouse_set_buttons(dev->bn); - dev->mouse_delayed_dx = 0; - dev->mouse_delayed_dy = 0; dev->mouse_buttons = 0; dev->mouse_buttons_last = 0; dev->sig_val = 0; /* the signature port value */ @@ -707,6 +713,8 @@ bm_init(const device_t *info) else bm_log("Standard MS/Logitech BusMouse initialized\n"); + mouse_set_sample_rate(0.0); + return dev; } diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 2d150b5ed..f78fc55c4 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -13,6 +13,7 @@ * Authors: Fred N. van Kempen, */ #include +#include #include #include #include @@ -23,6 +24,7 @@ #include <86box/device.h> #include <86box/keyboard.h> #include <86box/mouse.h> +#include <86box/plat.h> #include <86box/plat_unused.h> enum { @@ -75,40 +77,51 @@ ps2_report_coordinates(atkbc_dev_t *dev, int main) uint8_t buff[3] = { 0x08, 0x00, 0x00 }; int temp_z; - if (dev->x > 255) { - dev->x = 255; + if (mouse_x > 255) { buff[0] |= 0x40; + buff[1] = 255; + mouse_x -= 255; + } else if (mouse_x < -256) { + buff[0] |= (0x40 | 0x10); + mouse_x += 256; + } else { + if (mouse_x < 0) + buff[0] |= 0x10; + buff[1] = mouse_x; + mouse_x = 0; } - if (dev->x < -256) { - dev->x = -256; - buff[0] |= 0x40; - } - if (dev->y > 255) { - dev->y = 255; - buff[0] |= 0x80; - } - if (dev->y < -256) { - dev->y = -256; - buff[0] |= 0x80; - } - if (dev->z < -8) - dev->z = -8; - if (dev->z > 7) - dev->z = 7; - if (dev->x < 0) - buff[0] |= 0x10; - if (dev->y < 0) - buff[0] |= 0x20; - buff[0] |= (dev->b & ((dev->flags & FLAG_INTELLI) ? 0x07 : 0x03)); - buff[1] = (dev->x & 0xff); - buff[2] = (dev->y & 0xff); + if (mouse_y < -255) { + buff[0] |= 0x80; + buff[2] = 255; + mouse_y += 255; + } else if (mouse_y > 256) { + buff[0] |= (0x80 | 0x20); + mouse_y -= 256; + } else { + if (mouse_y > 0) + buff[0] |= 0x20; + buff[2] = -mouse_y; + mouse_y = 0; + } + + if (dev->z < -7) { + temp_z = 7; + temp_z += 7; + } else if (mouse_z > 8) { + temp_z = (-8) & 0x0f; + mouse_z -= 8; + } else { + temp_z = (-mouse_y) & 0x0f; + mouse_z = 0; + } + + buff[0] |= (mouse_buttons & ((dev->flags & FLAG_INTELLI) ? 0x07 : 0x03)); kbc_at_dev_queue_add(dev, buff[0], main); kbc_at_dev_queue_add(dev, buff[1], main); kbc_at_dev_queue_add(dev, buff[2], main); if (dev->flags & FLAG_INTMODE) { - temp_z = dev->z & 0x0f; if (dev->flags & FLAG_5BTN) { if (mouse_buttons & 8) temp_z |= 0x10; @@ -121,8 +134,6 @@ ps2_report_coordinates(atkbc_dev_t *dev, int main) } kbc_at_dev_queue_add(dev, temp_z, main); } - - dev->x = dev->y = dev->z = 0; } static void @@ -132,7 +143,7 @@ ps2_set_defaults(atkbc_dev_t *dev) dev->rate = 100; mouse_set_sample_rate(100.0); dev->resolution = 2; - dev->flags &= 0x88; + dev->flags &= 0x188; mouse_scan = 0; } @@ -316,25 +327,17 @@ ps2_poll(int x, int y, int z, int b, UNUSED(double abs_x), UNUSED(double abs_y), atkbc_dev_t *dev = (atkbc_dev_t *) priv; int packet_size = (dev->flags & FLAG_INTMODE) ? 4 : 3; - if (!mouse_scan || (!x && !y && !z && (b == dev->b))) - return 0xff; + int cond = (!mouse_capture && !video_fullscreen) || (!mouse_scan || (!x && !y && !z && (b == dev->b))) || + ((dev->mode == MODE_STREAM) && (kbc_at_dev_queue_pos(dev, 1) >= (FIFO_SIZE - packet_size))); - if ((dev->mode == MODE_STREAM) && (kbc_at_dev_queue_pos(dev, 1) < (FIFO_SIZE - packet_size))) { - dev->x = x; - dev->y = -y; - dev->z = -z; - dev->b = b; - } else { - dev->x += x; - dev->y -= y; - dev->z -= z; + if (!cond) { dev->b = b; + + if (dev->mode == MODE_STREAM) + ps2_report_coordinates(dev, 1); } - if ((dev->mode == MODE_STREAM) && (kbc_at_dev_queue_pos(dev, 1) < (FIFO_SIZE - packet_size))) - ps2_report_coordinates(dev, 1); - - return 0; + return cond; } /* diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index c74e5216b..16a8d6a1e 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -14,6 +14,7 @@ * * Authors: Fred N. van Kempen, */ +#include #include #include #include @@ -26,66 +27,82 @@ #include <86box/timer.h> #include <86box/serial.h> #include <86box/mouse.h> +#include <86box/plat.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> #define SERMOUSE_PORT 0 /* attach to Serial0 */ enum { - PHASE_IDLE, - PHASE_ID, - PHASE_DATA, - PHASE_STATUS, - PHASE_DIAGNOSTIC, - PHASE_FORMAT_AND_REVISION, - PHASE_COPYRIGHT_STRING, - PHASE_BUTTONS, - PHASE_ACK, - PHASE_BAUD_RATE + STATE_RESET, + STATE_BAUD_RATE, + STATE_DORMANT, + STATE_IDLE, + STATE_COMMAND, + STATE_DATA, + STATE_TRANSMIT, + STATE_TRANSMIT_REPORT, + STATE_SKIP_REPORT }; enum { - REPORT_PHASE_PREPARE, - REPORT_PHASE_TRANSMIT + FORMAT_BP1_ABS = 0x01, + FORMAT_BP1_REL, + FORMAT_MM_SERIES = 0x13, + FORMAT_PB_3BYTE, + FORMAT_PB_5BYTE, + FORMAT_MSYSTEMS = 0x15, /* Alias for FORMAT_PB_5BYTE. */ + FORMAT_MS, + FORMAT_HEX, + FORMAT_MS_4BYTE, + FORMAT_MS_WHEEL, + FORMATS_NUM }; typedef struct mouse_t { const char *name; /* name of this device */ - int8_t type; /* type of this device */ - int8_t port; + + uint8_t id[252]; + uint8_t buf[256]; + uint8_t flags; /* device flags */ uint8_t but; - uint8_t want_data; + uint8_t rts_toggle; uint8_t status; uint8_t format; uint8_t prompt; - uint8_t on_change; + + uint8_t continuous; + uint8_t ib; + uint8_t command; + uint8_t buf_len; + uint8_t report_mode; uint8_t id_len; - uint8_t id[255]; - uint8_t data_len; - uint8_t data[5]; + uint8_t buf_pos; + uint8_t rev; + + int8_t type; /* type of this device */ + int8_t port; + int abs_x; int abs_y; - int rel_x; - int rel_y; - int rel_z; - int oldb; - int lastb; + int old_buttons; + int state; + int bps; + int rps; - int command_pos; - int command_phase; - int report_pos; - int report_phase; - int command_enabled; - int report_enabled; - double transmit_period; - double report_period; - double auto_period; - pc_timer_t command_timer; - pc_timer_t report_timer; + double transmit_period; + double report_period; + double cur_period; + double min_bit_period; + double acc_time; + double host_transmit_period; - serial_t *serial; + pc_timer_t timer; + + serial_t * serial; } mouse_t; + #define FLAG_INPORT 0x80 /* device is MS InPort */ #define FLAG_3BTN 0x20 /* enable 3-button mode */ #define FLAG_SCALED 0x10 /* enable delta scaling */ @@ -112,184 +129,274 @@ mouse_serial_log(const char *fmt, ...) #endif static void -sermouse_timer_on(mouse_t *dev, double period, int report) +sermouse_set_period(mouse_t *dev, double period) { - pc_timer_t *timer; - int *enabled; + dev->cur_period = period; /* Needed for the recalculation of the timings. */ - if (report) { - timer = &dev->report_timer; - enabled = &dev->report_enabled; - } else { - timer = &dev->command_timer; - enabled = &dev->command_enabled; - } + timer_stop(&dev->timer); - timer_on_auto(timer, period); - - *enabled = 1; + if (period > 0.0) + timer_on_auto(&dev->timer, 10000.0); } -static double -sermouse_transmit_period(mouse_t *dev, int bps, int rps) -{ - double dbps = (double) bps; - double temp = 0.0; - int word_len; - - switch (dev->format) { - case 0: - case 1: /* Mouse Systems and Three Byte Packed formats: 8 data, no parity, 2 stop, 1 start */ - word_len = 11; - break; - case 2: /* Hexadecimal format - 8 data, no parity, 1 stop, 1 start - number of stop bits is a guess because - it is not documented anywhere. */ - word_len = 10; - break; - case 3: - case 6: /* Bit Pad One formats: 7 data, even parity, 2 stop, 1 start */ - word_len = 11; - break; - case 5: /* MM Series format: 8 data, odd parity, 1 stop, 1 start */ - word_len = 11; - break; - case 7: /* Microsoft-compatible format: 7 data, no parity, 1 stop, 1 start */ - default: - word_len = 9; - break; - } - - 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; -} - -/* Callback from serial driver: RTS was toggled. */ static void -sermouse_callback(UNUSED(struct serial_s *serial), void *priv) +sermouse_transmit_byte(mouse_t *dev, int do_next) { - mouse_t *dev = (mouse_t *) priv; + if (dev->buf_pos == 0) + dev->acc_time = 0.0; - /* Start a timer to wake us up in a little while. */ - dev->command_pos = 0; - dev->command_phase = PHASE_ID; - if (dev->id[0] != 'H') - dev->format = 7; - dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); - timer_stop(&dev->command_timer); -#ifdef USE_NEW_DYNAREC - sermouse_timer_on(dev, cpu_use_dynarec ? 5000.0 : dev->transmit_period, 0); -#else - sermouse_timer_on(dev, dev->transmit_period, 0); -#endif + serial_write_fifo(dev->serial, dev->buf[dev->buf_pos]); + + if (do_next) { + dev->buf_pos = (dev->buf_pos + 1) % dev->buf_len; + + if (dev->buf_pos != 0) + sermouse_set_period(dev, dev->transmit_period); + } +} + +static void +sermouse_transmit(mouse_t *dev, int len, int from_report, int to_report) +{ + dev->state = to_report ? STATE_TRANSMIT_REPORT : STATE_TRANSMIT; + dev->buf_pos = 0; + dev->buf_len = len; + + if (from_report) { + if (dev->acc_time > dev->report_period) + dev->acc_time -= dev->report_period; + + /* We have too little time left, pretend it's zero and handle + schedule the next report at byte period. */ + if (dev->acc_time < dev->min_bit_period) + sermouse_set_period(dev, dev->transmit_period); + /* We have enough time, schedule the next report at report period, + subtract the accumulated time from the total period, and add + one byte period (the first byte delay). */ + else + sermouse_set_period(dev, dev->report_period - dev->acc_time + dev->transmit_period); + } else + sermouse_set_period(dev, dev->transmit_period); +} + +/* It appears all host platforms give us y in the Microsoft format + (positive to the south), so for all non-Microsoft report formsts, + we have to invenrt that. */ +static void +sermouse_subtract_coords(mouse_t *dev, int *delta_x, int *delta_y, int min, int max, int invert, int abs) +{ + int real_y = mouse_y; + int abs_max = max + ABS(min); + + if (invert) + real_y = -real_y; + + if (mouse_x > max) { + if (abs) { + dev->abs_x += max; + *delta_x = dev->abs_x; + } else + *delta_x = max; + mouse_x -= max; + } else if (mouse_x < min) { + if (abs) { + dev->abs_x += min; + *delta_x = dev->abs_x; + } else + *delta_x = min; + mouse_x += ABS(min); + } else { + if (abs) { + dev->abs_x += mouse_x; + *delta_x = dev->abs_x; + } else + *delta_x = mouse_x; + mouse_x = 0; + } + + if (real_y > max) { + if (abs) { + dev->abs_y += max; + *delta_y = dev->abs_y; + } else + *delta_y = max; + real_y -= max; + } else if (real_y < min) { + if (abs) { + dev->abs_y += min; + *delta_y = dev->abs_y; + } else + *delta_y = min; + real_y += ABS(min); + } else { + if (abs) { + dev->abs_y += real_y; + *delta_y = dev->abs_y; + } else + *delta_y = real_y; + real_y = 0; + } + + if (abs) { + if (dev->abs_x < 0) + *delta_x = 0; + else if (dev->abs_x > abs_max) + *delta_x = abs_max; + + if (dev->abs_y < 0) + *delta_y = 0; + else if (dev->abs_y > abs_max) + *delta_y = abs_max; + } + + if (invert) + real_y = -real_y; + + mouse_y = real_y; } static uint8_t -sermouse_data_msystems(mouse_t *dev, int x, int y, int b) +sermouse_report_msystems(mouse_t *dev) { - dev->data[0] = 0x80; - dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ - dev->data[1] = x; - dev->data[2] = -y; - dev->data[3] = x; /* same as byte 1 */ - dev->data[4] = -y; /* same as byte 2 */ + int delta_x = 0; + int delta_y = 0; + + sermouse_subtract_coords(dev, &delta_x, &delta_y, -128, 127, 1, 0); + + dev->buf[0] = 0x80; + dev->buf[0] |= (mouse_buttons & 0x01) ? 0x00 : 0x04; /* left button */ + if (dev->but >= 3) + dev->buf[0] |= (mouse_buttons & 0x04) ? 0x00 : 0x02; /* middle button */ + else + dev->buf[0] |= 0x02; /* middle button */ + dev->buf[0] |= (mouse_buttons & 0x02) ? 0x00 : 0x01; /* right button */ + dev->buf[1] = delta_x; + dev->buf[2] = delta_y; + dev->buf[2] = delta_x; /* same as byte 1 */ + dev->buf[3] = delta_y; /* same as byte 2 */ return 5; } static uint8_t -sermouse_data_3bp(mouse_t *dev, int x, int y, int b) +sermouse_report_3bp(mouse_t *dev) { - dev->data[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - dev->data[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */ - dev->data[1] = x; - dev->data[2] = -y; + int delta_x = 0; + int delta_y = 0; + + sermouse_subtract_coords(dev, &delta_x, &delta_y, -128, 127, 1, 0); + + dev->buf[0] = 0x80; + dev->buf[0] |= (mouse_buttons & 0x01) ? 0x04 : 0x00; /* left button */ + if (dev->but >= 3) + dev->buf[0] |= (mouse_buttons & 0x04) ? 0x02 : 0x00; /* middle button */ + dev->buf[0] |= (mouse_buttons & 0x02) ? 0x01 : 0x00; /* right button */ + dev->buf[1] = delta_x; + dev->buf[2] = delta_y; + dev->buf[2] = delta_x; /* same as byte 1 */ + dev->buf[3] = delta_y; /* same as byte 2 */ return 3; } static uint8_t -sermouse_data_mmseries(mouse_t *dev, int x, int y, int b) +sermouse_report_mmseries(mouse_t *dev) { - if (x < -127) - x = -127; - if (y < -127) - y = -127; + int delta_x = 0; + int delta_y = 0; - dev->data[0] = 0x80; - if (x >= 0) - dev->data[0] |= 0x10; - /* It appears we have inverted Y polarity. */ - if (y < 0) - dev->data[0] |= 0x08; - dev->data[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - dev->data[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */ - dev->data[1] = abs(x) & 0x7f; - dev->data[2] = abs(y) & 0x7f; + sermouse_subtract_coords(dev, &delta_x, &delta_y, -127, 127, 1, 0); + + dev->buf[0] = 0x80; + if (delta_x >= 0) + dev->buf[0] |= 0x10; + if (delta_y >= 0) + dev->buf[0] |= 0x08; + + dev->buf[0] |= (mouse_buttons & 0x01) ? 0x04 : 0x00; /* left button */ + if (dev->but >= 3) + dev->buf[0] |= (mouse_buttons & 0x04) ? 0x02 : 0x00; /* middle button */ + dev->buf[0] |= (mouse_buttons & 0x02) ? 0x01 : 0x00; /* right button */ + dev->buf[1] = ABS(delta_x) & 0x7f; + dev->buf[2] = ABS(delta_y) & 0x7f; + mouse_serial_log("MM series mouse report: %02X %02X %02X\n", dev->buf[0], dev->buf[1], dev->buf[2]); return 3; } static uint8_t -sermouse_data_bp1(mouse_t *dev, int x, int y, int b) +sermouse_report_bp1(mouse_t *dev, int abs) { - dev->data[0] = 0x80; - dev->data[0] |= (b & 0x01) ? 0x10 : 0x00; /* left button */ - dev->data[0] |= (b & 0x04) ? 0x08 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x02) ? 0x04 : 0x00; /* right button */ - dev->data[1] = (x & 0x3f); - dev->data[2] = (x >> 6); - dev->data[3] = (y & 0x3f); - dev->data[4] = (y >> 6); + int delta_x = 0; + int delta_y = 0; + + sermouse_subtract_coords(dev, &delta_x, &delta_y, -2048, 2047, 1, abs); + + dev->buf[0] = 0x80; + dev->buf[0] |= (mouse_buttons & 0x01) ? 0x10 : 0x00; /* left button */ + if (dev->but >= 3) + dev->buf[0] |= (mouse_buttons & 0x04) ? 0x08 : 0x00; /* middle button */ + dev->buf[0] |= (mouse_buttons & 0x02) ? 0x04 : 0x00; /* right button */ + dev->buf[1] = (delta_x & 0x3f); + dev->buf[2] = ((delta_x >> 6) & 0x3f); + dev->buf[3] = (delta_y & 0x3f); + dev->buf[4] = ((delta_y >> 6) & 0x3f); return 5; } static uint8_t -sermouse_data_ms(mouse_t *dev, int x, int y, int z, int b) +sermouse_report_ms(mouse_t *dev) { uint8_t len; + int delta_x = 0; + int delta_y = 0; + int delta_z = 0; - dev->data[0] = 0x40; - dev->data[0] |= (((y >> 6) & 0x03) << 2); - dev->data[0] |= ((x >> 6) & 0x03); - if (b & 0x01) - dev->data[0] |= 0x20; - if (b & 0x02) - dev->data[0] |= 0x10; - dev->data[1] = x & 0x3F; - dev->data[2] = y & 0x3F; + sermouse_subtract_coords(dev, &delta_x, &delta_y, -128, 127, 0, 0); + + dev->buf[0] = 0x40; + dev->buf[0] |= (((delta_y >> 6) & 0x03) << 2); + dev->buf[0] |= ((delta_x >> 6) & 0x03); + if (mouse_buttons & 0x01) + dev->buf[0] |= 0x20; + if (mouse_buttons & 0x02) + dev->buf[0] |= 0x10; + dev->buf[1] = delta_x & 0x3f; + dev->buf[2] = delta_y & 0x3f; + mouse_serial_log("Microsoft serial mouse report: %02X %02X %02X\n", dev->buf[0], dev->buf[1], dev->buf[2]); if (dev->but == 3) { len = 3; - if (dev->type == MOUSE_TYPE_LT3BUTTON) { - if (b & 0x04) { - dev->data[3] = 0x20; + if (dev->format == FORMAT_MS) { + if (mouse_buttons & 0x04) { + dev->buf[3] = 0x20; len++; } } else { - if ((b ^ dev->oldb) & 0x04) { + if ((mouse_buttons ^ dev->old_buttons) & 0x04) { /* Microsoft 3-button mice send a fourth byte of 0x00 when the middle button has changed. */ - dev->data[3] = 0x00; + dev->buf[3] = 0x00; len++; } } } else if (dev->but == 4) { - len = 4; - dev->data[3] = z & 0x0F; - if (b & 0x04) - dev->data[3] |= 0x10; + len = 4; + + if (mouse_z > 7) { + delta_z = 7; + mouse_z -= 7; + } else if (mouse_z < -8) { + delta_z = -8; + mouse_z += 8; + } else { + delta_z = mouse_z; + mouse_z = 0; + } + + dev->buf[3] = delta_z & 0x0f; + if (mouse_buttons & 0x04) + dev->buf[3] |= 0x10; } else len = 3; @@ -297,252 +404,96 @@ sermouse_data_ms(mouse_t *dev, int x, int y, int z, int b) } static uint8_t -sermouse_data_hex(mouse_t *dev, int x, int y, int b) +sermouse_report_hex(mouse_t *dev) { char ret[6] = { 0, 0, 0, 0, 0, 0 }; uint8_t but = 0x00; + int delta_x = 0; + int delta_y = 0; - but |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - but |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ - but |= (b & 0x02) ? 0x01 : 0x00; /* right button */ + sermouse_subtract_coords(dev, &delta_x, &delta_y, -128, 127, 1, 0); - sprintf(ret, "%02X%02X%01X", (int8_t) y, (int8_t) x, but & 0x0f); + but |= (mouse_buttons & 0x01) ? 0x04 : 0x00; /* left button */ + if (dev->but >= 3) + but |= (mouse_buttons & 0x04) ? 0x02 : 0x00; /* middle button */ + but |= (mouse_buttons & 0x02) ? 0x01 : 0x00; /* right button */ - for (uint8_t i = 0; i < 5; i++) - dev->data[i] = ret[4 - i]; + sprintf(ret, "%01X%02X%02X", but & 0x0f, (int8_t) delta_x, (int8_t) delta_y); + + memcpy(dev->buf, ret, 5); return 5; } -static void -sermouse_report(int x, int y, int z, int b, mouse_t *dev) +static int +sermouse_report(mouse_t *dev) { int len = 0; - memset(dev->data, 0, 5); - - /* If the mouse is 2-button, ignore the middle button. */ - if (dev->but == 2) - b &= ~0x04; + memset(dev->buf, 0, 5); switch (dev->format) { - case 0: - len = sermouse_data_msystems(dev, x, y, b); + case FORMAT_PB_5BYTE: + len = sermouse_report_msystems(dev); break; - case 1: - len = sermouse_data_3bp(dev, x, y, b); + case FORMAT_PB_3BYTE: + len = sermouse_report_3bp(dev); break; - case 2: - len = sermouse_data_hex(dev, x, y, b); + case FORMAT_HEX: + len = sermouse_report_hex(dev); break; - case 3: /* Relative */ - len = sermouse_data_bp1(dev, x, y, b); + case FORMAT_BP1_REL: + len = sermouse_report_bp1(dev, 0); break; - case 5: - len = sermouse_data_mmseries(dev, x, y, b); + case FORMAT_MM_SERIES: + len = sermouse_report_mmseries(dev); break; - case 6: /* Absolute */ - len = sermouse_data_bp1(dev, dev->abs_x, dev->abs_y, b); + case FORMAT_BP1_ABS: + len = sermouse_report_bp1(dev, 1); break; - case 7: - len = sermouse_data_ms(dev, x, y, z, b); + case FORMAT_MS: + case FORMAT_MS_4BYTE: + case FORMAT_MS_WHEEL: + len = sermouse_report_ms(dev); break; default: break; } - dev->data_len = len; + return len; } static void -sermouse_command_phase_idle(mouse_t *dev) +sermouse_transmit_report(mouse_t *dev, int from_report) { - dev->command_pos = 0; - dev->command_phase = PHASE_IDLE; - dev->command_enabled = 0; -} + int z_changed = (dev->but == 4) ? mouse_z : 0; + int b_changed = ((mouse_buttons ^ dev->old_buttons) & 0x07); -static void -sermouse_command_pos_check(mouse_t *dev, int len) -{ - if (++dev->command_pos == len) - sermouse_command_phase_idle(dev); - else - timer_on_auto(&dev->command_timer, dev->transmit_period); -} + if (dev->but < 3) + b_changed &= ~0x04; -static uint8_t -sermouse_last_button_status(mouse_t *dev) -{ - uint8_t ret = 0x00; - - if (dev->oldb & 0x01) - ret |= 0x04; - if (dev->oldb & 0x02) - ret |= 0x02; - if (dev->oldb & 0x04) - ret |= 0x01; - - return ret; -} - -static void -sermouse_update_delta(mouse_t *dev, int *local, int *global) -{ - int min; - int max; - - if (dev->format == 3) { - min = -2048; - max = 2047; + if (mouse_capture && (mouse_x || mouse_y || z_changed || b_changed)) { + sermouse_transmit(dev, sermouse_report(dev), from_report, 1); + dev->old_buttons = mouse_buttons; } else { - min = -128; - max = 127; - } + if (dev->prompt || dev->continuous) + sermouse_set_period(dev, 0.0); + else { + dev->state = STATE_SKIP_REPORT; + /* Not in prompt or continuous mode and there have been no changes, + skip the next report entirely. */ + if (from_report) { + if (dev->acc_time > dev->report_period) + dev->acc_time -= dev->report_period; - if (*global > max) { - *local = max; - *global -= max; - } else if (*global < min) { - *local = min; - *global += -min; - } else { - *local = *global; - *global = 0; - } -} - -static uint8_t -sermouse_update_data(mouse_t *dev) -{ - uint8_t ret = 0; - int delta_x; - int delta_y; - int delta_z; - - /* Update the deltas and the delays. */ - sermouse_update_delta(dev, &delta_x, &dev->rel_x); - sermouse_update_delta(dev, &delta_y, &dev->rel_y); - sermouse_update_delta(dev, &delta_z, &dev->rel_z); - - sermouse_report(delta_x, delta_y, delta_z, dev->oldb, dev); - - mouse_serial_log("delta_x = %i, delta_y = %i, delta_z = %i, dev->oldb = %02X\n", - delta_x, delta_y, delta_z, dev->oldb); - - if (delta_x || delta_y || delta_z || (dev->oldb != dev->lastb) || !dev->on_change) - ret = 1; - - dev->lastb = dev->oldb; - - mouse_serial_log("sermouse_update_data(): ret = %i\n", ret); - - return ret; -} - -static double -sermouse_report_period(mouse_t *dev) -{ - if (dev->report_period == 0) - return dev->transmit_period; - else - return dev->report_period; -} - -static void -sermouse_report_prepare(mouse_t *dev) -{ - if (sermouse_update_data(dev)) { - /* Start sending data. */ - dev->report_phase = REPORT_PHASE_TRANSMIT; - dev->report_pos = 0; - sermouse_timer_on(dev, dev->transmit_period, 1); - } else { - dev->report_phase = REPORT_PHASE_PREPARE; - sermouse_timer_on(dev, sermouse_report_period(dev), 1); - } -} - -static void -sermouse_report_timer(void *priv) -{ - mouse_t *dev = (mouse_t *) priv; - - if (dev->report_phase == REPORT_PHASE_PREPARE) - sermouse_report_prepare(dev); - else { - /* If using the Mouse Systems format, update data because - the last two bytes are the X and Y delta since bytes 1 - and 2 were transmitted. */ - if (!dev->format && (dev->report_pos == 3)) - sermouse_update_data(dev); - serial_write_fifo(dev->serial, dev->data[dev->report_pos]); - if (++dev->report_pos == dev->data_len) { - if (!dev->report_enabled) - sermouse_report_prepare(dev); - else { - sermouse_timer_on(dev, sermouse_report_period(dev), 1); - dev->report_phase = REPORT_PHASE_PREPARE; - } - } else - sermouse_timer_on(dev, dev->transmit_period, 1); - } -} - -/* Callback timer expired, now send our "mouse ID" to the serial port. */ -static void -sermouse_command_timer(void *priv) -{ - mouse_t *dev = (mouse_t *) priv; - - switch (dev->command_phase) { - case PHASE_ID: - serial_write_fifo(dev->serial, dev->id[dev->command_pos]); - sermouse_command_pos_check(dev, dev->id_len); - if ((dev->command_phase == PHASE_IDLE) && (dev->type != MOUSE_TYPE_MSYSTEMS)) { - /* This resets back to Microsoft-compatible mode. */ - dev->report_phase = REPORT_PHASE_PREPARE; - sermouse_report_timer((void *) dev); - } - break; - case PHASE_ACK: - serial_write_fifo(dev->serial, 0x06); -#ifdef FALLTHROUGH_ANNOTATION - [[fallthrough]]; -#endif - case PHASE_BAUD_RATE: - sermouse_command_phase_idle(dev); - sermouse_timer_on(dev, dev->report_period, 1); - dev->report_phase = REPORT_PHASE_PREPARE; - sermouse_report_timer((void *) dev); - break; - case PHASE_DATA: - serial_write_fifo(dev->serial, dev->data[dev->command_pos]); - sermouse_command_pos_check(dev, dev->data_len); - break; - case PHASE_STATUS: - serial_write_fifo(dev->serial, dev->status); - sermouse_command_phase_idle(dev); - break; - case PHASE_DIAGNOSTIC: - if (dev->command_pos) - serial_write_fifo(dev->serial, 0x00); - else - serial_write_fifo(dev->serial, sermouse_last_button_status(dev)); - sermouse_command_pos_check(dev, 3); - break; - case PHASE_FORMAT_AND_REVISION: - serial_write_fifo(dev->serial, 0x10 | (dev->format << 1)); - sermouse_command_phase_idle(dev); - break; - case PHASE_BUTTONS: - serial_write_fifo(dev->serial, dev->but); - sermouse_command_phase_idle(dev); - break; - default: - sermouse_command_phase_idle(dev); - break; + if (dev->acc_time < dev->min_bit_period) + sermouse_set_period(dev, dev->report_period); + else + sermouse_set_period(dev, (dev->report_period * 2.0) - dev->acc_time); + } else + sermouse_set_period(dev, dev->report_period); + } } } @@ -551,85 +502,355 @@ sermouse_poll(int x, int y, int z, int b, UNUSED(double abs_x), UNUSED(double ab { mouse_t *dev = (mouse_t *) priv; - if (!x && !y && !z && (b == dev->oldb)) { - dev->oldb = b; + if (!mouse_capture || dev->prompt || !dev->continuous || (dev->state != STATE_IDLE)) return 1; - } - dev->oldb = b; - dev->abs_x += x; - dev->abs_y += y; - if (dev->abs_x < 0) - dev->abs_x = 0; - if (dev->abs_x > 4095) - dev->abs_x = 4095; - if (dev->abs_y < 0) - dev->abs_y = 0; - if (dev->abs_y > 4095) - dev->abs_y = 4095; - - if (dev->format == 3) { - if (x > 2047) - x = 2047; - if (y > 2047) - y = 2047; - if (x < -2048) - x = -2048; - if (y < -2048) - y = -2048; - } else { - if (x > 127) - x = 127; - if (y > 127) - y = 127; - if (x < -128) - x = -128; - if (y < -128) - y = -128; - } - - dev->rel_x += x; - dev->rel_y += y; - dev->rel_z += z; - - return 0; + sermouse_transmit_report(dev, 0); + return (dev->cur_period == 0.0) ? 1 : 0; } static void -ltsermouse_prompt_mode(mouse_t *dev, int prompt) +ltsermouse_set_prompt_mode(mouse_t *dev, int prompt) { dev->prompt = prompt; - dev->status &= 0xBF; - if (prompt) - dev->status |= 0x40; -} -static void -ltsermouse_command_phase(mouse_t *dev, int phase) -{ - dev->command_pos = 0; - dev->command_phase = phase; - timer_stop(&dev->command_timer); - sermouse_timer_on(dev, dev->transmit_period, 0); + if (prompt || dev->continuous) + sermouse_set_period(dev, 0.0); + else + sermouse_set_period(dev, dev->transmit_period); } static void ltsermouse_set_report_period(mouse_t *dev, int rps) { - dev->report_period = sermouse_transmit_period(dev, 9600, rps); - timer_stop(&dev->report_timer); - sermouse_timer_on(dev, dev->report_period, 1); - ltsermouse_prompt_mode(dev, 0); - dev->report_phase = REPORT_PHASE_PREPARE; + /* Limit the reports rate according to the baud rate. */ + if (rps == 0) { + sermouse_set_period(dev, 0.0); + + dev->report_period = 0.0; + dev->continuous = 1; + } else { + /* if (rps > dev->max_rps) + rps = dev->max_rps; */ + + dev->continuous = 0; + dev->report_period = 1000000.0 / ((double) rps); + /* Actual spacing between reports. */ + } } static void -ltsermouse_switch_baud_rate(mouse_t *dev, int phase) +ltsermouse_update_report_period(mouse_t *dev) { - dev->command_pos = 0; - dev->command_phase = phase; - timer_stop(&dev->command_timer); - sermouse_timer_on(dev, 10000.0, 0); + ltsermouse_set_report_period(dev, dev->rps); + + ltsermouse_set_prompt_mode(dev, 0); + mouse_serial_log("ltsermouse_update_report_period(): %i, %i\n", dev->continuous, dev->prompt); + if (dev->continuous) + dev->state = STATE_IDLE; + else { + sermouse_transmit_report(dev, 0); + dev->state = STATE_TRANSMIT_REPORT; + } +} + +static void +ltsermouse_switch_baud_rate(mouse_t *dev, int next_state) +{ + double word_lens[FORMATS_NUM] = { + [FORMAT_BP1_ABS] = 7.0 + 1.0, /* 7 data bits + even parity */ + [FORMAT_BP1_REL] = 7.0 + 1.0, /* 7 data bits + even parity */ + [FORMAT_MM_SERIES] = 8.0 + 1.0, /* 8 data bits + odd parity */ + [FORMAT_PB_3BYTE] = 8.0, /* 8 data bits + no parity */ + [FORMAT_PB_5BYTE] = 8.0, /* 8 data bits + no parity */ + [FORMAT_MS] = 7.0, /* 7 datas bits + no parity */ + [FORMAT_HEX] = 8.0, /* 8 data bits + no parity */ + [FORMAT_MS_4BYTE] = 7.0, /* 7 datas bits + no parity */ + [FORMAT_MS_WHEEL] = 7.0 }; /* 7 datas bits + no parity */ + double word_len = word_lens[dev->format]; + + word_len += 1.0 + 2.0; /* 1 start bit + 2 stop bits */ + + // dev->max_rps = (int) floor(((double) dev->bps) / (word_len * num_words)); + + if (next_state == STATE_BAUD_RATE) + dev->transmit_period = dev->host_transmit_period; + else + dev->transmit_period = (1000000.0) / ((double) dev->bps); + + dev->min_bit_period = dev->transmit_period; + + dev->transmit_period *= word_len; + /* The transmit period for the entire report, we're going to need this in ltsermouse_set_report_period(). */ + // dev->report_transmit_period = dev->transmit_period * num_words; + + ltsermouse_set_report_period(dev, dev->rps); + + if (!dev->continuous && (next_state != STATE_BAUD_RATE)) { + if (dev->prompt) + ltsermouse_set_prompt_mode(dev, 0); + + sermouse_transmit_report(dev, 0); + } + + dev->state = next_state; +} + +static int +sermouse_next_state(mouse_t *dev) +{ + int ret = STATE_IDLE; + + if (dev->prompt || (dev->rps == 0)) + ret = STATE_IDLE; + else + ret = STATE_TRANSMIT; + + return ret; +} + +static void +ltsermouse_process_command(mouse_t *dev) +{ + int cmd_to_rps[9] = { 10, 20, 35, 70, 150, 0, -1, 100, 50 }; + uint8_t format_codes[FORMATS_NUM] = { + [FORMAT_BP1_ABS] = 0x0c, + [FORMAT_BP1_REL] = 0x06, + [FORMAT_MM_SERIES] = 0x0a, + [FORMAT_PB_3BYTE] = 0x00, + [FORMAT_PB_5BYTE] = 0x02, + [FORMAT_MS] = 0x0e, + [FORMAT_HEX] = 0x04, + [FORMAT_MS_4BYTE] = 0x08, /* Guess */ + [FORMAT_MS_WHEEL] = 0x08 }; /* Guess */ + char *copr = "\r\n(C) 2023 86Box, Revision 3.0"; + + mouse_serial_log("ltsermouse_process_command(): %02X\n", dev->ib); + dev->command = dev->ib; + + switch (dev->command) { + case 0x20: + /* Auto Baud Selection */ + dev->bps = (int) floor(1000000.0 / dev->host_transmit_period); + dev->transmit_period = dev->host_transmit_period; + + dev->buf[0] = 0x06; + sermouse_transmit(dev, 1, 0, 0); + + ltsermouse_switch_baud_rate(dev, STATE_BAUD_RATE); + break; + + case 0x4a: /* Report Rate Selection commands */ + case 0x4b: + case 0x4c: + case 0x52: + case 0x4d: + case 0x51: + case 0x4e: + case 0x4f: + dev->report_mode = dev->command; + dev->rps = cmd_to_rps[dev->command - 0x4a]; + ltsermouse_update_report_period(dev); + break; + + case 0x44: + /* Select Prompt Mode */ + dev->report_mode = dev->command; + ltsermouse_set_prompt_mode(dev, 1); + dev->state = STATE_IDLE; + break; + case 0x50: + /* Promopt to send a report (also enters Prompt Mode). */ + if (!dev->prompt) { + dev->report_mode = 0x44; + ltsermouse_set_prompt_mode(dev, 1); + } + sermouse_transmit_report(dev, 0); + dev->state = STATE_TRANSMIT_REPORT; + break; + + case 0x41: + /* Absolute Bit Pad One Packed Binary Format */ + dev->abs_x = dev->abs_y = 0; +#ifdef FALLTHROUGH_ANNOTATION + [[fallthrough]]; +#endif + case 0x42: /* Relative Bit Pad One Packed Binary Format */ + case 0x53: /* MM Series Data Format */ + case 0x54: /* Three Byte Packed Binary Format */ + case 0x55: /* Five Byte Packed Binary Format (Mouse Systems-compatible) */ + case 0x56: /* Microsoft Compatible Format */ + case 0x57: /* Hexadecimal Format */ + case 0x58: /* Microsoft Compatible Format (3+1 byte 3-button, from the FreeBSD source code) */ + if ((dev->rev >= 0x02) && ((dev->command != 0x58) || (dev->rev > 0x04))) { + dev->format = dev->command & 0x1f; + ltsermouse_switch_baud_rate(dev, sermouse_next_state(dev)); + } + break; + + case 0x2a: + if (dev->rev >= 0x03) { + /* Programmable Baud Rate Selection */ + dev->state = STATE_DATA; + } + break; + + case 0x73: + /* Status */ + dev->buf[0] = dev->prompt ? 0x4f : 0x0f; + sermouse_transmit(dev, 1, 0, 0); + break; + case 0x05: + /* Diagnostic */ + dev->buf[0] = ((mouse_buttons & 0x01) << 2) | ((mouse_buttons & 0x06) >> 1); + dev->buf[1] = dev->buf[2] = 0x00; + sermouse_transmit(dev, 3, 0, 0); + break; + + case 0x66: + if (dev->rev >= 0x20) { + /* Format and Revision Number */ + dev->buf[0] = format_codes[dev->format]; + dev->buf[0] |= 0x10; /* Revision 3.0, 0x00 would be Revision 2.0 */ + sermouse_transmit(dev, 1, 0, 0); + } + break; + + case 0x74: + /* Format and Mode in ASCII */ + if (dev->rev >= 0x03) { + dev->buf[0] = dev->format | 0x40; + dev->buf[1] = dev->report_mode; + sermouse_transmit(dev, 2, 0, 0); + } + break; + + case 0x63: + /* Copyright and Revision in ASCII */ + if (dev->rev >= 0x03) { + memcpy(&(dev->buf[0]), copr, strlen(copr) + 1); + sermouse_transmit(dev, strlen(copr) + 1, 0, 0); + } else { + memcpy(&(dev->buf[0]), copr, strlen(copr)); + sermouse_transmit(dev, strlen(copr), 0, 0); + } + dev->buf[29] = dev->rev | 0x30; + break; + + case 0x64: + /* Dormant State */ + dev->state = STATE_DORMANT; + break; + + case 0x6b: + /* Buttons - 86Box-specific command. */ + dev->state = dev->but; + break; + } +} + +static void +ltsermouse_process_data(mouse_t *dev) +{ + mouse_serial_log("ltsermouse_process_data(): %02X (command = %02X)\n", dev->ib, dev->command); + + switch(dev->command) { + case 0x2a: + switch (dev->ib) { + default: + mouse_serial_log("Serial mouse: Invalid period %02X, using 1200 bps\n", data); +#ifdef FALLTHROUGH_ANNOTATION + [[fallthrough]]; +#endif + case 0x6e: + dev->bps = 1200; + break; + case 0x6f: + dev->bps = 2400; + break; + case 0x70: + dev->bps = 4800; + break; + case 0x71: + dev->bps = 9600; + break; + } + ltsermouse_switch_baud_rate(dev, (dev->prompt || dev->continuous) ? STATE_IDLE : STATE_TRANSMIT_REPORT); + break; + default: + dev->state = STATE_IDLE; + break; + } +} + +static void +sermouse_reset(mouse_t *dev, int callback) +{ + sermouse_set_period(dev, 0.0); + + dev->bps = 1200; + dev->rps = 0; + dev->prompt = 0; + if (dev->id[0] == 'H') + dev->format = FORMAT_MSYSTEMS; + else switch (dev->but) { + default: + case 2: + dev->format = FORMAT_MS; + break; + case 3: + dev->format = (dev->type == MOUSE_TYPE_LT3BUTTON) ? FORMAT_MS : FORMAT_MS_4BYTE; + break; + case 4: + dev->format = FORMAT_MS_WHEEL; + break; + } + + ltsermouse_switch_baud_rate(dev, callback ? STATE_TRANSMIT : STATE_IDLE); +} + +static void +sermouse_timer(void *priv) +{ + mouse_t *dev = (mouse_t *) priv; +#ifdef ENABLE_MOUSE_SERIAL_LOG + int old_state = dev->state; +#endif + + switch (dev->state) { + case STATE_RESET: + /* All three mice default to continuous reporting. */ + sermouse_reset(dev, 0); + break; + case STATE_DATA: + ltsermouse_process_data(dev); + break; + case STATE_COMMAND: + ltsermouse_process_command(dev); + break; + case STATE_SKIP_REPORT: + if (!dev->prompt && !dev->continuous) + sermouse_transmit_report(dev, (dev->state == STATE_TRANSMIT_REPORT)); + else + dev->state = STATE_IDLE; + break; + case STATE_TRANSMIT_REPORT: + case STATE_TRANSMIT: + case STATE_BAUD_RATE: + sermouse_transmit_byte(dev, 1); + + if (dev->buf_pos == 0) { + if (!dev->prompt && !dev->continuous) + sermouse_transmit_report(dev, (dev->state == STATE_TRANSMIT_REPORT)); + else + dev->state = STATE_IDLE; + } + break; + default: + break; + } + + mouse_serial_log("sermouse_timer(): %02i -> %02i\n", old_state, dev->state); } static void @@ -637,125 +858,42 @@ ltsermouse_write(UNUSED(struct serial_s *serial), void *priv, uint8_t data) { mouse_t *dev = (mouse_t *) priv; - /* Stop reporting when we're processing a command. */ - dev->report_phase = REPORT_PHASE_PREPARE; + mouse_serial_log("ltsermouse_write(): %02X\n", data); - if (dev->want_data) - switch (dev->want_data) { - case 0x2A: - dev->data_len--; - dev->want_data = 0; - switch (data) { - default: - mouse_serial_log("Serial mouse: Invalid period %02X, using 1200 bps\n", data); + dev->ib = data; + + switch (dev->state) { + case STATE_RESET: + case STATE_BAUD_RATE: + break; + case STATE_TRANSMIT_REPORT: + case STATE_TRANSMIT: + case STATE_SKIP_REPORT: + sermouse_set_period(dev, 0.0); #ifdef FALLTHROUGH_ANNOTATION - [[fallthrough]]; + [[fallthrough]]; #endif - case 0x6E: - dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); - break; - case 0x6F: - dev->transmit_period = sermouse_transmit_period(dev, 2400, -1); - break; - case 0x70: - dev->transmit_period = sermouse_transmit_period(dev, 4800, -1); - break; - case 0x71: - dev->transmit_period = sermouse_transmit_period(dev, 9600, -1); - break; - } - ltsermouse_switch_baud_rate(dev, PHASE_BAUD_RATE); - break; - default: - break; - } - else - switch (data) { - case 0x20: - sermouse_timer_on(dev, 0.0, 1); - dev->transmit_period = dev->auto_period; - ltsermouse_switch_baud_rate(dev, PHASE_ACK); - break; - case 0x2A: - sermouse_timer_on(dev, 0.0, 1); - dev->want_data = data; - dev->data_len = 1; - break; - case 0x44: /* Set prompt mode */ - ltsermouse_prompt_mode(dev, 1); - break; - case 0x50: - if (!dev->prompt) - ltsermouse_prompt_mode(dev, 1); - sermouse_update_data(dev); - ltsermouse_command_phase(dev, PHASE_DATA); - break; - case 0x73: /* Status */ - ltsermouse_command_phase(dev, PHASE_STATUS); - break; - case 0x4A: /* Report Rate Selection commands */ - ltsermouse_set_report_period(dev, 10); - break; - case 0x4B: - ltsermouse_set_report_period(dev, 20); - break; - case 0x4C: - ltsermouse_set_report_period(dev, 35); - break; - case 0x52: - ltsermouse_set_report_period(dev, 50); - break; - case 0x4D: - ltsermouse_set_report_period(dev, 70); - break; - case 0x51: - ltsermouse_set_report_period(dev, 100); - break; - case 0x4E: - ltsermouse_set_report_period(dev, 150); - break; - case 0x4F: - ltsermouse_prompt_mode(dev, 0); - dev->report_period = 0; - timer_stop(&dev->report_timer); - dev->report_phase = REPORT_PHASE_PREPARE; - sermouse_report_timer((void *) dev); - break; - case 0x41: - dev->format = 6; /* Aboslute Bit Pad One Format */ - dev->abs_x = dev->abs_y = 0; - break; - case 0x42: - dev->format = 3; /* Relative Bit Pad One Format */ - break; - case 0x53: - dev->format = 5; /* MM Series Format */ - break; - case 0x54: - dev->format = 1; /* Three Byte Packed Binary Format */ - break; - case 0x55: /* This is the Mouse Systems-compatible format */ - dev->format = 0; /* Five Byte Packed Binary Format */ - break; - case 0x56: - dev->format = 7; /* Microsoft Compatible Format */ - break; - case 0x57: - dev->format = 2; /* Hexadecimal Format */ - break; - case 0x05: - ltsermouse_command_phase(dev, PHASE_DIAGNOSTIC); - break; - case 0x66: - ltsermouse_command_phase(dev, PHASE_FORMAT_AND_REVISION); - break; - case 0x6B: - ltsermouse_command_phase(dev, PHASE_BUTTONS); - break; + default: + dev->state = STATE_COMMAND; +#ifdef FALLTHROUGH_ANNOTATION + [[fallthrough]]; +#endif + case STATE_DATA: + sermouse_timer(dev); + break; + } +} - default: - break; - } +/* Callback from serial driver: RTS was toggled. */ +static void +sermouse_callback(UNUSED(struct serial_s *serial), void *priv) +{ + mouse_t *dev = (mouse_t *) priv; + + sermouse_reset(dev, 1); + + memcpy(dev->buf, dev->id, dev->id_len); + sermouse_transmit(dev, dev->id_len, 0, 0); } static void @@ -763,7 +901,7 @@ ltsermouse_transmit_period(UNUSED(serial_t *serial), void *priv, double transmit { mouse_t *dev = (mouse_t *) priv; - dev->auto_period = transmit_period; + dev->host_transmit_period = transmit_period; } static void @@ -771,18 +909,8 @@ sermouse_speed_changed(void *priv) { mouse_t *dev = (mouse_t *) priv; - if (dev->report_enabled) { - timer_stop(&dev->report_timer); - if (dev->report_phase == REPORT_PHASE_TRANSMIT) - sermouse_timer_on(dev, dev->transmit_period, 1); - else - sermouse_timer_on(dev, sermouse_report_period(dev), 1); - } - - if (dev->command_enabled) { - timer_stop(&dev->command_timer); - sermouse_timer_on(dev, dev->transmit_period, 0); - } + if (dev->cur_period != 0.0) + sermouse_set_period(dev, dev->cur_period); } static void @@ -802,26 +930,36 @@ static void * sermouse_init(const device_t *info) { mouse_t *dev; + void (*rcr_callback)(struct serial_s *serial, void *p); + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data); + void (*transmit_period_callback)(struct serial_s *serial, void *p, double transmit_period); dev = (mouse_t *) malloc(sizeof(mouse_t)); memset(dev, 0x00, sizeof(mouse_t)); dev->name = info->name; dev->but = device_get_config_int("buttons"); + dev->rev = device_get_config_int("revision"); + + if (info->local == 0) + dev->rts_toggle = 0; + else + dev->rts_toggle = device_get_config_int("rts_toggle"); + if (dev->but > 2) dev->flags |= FLAG_3BTN; if (info->local == MOUSE_TYPE_MSYSTEMS) { - dev->on_change = 1; dev->format = 0; dev->type = info->local; dev->id_len = 1; dev->id[0] = 'H'; } else { - dev->on_change = !info->local; dev->format = 7; dev->status = 0x0f; dev->id_len = 1; dev->id[0] = 'M'; + if (info->local) + dev->rev = device_get_config_int("revision"); switch (dev->but) { default: case 2: @@ -841,33 +979,22 @@ sermouse_init(const device_t *info) } } - dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); - dev->auto_period = dev->transmit_period; - - /* Default: Continuous reporting = no delay between reports. */ - dev->report_phase = REPORT_PHASE_PREPARE; - dev->report_period = 0; - - /* Default: Doing nothing - command transmit timer deactivated. */ - dev->command_phase = PHASE_IDLE; - dev->port = device_get_config_int("port"); /* Attach a serial port to the mouse. */ - if (info->local) - dev->serial = serial_attach_ex(dev->port, sermouse_callback, ltsermouse_write, ltsermouse_transmit_period, NULL, dev); - else - dev->serial = serial_attach(dev->port, sermouse_callback, NULL, dev); + rcr_callback = dev->rts_toggle ? sermouse_callback : NULL; + dev_write = (info->local == 1) ? ltsermouse_write : NULL; + transmit_period_callback = (info->local == 1) ? ltsermouse_transmit_period : NULL; + + dev->serial = serial_attach_ex(dev->port, rcr_callback, dev_write, + transmit_period_callback, NULL, dev); mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port + 1); - timer_add(&dev->report_timer, sermouse_report_timer, dev, 0); - timer_add(&dev->command_timer, sermouse_command_timer, dev, 0); + timer_add(&dev->timer, sermouse_timer, dev, 0); - if (info->local == MOUSE_TYPE_MSYSTEMS) { - sermouse_timer_on(dev, dev->transmit_period, 1); - dev->report_enabled = 1; - } + /* The five second delay allows the mouse to execute internal initializations. */ + sermouse_set_period(dev, 5000000.0); /* Tell them how many buttons we have. */ mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); @@ -876,6 +1003,49 @@ sermouse_init(const device_t *info) return dev; } +static const device_config_t msssermouse_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 = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "" } + } + }, + { + .name = "rts_toggle", + .description = "RTS toggle", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + static const device_config_t mssermouse_config[] = { // clang-format off { @@ -945,6 +1115,29 @@ static const device_config_t ltsermouse_config[] = { { .description = "" } } }, + { + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "LOGIMOUSE R7 1.0", .value = 1 }, + { .description = "LOGIMOUSE R7 2.0", .value = 2 }, + { .description = "LOGIMOUSE C7 3.0", .value = 3 }, + { .description = "Logitech MouseMan", .value = 4 }, + { .description = "" } + } + }, + { + .name = "rts_toggle", + .description = "Microsoft-compatible RTS toggle", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -960,7 +1153,7 @@ const device_t mouse_mssystems_device = { { .poll = sermouse_poll }, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, - .config = mssermouse_config + .config = msssermouse_config }; const device_t mouse_msserial_device = { diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index 839c0f11a..d8d609fbb 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -20,6 +20,11 @@ #ifndef EMU_MOUSE_H #define EMU_MOUSE_H +#ifndef __cplusplus +/* Yes, a big no-no, but I'm saving myself time here. */ +#include +#endif + #define MOUSE_TYPE_NONE 0 /* no mouse configured */ #define MOUSE_TYPE_INTERNAL 1 /* machine has internal mouse */ #define MOUSE_TYPE_LOGIBUS 2 /* Logitech/ATI Bus Mouse */ @@ -39,20 +44,26 @@ #define MOUSE_TYPE_ONBOARD 0x80 /* Mouse is an on-board version of one of the above. */ + #ifdef __cplusplus extern "C" { +#else +extern atomic_int mouse_x; +extern atomic_int mouse_y; +extern atomic_int mouse_z; +extern atomic_int mouse_buttons; #endif extern int mouse_type; -extern int mouse_x; -extern int mouse_y; -extern int mouse_z; extern int mouse_mode; /* 1 = Absolute, 0 = Relative */ +extern int mouse_timed; /* 1 = Timed, 0 = Constant */ extern int mouse_tablet_in_proximity; extern double mouse_x_abs; extern double mouse_y_abs; -extern int mouse_buttons; extern int tablet_tool_type; +extern double mouse_sensitivity; +extern double mouse_x_error; +extern double mouse_y_error; #ifdef EMU_DEVICE_H extern const device_t *mouse_get_device(int mouse); @@ -79,11 +90,16 @@ extern void mouse_set_buttons(int buttons); extern void mouse_set_poll_ex(void (*poll_ex)(void)); extern void mouse_process(void); extern void mouse_set_poll(int (*f)(int, int, int, int, void *), void *); -extern void mouse_poll(void); extern void mouse_bus_set_irq(void *priv, int irq); extern void mouse_set_sample_rate(double new_rate); +extern void mouse_scale(int x, int y); +extern void mouse_scale_x(int x); +extern void mouse_scale_y(int y); +extern void mouse_set_z(int z); +extern void mouse_set_buttons_ex(int b); +extern int mouse_get_buttons_ex(void); extern char *mouse_get_name(int mouse); extern char *mouse_get_internal_name(int mouse); diff --git a/src/io.c b/src/io.c index b9db1e73c..4a4d293e2 100644 --- a/src/io.c +++ b/src/io.c @@ -318,8 +318,12 @@ inb(uint16_t port) amstrad_latch = AMSTRAD_SW9 | 0x80000000; } - if (!found) - cycles -= io_delay; + if (!found) { + if (is286) + cycles -= io_delay; + else + sub_cycles(io_delay); + } /* TriGem 486-BIOS MHz output. */ #if 0 @@ -327,7 +331,16 @@ inb(uint16_t port) ret = 0xfe; #endif - io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + /* if (port == 0x23) + ret = 0x00; */ + + if (port == 0x7f) + ret = 0x00; + + // if ((port != 0x42) && (port != 0x61) && (port != 0x3b4) && (port != 0x3ba) && (port != 0x3da)) { + if (((port >= 0xcf8) && (port <= 0xcff)) || ((port >= 0xc000) && (port <= 0xcfff))) { + io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + } return ret; } @@ -362,14 +375,21 @@ outb(uint16_t port, uint8_t val) } if (!found) { - cycles -= io_delay; + if (is286) + cycles -= io_delay; + else + sub_cycles(io_delay); + #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); #endif } - io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + // if ((port != 0x43) && (port != 0xea)) { + if (((port >= 0xcf8) && (port <= 0xcff)) || ((port >= 0xc000) && (port <= 0xcfff))) { + io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + } return; } @@ -430,10 +450,16 @@ inw(uint16_t port) amstrad_latch = AMSTRAD_SW9 | 0x80000000; } - if (!found) - cycles -= io_delay; + if (!found) { + if (is286) + cycles -= io_delay; + else + sub_cycles(io_delay); + } - io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + if (((port >= 0xcf8) && (port <= 0xcff)) || ((port >= 0xc000) && (port <= 0xcfff))) { + io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + } return ret; } @@ -481,14 +507,21 @@ outw(uint16_t port, uint16_t val) } if (!found) { - cycles -= io_delay; + if (is286) + cycles -= io_delay; + else + sub_cycles(io_delay); + #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); #endif } - io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + // if (port != 0xea) { + if (((port >= 0xcf8) && (port <= 0xcff)) || ((port >= 0xc000) && (port <= 0xcfff))) { + io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + } return; } @@ -580,7 +613,9 @@ inl(uint16_t port) if (!found) cycles -= io_delay; - io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + if (((port >= 0xcf8) && (port <= 0xcff)) || ((port >= 0xc000) && (port <= 0xcfff))) { + io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + } return ret; } @@ -651,7 +686,9 @@ outl(uint16_t port, uint32_t val) #endif } - io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + if (((port >= 0xcf8) && (port <= 0xcff)) || ((port >= 0xc000) && (port <= 0xcfff))) { + io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + } return; } diff --git a/src/qt/evdev_mouse.cpp b/src/qt/evdev_mouse.cpp index 4b487e65d..b5f68a286 100644 --- a/src/qt/evdev_mouse.cpp +++ b/src/qt/evdev_mouse.cpp @@ -37,21 +37,6 @@ static std::vector> evdev_mice; static std::atomic stopped = false; static QThread *evdev_thread; -static std::atomic evdev_mouse_rel_x = 0, evdev_mouse_rel_y = 0; - -void -evdev_mouse_poll() -{ - if (!evdev_mice.size() || !mouse_capture) { - evdev_mouse_rel_x = 0; - evdev_mouse_rel_y = 0; - return; - } - mouse_x = evdev_mouse_rel_x; - mouse_y = evdev_mouse_rel_y; - evdev_mouse_rel_x = evdev_mouse_rel_y = 0; -} - void evdev_thread_func() { @@ -67,11 +52,11 @@ evdev_thread_func() struct input_event ev; if (pfds[i].revents & POLLIN) { while (libevdev_next_event(evdev_mice[i].second, LIBEVDEV_READ_FLAG_NORMAL, &ev) == 0) { - if (ev.type == EV_REL && mouse_capture) { + if (evdev_mice.size() && (ev.type == EV_REL) && mouse_capture) { if (ev.code == REL_X) - evdev_mouse_rel_x += ev.value; + mouse_scale_x(ev.value); if (ev.code == REL_Y) - evdev_mouse_rel_y += ev.value; + mouse_scale_y(ev.value); } } } diff --git a/src/qt/evdev_mouse.hpp b/src/qt/evdev_mouse.hpp index 7681771c6..0b0b8b26f 100644 --- a/src/qt/evdev_mouse.hpp +++ b/src/qt/evdev_mouse.hpp @@ -1,4 +1,3 @@ #ifdef EVDEV_INPUT void evdev_init(); -void evdev_mouse_poll(); #endif diff --git a/src/qt/macos_event_filter.mm b/src/qt/macos_event_filter.mm index 6f84beee5..5e276679f 100644 --- a/src/qt/macos_event_filter.mm +++ b/src/qt/macos_event_filter.mm @@ -17,13 +17,6 @@ extern int mouse_capture; extern void plat_mouse_capture(int); } -typedef struct mouseinputdata { - int deltax, deltay, deltaz; - int mousebuttons; -} mouseinputdata; - -static mouseinputdata mousedata; - CocoaEventFilter::~CocoaEventFilter() { } @@ -31,6 +24,8 @@ CocoaEventFilter::~CocoaEventFilter() bool CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) { + int b = 0; + if (mouse_capture) { if (eventType == "mac_generic_NSEvent") { NSEvent *event = (NSEvent *) message; @@ -38,12 +33,11 @@ CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, || [event type] == NSEventTypeLeftMouseDragged || [event type] == NSEventTypeRightMouseDragged || [event type] == NSEventTypeOtherMouseDragged) { - mousedata.deltax += [event deltaX]; - mousedata.deltay += [event deltaY]; + mouse_scale([event deltaX], [event deltaY]); return true; } if ([event type] == NSEventTypeScrollWheel) { - mousedata.deltaz += [event deltaY]; + mouse_set_z([event deltaY]); return true; } switch ([event type]) { @@ -51,27 +45,32 @@ CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, return false; case NSEventTypeLeftMouseDown: { - mousedata.mousebuttons |= 1; + b = mouse_get_buttons_ex() | 1; + mouse_set_buttons_ex(b); break; } case NSEventTypeLeftMouseUp: { - mousedata.mousebuttons &= ~1; + b = mouse_get_buttons_ex() & ~1; + mouse_set_buttons_ex(b); break; } case NSEventTypeRightMouseDown: { - mousedata.mousebuttons |= 2; + b = mouse_get_buttons_ex() | 2; + mouse_set_buttons_ex(b); break; } case NSEventTypeRightMouseUp: { - mousedata.mousebuttons &= ~2; + b = mouse_get_buttons_ex() & ~2; + mouse_set_buttons_ex(b); break; } case NSEventTypeOtherMouseDown: { - mousedata.mousebuttons |= 4; + b = mouse_get_buttons_ex() | 4; + mouse_set_buttons_ex(b); break; } case NSEventTypeOtherMouseUp: @@ -80,7 +79,8 @@ CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, plat_mouse_capture(0); return true; } - mousedata.mousebuttons &= ~4; + b = mouse_get_buttons_ex() & ~4; + mouse_set_buttons_ex(b); break; } } @@ -89,13 +89,3 @@ CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, } return false; } - -extern "C" void -macos_poll_mouse() -{ - mouse_x = mousedata.deltax; - mouse_y = mousedata.deltay; - mouse_z = mousedata.deltaz; - mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; - mouse_buttons = mousedata.mousebuttons; -} diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index daf13f72d..04fb01ffb 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -256,7 +256,6 @@ main(int argc, char *argv[]) auto rawInputFilter = WindowsRawInputFilter::Register(main_window); if (rawInputFilter) { app.installNativeEventFilter(rawInputFilter.get()); - QObject::connect(main_window, &MainWindow::pollMouse, (WindowsRawInputFilter *) rawInputFilter.get(), &WindowsRawInputFilter::mousePoll, Qt::DirectConnection); main_window->setSendKeyboardInput(false); } #endif diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ef39765dd..9d3ef7b48 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -253,8 +253,6 @@ MainWindow::MainWindow(QWidget *parent) emit updateMenuResizeOptions(); - connect(this, &MainWindow::pollMouse, ui->stackedWidget, &RendererStack::mousePoll, Qt::DirectConnection); - connect(this, &MainWindow::setMouseCapture, this, [this](bool state) { mouse_capture = state ? 1 : 0; qt_mouse_capture(mouse_capture); @@ -764,7 +762,6 @@ MainWindow::initRendererMonitorSlot(int monitor_index) secondaryRenderer->switchRenderer((RendererStack::Renderer) vid_api); secondaryRenderer->setMouseTracking(true); } - connect(this, &MainWindow::pollMouse, secondaryRenderer.get(), &RendererStack::mousePoll, Qt::DirectConnection); } } @@ -890,6 +887,9 @@ MainWindow::on_actionSettings_triggered() Settings settings(this); settings.setModal(true); settings.setWindowModality(Qt::WindowModal); + settings.setWindowFlag(Qt::CustomizeWindowHint, true); + settings.setWindowFlag(Qt::WindowTitleHint, true); + settings.setWindowFlag(Qt::WindowSystemMenuHint, false); settings.exec(); switch (settings.result()) { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index d5a6b1967..7e4032a31 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -39,7 +39,6 @@ signals: void paint(const QImage &image); void resizeContents(int w, int h); void resizeContentsMonitor(int w, int h, int monitor_index); - void pollMouse(); void statusBarMessage(const QString &msg); void updateStatusBarPanes(); void updateStatusBarActivity(int tag, bool active); diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index ee87dccb8..62f859fa4 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -49,26 +49,19 @@ extern "C" { #include <86box/86box.h> #include <86box/config.h> -#include <86box/mouse.h> #include <86box/plat.h> #include <86box/video.h> - -double mouse_sensitivity = 1.0; -double mouse_x_error = 0.0, mouse_y_error = 0.0; +#include <86box/mouse.h> } struct mouseinputdata { - atomic_int deltax; - atomic_int deltay; - atomic_int deltaz; - atomic_int mousebuttons; atomic_bool mouse_tablet_in_proximity; + std::atomic x_abs; std::atomic y_abs; }; static mouseinputdata mousedata; -extern "C" void macos_poll_mouse(); extern MainWindow *main_window; RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) @@ -94,29 +87,21 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) # ifdef WAYLAND if (!stricmp(mouse_type, "wayland")) { wl_init(); - this->mouse_poll_func = wl_mouse_poll; this->mouse_capture_func = wl_mouse_capture; this->mouse_uncapture_func = wl_mouse_uncapture; } # endif # ifdef EVDEV_INPUT - if (!stricmp(mouse_type, "evdev")) { + if (!stricmp(mouse_type, "evdev")) evdev_init(); - this->mouse_poll_func = evdev_mouse_poll; - } # endif if (!stricmp(mouse_type, "xinput2")) { extern void xinput2_init(); - extern void xinput2_poll(); extern void xinput2_exit(); xinput2_init(); - this->mouse_poll_func = xinput2_poll; this->mouse_exit_func = xinput2_exit; } #endif -#ifdef __APPLE__ - this->mouse_poll_func = macos_poll_mouse; -#endif } RendererStack::~RendererStack() @@ -149,49 +134,25 @@ RendererStack::mousePoll() { if (m_monitor_index >= 1) { if (mouse_mode >= 1) { - mouse_x_abs = mousedata.x_abs; - mouse_y_abs = mousedata.y_abs; - if (!mouse_tablet_in_proximity) { + mouse_x_abs = mousedata.x_abs; + mouse_y_abs = mousedata.y_abs; + if (!mouse_tablet_in_proximity) mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; - } - if (mousedata.mouse_tablet_in_proximity) { - mouse_buttons = mousedata.mousebuttons; - } } return; } #ifdef Q_OS_WINDOWS if (mouse_mode == 0) { - mouse_x_abs = mousedata.x_abs; - mouse_y_abs = mousedata.y_abs; + mouse_x_abs = mousedata.x_abs; + mouse_y_abs = mousedata.y_abs; return; } #endif -#ifndef __APPLE__ - mouse_x = mousedata.deltax; - mouse_y = mousedata.deltay; - mouse_z = mousedata.deltaz; - mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; - mouse_buttons = mousedata.mousebuttons; - - if (this->mouse_poll_func) -#endif - this->mouse_poll_func(); - mouse_x_abs = mousedata.x_abs; mouse_y_abs = mousedata.y_abs; mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; - - double scaled_x = mouse_x * mouse_sensitivity + mouse_x_error; - double scaled_y = mouse_y * mouse_sensitivity + mouse_y_error; - - mouse_x = static_cast(scaled_x); - mouse_y = static_cast(scaled_y); - - mouse_x_error = scaled_x - mouse_x; - mouse_y_error = scaled_y - mouse_y; } int ignoreNextMouseEvent = 1; @@ -212,8 +173,9 @@ RendererStack::mouseReleaseEvent(QMouseEvent *event) isMouseDown &= ~1; return; } - if (mouse_capture || mouse_mode >= 1) { - mousedata.mousebuttons &= ~event->button(); + if (mouse_capture || (mouse_mode >= 1)) { + if ((mouse_mode >= 1) && ((m_monitor_index < 1) || mousedata.mouse_tablet_in_proximity)) + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~event->button()); } isMouseDown &= ~1; } @@ -222,8 +184,9 @@ void RendererStack::mousePressEvent(QMouseEvent *event) { isMouseDown |= 1; - if (mouse_capture || mouse_mode >= 1) { - mousedata.mousebuttons |= event->button(); + if (mouse_capture || (mouse_mode >= 1)) { + if ((mouse_mode >= 1) && ((m_monitor_index < 1) || mousedata.mouse_tablet_in_proximity)) + mouse_set_buttons_ex(mouse_get_buttons_ex() | event->button()); } event->accept(); } @@ -231,9 +194,7 @@ RendererStack::mousePressEvent(QMouseEvent *event) void RendererStack::wheelEvent(QWheelEvent *event) { - if (mouse_capture) { - mousedata.deltaz += event->pixelDelta().y(); - } + mouse_set_z(event->pixelDelta().y()); } void @@ -258,8 +219,12 @@ RendererStack::mouseMoveEvent(QMouseEvent *event) event->accept(); return; } - mousedata.deltax += event->pos().x() - oldPos.x(); - mousedata.deltay += event->pos().y() - oldPos.y(); + +#if defined __unix__ && !defined __HAIKU__ + if (!stricmp(mouse_type, "wayland")) + mouse_scale(event->pos().x() - oldPos.x(), event->pos().y() - oldPos.y()); +#endif + if (QApplication::platformName() == "eglfs") { leaveEvent((QEvent *) event); ignoreNextMouseEvent--; diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index df52a9542..7c0820190 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -82,9 +82,9 @@ public: rendererWindow->onResize(width, height); } - void (*mouse_poll_func)() = nullptr; void (*mouse_capture_func)(QWindow *window) = nullptr; void (*mouse_uncapture_func)() = nullptr; + void (*mouse_exit_func)() = nullptr; signals: diff --git a/src/qt/qt_sdl.c b/src/qt/qt_sdl.c index 6d04acd25..166ea88fa 100644 --- a/src/qt/qt_sdl.c +++ b/src/qt/qt_sdl.c @@ -198,12 +198,6 @@ static const uint16_t sdl_to_xt[0x200] = { [SDL_SCANCODE_NONUSBACKSLASH] = 0x56, }; -typedef struct mouseinputdata { - int deltax, deltay, deltaz; - int mousebuttons; -} mouseinputdata; -static mouseinputdata mousedata; - // #define ENABLE_SDL_LOG 3 #ifdef ENABLE_SDL_LOG int sdl_do_log = ENABLE_SDL_LOG; @@ -620,16 +614,14 @@ sdl_main() event.wheel.x *= -1; event.wheel.y *= -1; } - mousedata.deltaz = event.wheel.y; + mouse_set_z(event.wheel.y); } break; } case SDL_MOUSEMOTION: { - if (mouse_capture || video_fullscreen) { - mousedata.deltax += event.motion.xrel; - mousedata.deltay += event.motion.yrel; - } + if (mouse_capture || video_fullscreen) + mouse_scale(event.motion.xrel, event.motion.yrel); break; } case SDL_MOUSEBUTTONDOWN: @@ -660,10 +652,10 @@ sdl_main() buttonmask = 4; break; } - if (event.button.state == SDL_PRESSED) { - mousedata.mousebuttons |= buttonmask; - } else - mousedata.mousebuttons &= ~buttonmask; + if (event.button.state == SDL_PRESSED) + mouse_set_buttons_ex(mouse_get_buttons_ex() | buttonmask); + else + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~buttonmask); } break; } @@ -714,13 +706,3 @@ sdl_mouse_capture(int on) { SDL_SetRelativeMouseMode((SDL_bool) on); } - -void -sdl_mouse_poll() -{ - mouse_x = mousedata.deltax; - mouse_y = mousedata.deltay; - mouse_z = mousedata.deltaz; - mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; - mouse_buttons = mousedata.mousebuttons; -} diff --git a/src/qt/qt_sdl.h b/src/qt/qt_sdl.h index 29804c278..f9709c857 100644 --- a/src/qt/qt_sdl.h +++ b/src/qt/qt_sdl.h @@ -68,6 +68,5 @@ enum sdl_main_status { extern enum sdl_main_status sdl_main(); extern void sdl_mouse_capture(int on); -extern void sdl_mouse_poll(); #endif /*WIN_SDL_H*/ diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 22dad3fa1..47e6b48a2 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -88,12 +88,6 @@ qt_blit(int x, int y, int w, int h, int monitor_index) main_window->blitToWidget(x, y, w, h, monitor_index); } -void -mouse_poll() -{ - main_window->pollMouse(); -} - extern "C" int vid_resize; void plat_resize_request(int w, int h, int monitor_index) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 73eea9ad8..f75c11698 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -35,6 +35,8 @@ #include +#include + #include #include <86box/keyboard.h> @@ -338,85 +340,73 @@ void WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) { RAWMOUSE state = raw->data.mouse; - static int x; - static int y; + static int x, delta_x; + static int y, delta_y; + static int b, delta_z; + + pclog("WindowsRawInputFilter::mouse_handle()\n"); + + b = mouse_get_buttons_ex(); /* read mouse buttons and wheel */ if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) - buttons |= 1; + b |= 1; else if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) - buttons &= ~1; + b &= ~1; if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) - buttons |= 4; + b |= 4; else if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) - buttons &= ~4; + b &= ~4; if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) - buttons |= 2; + b |= 2; else if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) - buttons &= ~2; + b &= ~2; if (state.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) - buttons |= 8; + b |= 8; else if (state.usButtonFlags & RI_MOUSE_BUTTON_4_UP) - buttons &= ~8; + b &= ~8; if (state.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) - buttons |= 16; + b |= 16; else if (state.usButtonFlags & RI_MOUSE_BUTTON_5_UP) - buttons &= ~16; - + b &= ~16; + + mouse_set_buttons_ex(b); + if (state.usButtonFlags & RI_MOUSE_WHEEL) { - dwheel += (SHORT) state.usButtonData / 120; - } + delta_z = (SHORT) state.usButtonData / 120; + mouse_set_z(delta_z); + } else + delta_z = 0; if (state.usFlags & MOUSE_MOVE_ABSOLUTE) { /* absolute mouse, i.e. RDP or VNC * seems to work fine for RDP on Windows 10 * Not sure about other environments. */ - dx += (state.lLastX - x) / 25; - dy += (state.lLastY - y) / 25; + delta_x = (state.lLastX - x) / 25; + delta_y = (state.lLastY - y) / 25; x = state.lLastX; y = state.lLastY; } else { /* relative mouse, i.e. regular mouse */ - dx += state.lLastX; - dy += state.lLastY; + delta_x = state.lLastX; + delta_y = state.lLastY; } - HWND wnd = (HWND) window->winId(); + + mouse_scale(delta_x, delta_y); + + HWND wnd = (HWND)window->winId(); RECT rect; GetWindowRect(wnd, &rect); int left = rect.left + (rect.right - rect.left) / 2; - int top = rect.top + (rect.bottom - rect.top) / 2; + int top = rect.top + (rect.bottom - rect.top) / 2; SetCursorPos(left, top); } - -void -WindowsRawInputFilter::mousePoll() -{ - if (mouse_mode >= 1) return; - if (mouse_capture || video_fullscreen) { - static int b = 0; - - if (dx != 0 || dy != 0 || dwheel != 0) { - mouse_x += dx; - mouse_y += dy; - mouse_z = dwheel; - - dx = 0; - dy = 0; - dwheel = 0; - } - - if (b != buttons) { - mouse_buttons = buttons; - b = buttons; - } - } -} diff --git a/src/qt/qt_winrawinputfilter.hpp b/src/qt/qt_winrawinputfilter.hpp index 81b2c0d48..f687164ca 100644 --- a/src/qt/qt_winrawinputfilter.hpp +++ b/src/qt/qt_winrawinputfilter.hpp @@ -59,9 +59,6 @@ public: ~WindowsRawInputFilter(); -public slots: - void mousePoll(); - private: MainWindow *window; uint16_t scancode_map[768]; diff --git a/src/qt/wl_mouse.cpp b/src/qt/wl_mouse.cpp index 789712de5..5d6d95a0a 100644 --- a/src/qt/wl_mouse.cpp +++ b/src/qt/wl_mouse.cpp @@ -26,6 +26,7 @@ #include extern "C" { +#include <86box/mouse.h> #include <86box/plat.h> } @@ -34,28 +35,12 @@ static zwp_relative_pointer_v1 *rel_pointer = nullptr; static zwp_pointer_constraints_v1 *conf_pointer_interface = nullptr; static zwp_locked_pointer_v1 *conf_pointer = nullptr; -static int rel_mouse_x = 0; -static int rel_mouse_y = 0; static bool wl_init_ok = false; void rel_mouse_event(void *data, zwp_relative_pointer_v1 *zwp_relative_pointer_v1, uint32_t tstmp, uint32_t tstmpl, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_real, wl_fixed_t dy_real) { - rel_mouse_x += wl_fixed_to_int(dx_real); - rel_mouse_y += wl_fixed_to_int(dy_real); -} - -extern "C" { -extern int mouse_x, mouse_y; -} - -void -wl_mouse_poll() -{ - mouse_x = rel_mouse_x; - mouse_y = rel_mouse_y; - rel_mouse_x = 0; - rel_mouse_y = 0; + mouse_scale(wl_fixed_to_int(dx_real), wl_fixed_to_int(dy_real)); } static struct zwp_relative_pointer_v1_listener rel_listener = { diff --git a/src/qt/wl_mouse.hpp b/src/qt/wl_mouse.hpp index 25d4de66c..e1751fd82 100644 --- a/src/qt/wl_mouse.hpp +++ b/src/qt/wl_mouse.hpp @@ -1,5 +1,4 @@ class QWindow; void wl_mouse_capture(QWindow *window); void wl_mouse_uncapture(); -void wl_mouse_poll(); void wl_init(); diff --git a/src/qt/xinput2_mouse.cpp b/src/qt/xinput2_mouse.cpp index dafa4ffda..1be6ec826 100644 --- a/src/qt/xinput2_mouse.cpp +++ b/src/qt/xinput2_mouse.cpp @@ -48,7 +48,7 @@ static Display *disp = nullptr; static QThread *procThread = nullptr; static XIEventMask ximask; static std::atomic exitfromthread = false; -static std::atomic xi2_mouse_x = 0, xi2_mouse_y = 0, xi2_mouse_abs_x = 0, xi2_mouse_abs_y = 0; +static std::atomic xi2_mouse_abs_x = 0, xi2_mouse_abs_y = 0; static int xi2opcode = 0; static double prev_coords[2] = { 0.0 }; static Time prev_time = 0; @@ -168,9 +168,9 @@ common_motion: if ((v->mode == XIModeRelative) && (rawev->sourceid != xtest_pointer)) { /* Set relative coordinates. */ if (axis == 0) - xi2_mouse_x = xi2_mouse_x + coords[axis]; + mouse_scale_x(coords[axis]); else - xi2_mouse_y = xi2_mouse_y + coords[axis]; + mouse_scale_y(coords[axis]); } else { /* Convert absolute value range to pixel granularity, then to relative coordinates. */ int disp_screen = XDefaultScreen(disp); @@ -188,7 +188,7 @@ common_motion: } if (xi2_mouse_abs_x != 0) - xi2_mouse_x = xi2_mouse_x + (abs_div - xi2_mouse_abs_x); + mouse_scale_x(abs_div - xi2_mouse_abs_x); xi2_mouse_abs_x = abs_div; } else { if (v->mode == XIModeRelative) { @@ -202,7 +202,7 @@ common_motion: } if (xi2_mouse_abs_y != 0) - xi2_mouse_y = xi2_mouse_y + (abs_div - xi2_mouse_abs_y); + mouse_scale_y(abs_div - xi2_mouse_abs_y); xi2_mouse_abs_y = abs_div; } } @@ -273,14 +273,3 @@ xinput2_init() } } } - -void -xinput2_poll() -{ - if (procThread && mouse_capture) { - mouse_x = xi2_mouse_x; - mouse_y = xi2_mouse_y; - } - xi2_mouse_x = 0; - xi2_mouse_y = 0; -} diff --git a/src/unix/unix.c b/src/unix/unix.c index b56022474..513f3b259 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -699,19 +699,6 @@ typedef struct mouseinputdata { int mousebuttons; } mouseinputdata; SDL_mutex *mousemutex; -static mouseinputdata mousedata; -void -mouse_poll(void) -{ - SDL_LockMutex(mousemutex); - mouse_x = mousedata.deltax; - mouse_y = mousedata.deltay; - mouse_z = mousedata.deltaz; - mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; - mouse_buttons = mousedata.mousebuttons; - SDL_UnlockMutex(mousemutex); -} - int real_sdl_w; int real_sdl_h; void @@ -1182,7 +1169,7 @@ main(int argc, char **argv) event.wheel.y *= -1; } SDL_LockMutex(mousemutex); - mousedata.deltaz = event.wheel.y; + mouse_set_z(event.wheel.y); SDL_UnlockMutex(mousemutex); } break; @@ -1191,8 +1178,7 @@ main(int argc, char **argv) { if (mouse_capture || video_fullscreen) { SDL_LockMutex(mousemutex); - mousedata.deltax += event.motion.xrel; - mousedata.deltay += event.motion.yrel; + mouse_scale(event.motion.xrel, event.motion.yrel); SDL_UnlockMutex(mousemutex); } break; @@ -1232,10 +1218,10 @@ main(int argc, char **argv) break; } SDL_LockMutex(mousemutex); - if (event.button.state == SDL_PRESSED) { - mousedata.mousebuttons |= buttonmask; - } else - mousedata.mousebuttons &= ~buttonmask; + if (event.button.state == SDL_PRESSED) + mouse_set_buttons_ex(mouse_get_buttons_ex() | buttonmask); + else + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~buttonmask); SDL_UnlockMutex(mousemutex); } break; diff --git a/src/win/win_mouse.c b/src/win/win_mouse.c index 3e31f12de..c8f7f90fd 100644 --- a/src/win/win_mouse.c +++ b/src/win/win_mouse.c @@ -21,17 +21,16 @@ */ #include #include +#include #include #include #include <86box/86box.h> #include <86box/mouse.h> +#include <86box/pic.h> #include <86box/plat.h> #include <86box/win.h> int mouse_capture; -double mouse_sensitivity = 1.0; /* Unused. */ -double mouse_x_error = 0.0; /* Unused. */ -double mouse_y_error = 0.0; /* Unused. */ typedef struct { int buttons; @@ -65,53 +64,62 @@ void win_mouse_handle(PRAWINPUT raw) { RAWMOUSE state = raw->data.mouse; - static int x; - static int y; + static int x, delta_x; + static int y, delta_y; + static int b, delta_z; + + b = mouse_get_buttons_ex(); /* read mouse buttons and wheel */ if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) - mousestate.buttons |= 1; + b |= 1; else if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) - mousestate.buttons &= ~1; + b &= ~1; if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) - mousestate.buttons |= 4; + b |= 4; else if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) - mousestate.buttons &= ~4; + b &= ~4; if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) - mousestate.buttons |= 2; + b |= 2; else if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) - mousestate.buttons &= ~2; + b &= ~2; if (state.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) - mousestate.buttons |= 8; + b |= 8; else if (state.usButtonFlags & RI_MOUSE_BUTTON_4_UP) - mousestate.buttons &= ~8; + b &= ~8; if (state.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) - mousestate.buttons |= 16; + b |= 16; else if (state.usButtonFlags & RI_MOUSE_BUTTON_5_UP) - mousestate.buttons &= ~16; + b &= ~16; + + mouse_set_buttons_ex(b); if (state.usButtonFlags & RI_MOUSE_WHEEL) { - mousestate.dwheel += (SHORT) state.usButtonData / 120; - } + delta_z = (SHORT) state.usButtonData / 120; + mouse_set_z(delta_z); + } else + delta_z = 0; if (state.usFlags & MOUSE_MOVE_ABSOLUTE) { /* absolute mouse, i.e. RDP or VNC * seems to work fine for RDP on Windows 10 * Not sure about other environments. */ - mousestate.dx += (state.lLastX - x) / 25; - mousestate.dy += (state.lLastY - y) / 25; + delta_x = (state.lLastX - x) / 25; + delta_y = (state.lLastY - y) / 25; x = state.lLastX; y = state.lLastY; } else { /* relative mouse, i.e. regular mouse */ - mousestate.dx += state.lLastX; - mousestate.dy += state.lLastY; + delta_x = state.lLastX; + delta_y = state.lLastY; } + + mouse_scale(delta_x, delta_y); } void @@ -124,27 +132,3 @@ win_mouse_close(void) ridev.usUsage = 0x02; RegisterRawInputDevices(&ridev, 1, sizeof(ridev)); } - -void -mouse_poll(void) -{ - static int b = 0; - if (mouse_capture || video_fullscreen) { - if (mousestate.dx != 0 || mousestate.dy != 0 || mousestate.dwheel != 0) { - mouse_x += mousestate.dx; - mouse_y += mousestate.dy; - mouse_z = mousestate.dwheel; - - mousestate.dx = 0; - mousestate.dy = 0; - mousestate.dwheel = 0; - - // pclog("dx=%d, dy=%d, dwheel=%d\n", mouse_x, mouse_y, mouse_z); - } - - if (b != mousestate.buttons) { - mouse_buttons = mousestate.buttons; - b = mousestate.buttons; - } - } -}