Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dosbox-staging/dosbox-staging.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFeralChild64 <unknown>2022-10-28 21:21:12 +0300
committerkcgen <1557255+kcgen@users.noreply.github.com>2022-11-03 16:02:58 +0300
commitd1d8f515df0ca0bfbc031cfdc2853bb2daf83aa9 (patch)
tree9bb7ca4cf590521ebeb409ec619bb218532262d3
parent92162d5fd08e34074ba57526a15c3dc44d0c76f2 (diff)
Move toolkit-independent mouse code out of sdlmain.cpp
-rw-r--r--include/mouse.h49
-rw-r--r--include/sdlmain.h12
-rw-r--r--include/video.h9
-rw-r--r--src/dos/program_mousectl.cpp3
-rw-r--r--src/gui/sdl_mapper.cpp26
-rw-r--r--src/gui/sdlmain.cpp287
-rw-r--r--src/hardware/mouse/mouse.cpp503
-rw-r--r--src/hardware/mouse/mouse_common.cpp3
-rw-r--r--src/hardware/mouse/mouse_common.h28
-rw-r--r--src/hardware/mouse/mouse_config.cpp154
-rw-r--r--src/hardware/mouse/mouse_config.h18
-rw-r--r--src/hardware/mouse/mouse_interfaces.cpp47
-rw-r--r--src/hardware/mouse/mouse_interfaces.h24
-rw-r--r--src/hardware/mouse/mouse_manymouse.cpp12
-rw-r--r--src/hardware/mouse/mouseif_dos_driver.cpp71
-rw-r--r--src/hardware/mouse/mouseif_ps2_bios.cpp4
-rw-r--r--src/hardware/mouse/mouseif_virtual_machines.cpp88
17 files changed, 737 insertions, 601 deletions
diff --git a/include/mouse.h b/include/mouse.h
index 98ef12871..11df6328c 100644
--- a/include/mouse.h
+++ b/include/mouse.h
@@ -50,8 +50,7 @@ enum class MouseInterfaceId : uint8_t {
None = UINT8_MAX
};
-constexpr uint8_t num_mouse_interfaces = static_cast<uint8_t>(MouseInterfaceId::Last) +
- 1;
+constexpr uint8_t num_mouse_interfaces = static_cast<uint8_t>(MouseInterfaceId::Last) + 1;
enum class MouseMapStatus : uint8_t {
HostPointer,
@@ -65,7 +64,7 @@ enum class MouseMapStatus : uint8_t {
// ***************************************************************************
void MOUSE_EventMoved(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs);
+ const int32_t x_abs, const int32_t y_abs);
void MOUSE_EventMoved(const float x_rel, const float y_rel,
const MouseInterfaceId device_id);
@@ -76,23 +75,37 @@ void MOUSE_EventButton(const uint8_t idx, const bool pressed,
void MOUSE_EventWheel(const int16_t w_rel);
void MOUSE_EventWheel(const int16_t w_rel, const MouseInterfaceId device_id);
+// Notify that guest OS is being booted, so that certain
+// parts of the emulation (like DOS driver) should be disabled
void MOUSE_NotifyBooting();
-void MOUSE_SetConfigSeamless(const bool seamless);
-void MOUSE_SetConfigNoMouse();
-
-void MOUSE_NewScreenParams(const uint16_t clip_x, const uint16_t clip_y,
- const uint16_t res_x, const uint16_t res_y,
- const bool fullscreen, const uint16_t x_abs,
- const uint16_t y_abs);
-
-// ***************************************************************************
-// Information for the GFX subsystem
-// ***************************************************************************
-
-bool MOUSE_IsUsingSeamlessDriver(); // if driver with seamless pointer support
- // is running
-bool MOUSE_IsUsingSeamlessSetting(); // if user selected seamless mode is in effect
+// Notify that GFX subsystem (currently SDL) is started
+// and can accept requests from mouse emulation module
+void MOUSE_NotifyReadyGFX();
+
+// Notify that window has lost or gained focus, this tells the mouse
+// emulation code if it should process mouse events or ignore them
+void MOUSE_NotifyHasFocus(const bool has_focus);
+
+// A GUI has to use this function to tell when it takes over or releases
+// the mouse; this will change various settings like raw input (we don't
+// want it for the GUI) or cursor visibility (we want the host cursor
+// visible while a GUI is running)
+void MOUSE_NotifyTakeOver(const bool gui_has_taken_over);
+
+// To be called when screen mode changes, emulator window gets resized, etc.
+// clip_x / clip_y - size of the black bars around screen area
+// res_x / res_y - size of drawing area (in hot OS pixels)
+// x_abs / y_abs - new absolute mouse cursor position
+// is_fullscreen - whether the new mode is fullscreen or windowed
+void MOUSE_NewScreenParams(const uint32_t clip_x, const uint32_t clip_y,
+ const uint32_t res_x, const uint32_t res_y,
+ const int32_t x_abs, const int32_t y_abs,
+ const bool is_fullscreen);
+
+// Notification that user pressed/released the hotkey combination
+// to capture/release the mouse
+void MOUSE_ToggleUserCapture(const bool pressed);
// ***************************************************************************
// BIOS mouse interface for PS/2 mouse
diff --git a/include/sdlmain.h b/include/sdlmain.h
index cbf17c200..5dbc4e4be 100644
--- a/include/sdlmain.h
+++ b/include/sdlmain.h
@@ -48,13 +48,6 @@ static void update_frame_surface(const uint16_t *changedLines);
constexpr void update_frame_noop([[maybe_unused]] const uint16_t *) { /* no-op */ }
static inline bool present_frame_noop() { return true; }
-enum MouseControlType {
- CaptureOnClick = 1 << 0,
- CaptureOnStart = 1 << 1,
- Seamless = 1 << 2,
- NoMouse = 1 << 3
-};
-
enum SCREEN_TYPES {
SCREEN_SURFACE,
SCREEN_TEXTURE,
@@ -232,11 +225,6 @@ struct SDL_Block {
int period_us_early = 0;
int period_us_late = 0;
} frame = {};
- struct {
- MouseControlType control_choice = Seamless;
- bool middle_will_release = true;
- bool has_focus = false;
- } mouse = {};
PPScale pp_scale = {};
SDL_Rect updateRects[1024] = {};
bool use_exact_window_resolution = false;
diff --git a/include/video.h b/include/video.h
index 456574acd..1b3b741dd 100644
--- a/include/video.h
+++ b/include/video.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2020-2022 The DOSBox Staging Team
* Copyright (C) 2002-2021 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
@@ -78,12 +79,12 @@ void GFX_SwitchFullScreen(void);
bool GFX_StartUpdate(uint8_t * &pixels, int &pitch);
void GFX_EndUpdate( const uint16_t *changedLines );
void GFX_GetSize(int &width, int &height, bool &fullscreen);
-void GFX_UpdateMouseState();
void GFX_LosingFocus();
void GFX_RegenerateWindow(Section *sec);
-void GFX_SetMouseRawInput(const bool raw_input);
-void GFX_MouseCaptureAfterMapping();
-bool GFX_MouseIsAvailable();
+
+void GFX_SetMouseCapture(const bool requested_capture);
+void GFX_SetMouseVisibility(const bool requested_visible);
+void GFX_SetMouseRawInput(const bool requested_raw_input);
#if defined (REDUCE_JOYSTICK_POLLING)
void MAPPER_UpdateJoysticks(void);
diff --git a/src/dos/program_mousectl.cpp b/src/dos/program_mousectl.cpp
index 64709fe55..66f90611f 100644
--- a/src/dos/program_mousectl.cpp
+++ b/src/dos/program_mousectl.cpp
@@ -23,7 +23,6 @@
#include "ansi_code_markup.h"
#include "checks.h"
#include "string_utils.h"
-#include "video.h"
#include <set>
@@ -323,8 +322,6 @@ void MOUSECTL::FinalizeMapping()
WriteOut("\n");
WriteOut(MSG_Get("SHELL_CMD_MOUSECTL_MAP_HINT"));
WriteOut("\n\n");
-
- GFX_MouseCaptureAfterMapping();
}
bool MOUSECTL::CmdMap(const MouseInterfaceId interface_id, const std::string &pattern)
diff --git a/src/gui/sdl_mapper.cpp b/src/gui/sdl_mapper.cpp
index 284f9e8fc..188bd38ac 100644
--- a/src/gui/sdl_mapper.cpp
+++ b/src/gui/sdl_mapper.cpp
@@ -42,6 +42,7 @@
#include "keyboard.h"
#include "mapper.h"
#include "math_utils.h"
+#include "mouse.h"
#include "pic.h"
#include "rgb24.h"
#include "setup.h"
@@ -59,10 +60,6 @@ constexpr rgb24 marginal_color(255, 103, 0); // Amber for marginal conditions
constexpr rgb24 on_color(0, 1, 0); // Green for on/ready/in-use
constexpr rgb24 off_color(0, 0, 0); // Black for off/stopped/not-in-use
-/* Mouse related */
-void GFX_ToggleMouseCapture();
-extern bool mouse_is_captured; //true if mouse is confined to window
-
enum {
CLR_BLACK=0,
CLR_GREY=1,
@@ -2921,11 +2918,6 @@ void MAPPER_LosingFocus() {
void MAPPER_RunEvent(uint32_t /*val*/)
{
- if (!GFX_MouseIsAvailable()) {
- LOG_ERR("MAPPER: The mapper requires a mouse, but no mouse is available");
- LOG_WARNING("MAPPER: Set your conf 'capture_mouse' setting to something other than 'nomouse'");
- return;
- }
KEYBOARD_ClrBuffer(); // Clear buffer
GFX_LosingFocus(); //Release any keys pressed (buffer gets filled again).
MAPPER_DisplayUI();
@@ -2940,20 +2932,14 @@ void MAPPER_Run(bool pressed) {
SDL_Surface* SDL_SetVideoMode_Wrap(int width,int height,int bpp,uint32_t flags);
void MAPPER_DisplayUI() {
+ MOUSE_NotifyTakeOver(true);
+
// The mapper is about to take-over SDL's surface and rendering
// functions, so disengage the main ones. When the mapper closes, SDL
// main will recreate its rendering pipeline.
GFX_DisengageRendering();
- int cursor = SDL_ShowCursor(SDL_QUERY);
- SDL_ShowCursor(SDL_ENABLE);
- bool mousetoggle = false;
- if (mouse_is_captured) {
- mousetoggle = true;
- GFX_ToggleMouseCapture();
- }
-
- /* Be sure that there is no update in progress */
+ // Be sure that there is no update in progress
GFX_EndUpdate( 0 );
mapper.window = GFX_SetSDLSurfaceWindow(640, 480);
if (mapper.window == nullptr)
@@ -3000,10 +2986,8 @@ void MAPPER_DisplayUI() {
#if defined (REDUCE_JOYSTICK_POLLING)
SDL_JoystickEventState(SDL_DISABLE);
#endif
- if (mousetoggle)
- GFX_ToggleMouseCapture();
- SDL_ShowCursor(cursor);
GFX_ResetScreen();
+ MOUSE_NotifyTakeOver(false);
}
static void MAPPER_Destroy(Section *sec) {
diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp
index b85932fd0..4eb0d7e94 100644
--- a/src/gui/sdlmain.cpp
+++ b/src/gui/sdlmain.cpp
@@ -198,9 +198,6 @@ PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = NULL;
SDL_Block sdl;
-bool mouse_is_captured = false; // the actual state of the mouse
-bool mouse_capture_requested = false; // if the user manually requested the capture
-
// Masks to be passed when creating SDL_Surface.
// Remove ifndef if they'll be needed for MacOS X builds.
#ifndef MACOSX
@@ -1131,10 +1128,9 @@ static void setup_presentation_mode(FRAME_MODE &previous_mode)
static void NewMouseScreenParams()
{
- int abs_x, abs_y;
+ int abs_x = 0;
+ int abs_y = 0;
SDL_GetMouseState(&abs_x, &abs_y);
- abs_x = std::clamp(abs_x, 0, static_cast<int>(UINT16_MAX));
- abs_y = std::clamp(abs_y, 0, static_cast<int>(UINT16_MAX));
#ifdef __APPLE__
// macOS moves mouse cursor on "client points" grid, not physical pixels;
@@ -1143,15 +1139,17 @@ static void NewMouseScreenParams()
sdl.clip.y / sdl.desktop.dpi_scale,
sdl.clip.w / sdl.desktop.dpi_scale,
sdl.clip.h / sdl.desktop.dpi_scale,
- sdl.desktop.fullscreen,
- check_cast<uint16_t>(abs_x),
- check_cast<uint16_t>(abs_y));
+ check_cast<int32_t>(abs_x),
+ check_cast<int32_t>(abs_y),
+ sdl.desktop.fullscreen);
#else
- MOUSE_NewScreenParams(sdl.clip.x, sdl.clip.y,
- sdl.clip.w, sdl.clip.h,
- sdl.desktop.fullscreen,
- check_cast<uint16_t>(abs_x),
- check_cast<uint16_t>(abs_y));
+ MOUSE_NewScreenParams(check_cast<uint32_t>(sdl.clip.x),
+ check_cast<uint32_t>(sdl.clip.y),
+ check_cast<uint32_t>(sdl.clip.w),
+ check_cast<uint32_t>(sdl.clip.h),
+ check_cast<int32_t>(abs_x),
+ check_cast<int32_t>(abs_y),
+ sdl.desktop.fullscreen);
#endif
}
@@ -2169,61 +2167,34 @@ void GFX_SetShader([[maybe_unused]] const std::string &source)
#endif
}
-bool GFX_MouseIsAvailable() {
- return sdl.mouse.control_choice != NoMouse;
-}
-
-void GFX_SetMouseRawInput(const bool raw_input)
+void GFX_SetMouseRawInput(const bool requested_raw_input)
{
- if (!SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP,
- raw_input ? "0" : "1",
- SDL_HINT_OVERRIDE))
- LOG_WARNING("DISPLAY: Mouse raw input set failed");
+ if (SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP,
+ requested_raw_input ? "0" : "1",
+ SDL_HINT_OVERRIDE) != SDL_TRUE)
+ LOG_WARNING("SDL: Mouse raw input %s failed",
+ requested_raw_input ? "enable" : "disable");
}
-void GFX_ToggleMouseCapture()
+void GFX_SetMouseCapture(const bool requested_capture)
{
- /*
- * Only process mouse events when we have focus.
- * This protects against out-of-order event issues such
- * as acting on clicks before the window is drawn.
- */
- if (!sdl.mouse.has_focus)
- return;
-
- assertm(sdl.mouse.control_choice != NoMouse,
- "SDL: Mouse capture is invalid when NoMouse is configured [Logic Bug]");
-
- mouse_is_captured = !mouse_is_captured; // flip state
- if (SDL_SetRelativeMouseMode(mouse_is_captured ? SDL_TRUE : SDL_FALSE) != 0) {
+ const auto param = requested_capture ? SDL_TRUE : SDL_FALSE;
+ if (SDL_SetRelativeMouseMode(param) != 0) {
SDL_ShowCursor(SDL_ENABLE);
- E_Exit("SDL: failed to %s relative-mode [SDL Bug]",
- mouse_is_captured ? "put the mouse in"
- : "take the mouse out of");
+ E_Exit("SDL: Failed to %s relative-mode [SDL Bug]",
+ requested_capture ? "put the mouse in" :
+ "take the mouse out of");
}
- LOG_MSG("SDL: %s the mouse", mouse_is_captured ? "captured" : "released");
}
-static void toggle_mouse_capture_from_user(bool pressed)
+void GFX_SetMouseVisibility(const bool requested_visible)
{
- if (!pressed || sdl.desktop.fullscreen)
- return;
- mouse_capture_requested = !mouse_capture_requested;
- GFX_ToggleMouseCapture();
-}
-
-void GFX_MouseCaptureAfterMapping()
-{
- if (sdl.desktop.fullscreen ||
- !sdl.mouse.has_focus ||
- mouse_is_captured)
- return;
-
- mouse_capture_requested = true;
- GFX_ToggleMouseCapture();
+ const auto param = requested_visible ? SDL_ENABLE : SDL_DISABLE;
+ if (SDL_ShowCursor(param) < 0)
+ E_Exit("SDL: Failed to make mouse cursor %s [SDL Bug]",
+ requested_visible ? "visible" : "invisible");
}
-
static void FocusInput()
{
// Ensure auto-cycles are enabled
@@ -2246,60 +2217,6 @@ static void FocusInput()
SDL_SetWindowInputFocus(sdl.window);
}
-/*
- * Assesses the following:
- * - current window size (full or not),
- * - mouse capture state (yes or no),
- * - whether VMware type mouse driver is running,
- * - desired capture type (start, click, seamless), and
- * - if we're starting up for the first time,
- * to determine if the mouse-capture state should be toggled.
- * Note that this also acts a filter: we don't want to repeatedly
- * re-apply the same mouse capture state over and over again, so most
- * of the time this function will (or should) decide to do nothing.
- */
-void GFX_UpdateMouseState()
-{
- // Don't change anything if we do not have focus
- if (!sdl.mouse.has_focus)
- return;
-
- // Used below
- static bool has_run_once = false;
-
- // We've switched to or started in fullscreen, so capture the mouse
- // This is valid for all modes except for nomouse
- if (sdl.desktop.fullscreen && !mouse_is_captured &&
- sdl.mouse.control_choice != NoMouse) {
- GFX_ToggleMouseCapture();
-
- // If we've switched-back from fullscreen, then release the
- // mouse if it is controlled by a VMware type driver or
- // it's auto-captured (but not manually requested) and
- // in seamless-mode
- } else if (!sdl.desktop.fullscreen && mouse_is_captured &&
- (MOUSE_IsUsingSeamlessDriver() ||
- (!mouse_capture_requested && MOUSE_IsUsingSeamlessSetting()))) {
- GFX_ToggleMouseCapture();
- SDL_ShowCursor(SDL_DISABLE);
-
- // If none of the above are true /and/ we're starting
- // up the first time, then:
- // - Capture the mouse if configured onstart is set
- // - Hide the mouse if seamless or nomouse are set
- // - Also hide if it is handled by a VMware type driver
- } else if (!has_run_once) {
- if (sdl.mouse.control_choice == CaptureOnStart) {
- SDL_RaiseWindow(sdl.window);
- toggle_mouse_capture_from_user(true);
- } else if (MOUSE_IsUsingSeamlessDriver() ||
- (sdl.mouse.control_choice & (Seamless | NoMouse))) {
- SDL_ShowCursor(SDL_DISABLE);
- }
- }
- has_run_once = true;
-}
-
#if defined (WIN32)
STICKYKEYS stick_keys = {sizeof(STICKYKEYS), 0};
void sticky_keys(bool restore){
@@ -2637,8 +2554,9 @@ static void GUI_ShutDown(Section *)
(sdl.draw.callback)( GFX_CallBackStop );
if (sdl.desktop.fullscreen)
GFX_SwitchFullScreen();
- if (mouse_is_captured)
- GFX_ToggleMouseCapture();
+
+ GFX_SetMouseCapture(false);
+ GFX_SetMouseVisibility(true);
CleanupSDLResources();
if (sdl.renderer) {
@@ -3557,56 +3475,16 @@ static void GUI_StartUp(Section *sec)
SDL_SetWindowTitle(sdl.window, "DOSBox Staging");
SetIcon();
- // Apply the user's mouse settings
- Section_prop* s = section->GetMultiVal("capture_mouse")->GetSection();
- const std::string control_choice = s->Get_string("capture_mouse_first_value");
- std::string mouse_control_msg;
- if (control_choice == "onclick") {
- sdl.mouse.control_choice = CaptureOnClick;
- mouse_control_msg = "will be captured after the first left or right button click";
- } else if (control_choice == "onstart") {
- sdl.mouse.control_choice = CaptureOnStart;
- mouse_control_msg = "will be captured immediately on start";
- } else if (control_choice == "seamless") {
- sdl.mouse.control_choice = Seamless;
- mouse_control_msg = "will move seamlessly: left and right button clicks won't capture the mouse";
- } else if (control_choice == "nomouse") {
- sdl.mouse.control_choice = NoMouse;
- mouse_control_msg = "is disabled";
- MOUSE_SetConfigNoMouse();
- } else {
- assert(sdl.mouse.control_choice == CaptureOnClick);
- }
-
- LOG_MSG("SDL: Mouse %s", mouse_control_msg.c_str());
-
- if (sdl.mouse.control_choice != NoMouse) {
- const std::string mclick_choice = s->Get_string("capture_mouse_second_value");
-
- // release the mouse is the default; this logic handles an empty 2nd value
- sdl.mouse.middle_will_release = (mclick_choice != "middlegame");
-
-
- const auto middle_control_msg = sdl.mouse.middle_will_release
- ? "will capture/release the mouse (clicks not sent to the game/program)"
- : "will be sent to the game/program (clicks not used to capture/release)";
- LOG_MSG("SDL: Middle mouse button %s", middle_control_msg);
-
- // Only setup the Ctrl/Cmd+F10 handler if the mouse is capturable
- MAPPER_AddHandler(toggle_mouse_capture_from_user, SDL_SCANCODE_F10,
- PRIMARY_MOD, "capmouse", "Cap Mouse");
-
- // Notify mouse emulation routines about the configuration
- MOUSE_SetConfigSeamless(sdl.mouse.control_choice == Seamless);
- }
-
/* Get some Event handlers */
MAPPER_AddHandler(GFX_RequestExit, SDL_SCANCODE_F9, PRIMARY_MOD,
"shutdown", "Shutdown");
MAPPER_AddHandler(SwitchFullScreen, SDL_SCANCODE_RETURN, MMOD2,
"fullscr", "Fullscreen");
- MAPPER_AddHandler(Restart, SDL_SCANCODE_HOME, MMOD1 | MMOD2, "restart",
- "Restart");
+ MAPPER_AddHandler(Restart, SDL_SCANCODE_HOME, MMOD1 | MMOD2,
+ "restart", "Restart");
+ MAPPER_AddHandler(MOUSE_ToggleUserCapture, SDL_SCANCODE_F10, PRIMARY_MOD,
+ "capmouse", "Cap Mouse");
+
#if C_DEBUG
/* Pause binds with activate-debugger */
#else
@@ -3621,15 +3499,17 @@ static void GUI_StartUp(Section *sec)
// be toggled by the user /after/ starting DOSBox.
startup_state_numlock = keystate & KMOD_NUM;
startup_state_capslock = keystate & KMOD_CAPS;
-}
+ // Notify MOUSE subsystem that it can start now
+ MOUSE_NotifyReadyGFX();
+}
static void HandleMouseMotion(SDL_MouseMotionEvent *motion)
{
MOUSE_EventMoved(static_cast<float>(motion->xrel),
static_cast<float>(motion->yrel),
- std::clamp(motion->x, 0, static_cast<int>(UINT16_MAX)),
- std::clamp(motion->y, 0, static_cast<int>(UINT16_MAX)));
+ check_cast<int32_t>(motion->x),
+ check_cast<int32_t>(motion->y));
}
static void HandleMouseWheel(SDL_MouseWheelEvent *wheel)
@@ -3640,10 +3520,7 @@ static void HandleMouseWheel(SDL_MouseWheelEvent *wheel)
static void HandleMouseButton(SDL_MouseButtonEvent * button)
{
- constexpr auto state_released = false;
- constexpr auto state_pressed = true;
-
- auto notify_button = [](const uint8_t button, const bool pressed) {
+ auto notify_button = [](const uint8_t button, const bool pressed) {
switch (button) {
case SDL_BUTTON_LEFT: MOUSE_EventButton(0, pressed); break;
case SDL_BUTTON_RIGHT: MOUSE_EventButton(1, pressed); break;
@@ -3653,29 +3530,7 @@ static void HandleMouseButton(SDL_MouseButtonEvent * button)
}
};
- if (button->state == SDL_RELEASED) {
- notify_button(button->button, state_released);
- return;
- }
-
- assert(button->state == SDL_PRESSED);
-
- if (sdl.desktop.fullscreen || MOUSE_IsUsingSeamlessDriver()) {
- notify_button(button->button, state_pressed);
- return;
- }
-
- if (!mouse_is_captured && (sdl.mouse.control_choice & (CaptureOnStart | CaptureOnClick))) {
- toggle_mouse_capture_from_user(true);
- return; // Don't pass click to mouse handler
- }
-
- if (button->button == SDL_BUTTON_MIDDLE && sdl.mouse.control_choice != NoMouse) {
- toggle_mouse_capture_from_user(true);
- return; // Don't pass click to mouse handler
- }
-
- notify_button(button->button, true);
+ notify_button(button->button, button->state == SDL_PRESSED);
}
void GFX_LosingFocus()
@@ -3872,9 +3727,7 @@ bool GFX_Events()
// keyboard focus");
if (sdl.draw.callback)
sdl.draw.callback(GFX_CallBackRedraw);
- sdl.mouse.has_focus = true;
- GFX_UpdateMouseState();
-
+ MOUSE_NotifyHasFocus(true);
ApplyActiveSettings();
FocusInput();
continue;
@@ -3890,7 +3743,7 @@ bool GFX_Events()
ApplyInactiveSettings();
GFX_LosingFocus();
CPU_Enable_SkipAutoAdjust();
- sdl.mouse.has_focus = false;
+ MOUSE_NotifyHasFocus(false);
break;
case SDL_WINDOWEVENT_ENTER:
@@ -4063,10 +3916,7 @@ bool GFX_Events()
case SDL_MOUSEMOTION: HandleMouseMotion(&event.motion); break;
case SDL_MOUSEWHEEL: HandleMouseWheel(&event.wheel); break;
case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- if (sdl.mouse.control_choice != NoMouse)
- HandleMouseButton(&event.button);
- break;
+ case SDL_MOUSEBUTTONUP: HandleMouseButton(&event.button); break;
case SDL_QUIT: GFX_RequestExit(true); break;
#ifdef WIN32
@@ -4273,47 +4123,8 @@ void Config_Add_SDL() {
"Use texture_renderer=auto for an automatic choice.");
pstring->Set_values(Get_SDL_TextureRenderers());
- // Define mouse control settings
- Pmulti = sdl_sec->AddMultiVal("capture_mouse", always, " ");
- const char *mouse_controls[] = {
- "seamless", // default
- "onclick", "onstart", "nomouse", 0,
- };
- const char *middle_controls[] = {
- "middlerelease", // default
- "middlegame",
- "", // allow empty second value for 'nomouse'
- 0,
- };
- // Generate and set the mouse control defaults from above arrays
- std::string mouse_control_defaults(mouse_controls[0]);
- mouse_control_defaults += " ";
- mouse_control_defaults += middle_controls[0];
- Pmulti->SetValue(mouse_control_defaults);
-
- // Add the mouse and middle control as sub-sections
- psection = Pmulti->GetSection();
- psection->Add_string("capture_mouse_first_value", always, mouse_controls[0])
- ->Set_values(mouse_controls);
- psection->Add_string("capture_mouse_second_value", always, middle_controls[0])
- ->Set_values(middle_controls);
-
- // Construct and set the help block using defaults set above
- std::string mouse_control_help(
- "Choose a mouse control method:\n"
- " onclick: Capture the mouse when clicking any button in the window.\n"
- " onstart: Capture the mouse immediately on start.\n"
- " seamless: Let the mouse move seamlessly; captures only with\n"
- " middle-click or hotkey.\n"
- " nomouse: Hide the mouse and don't send input to the game.\n"
- "Choose how middle-clicks are handled (second parameter):\n"
- " middlegame: Middle-clicks are sent to the game.\n"
- " middlerelease: Middle-click will release the captured mouse, and also\n"
- " capture when seamless.\n"
- "Defaults (if not present or incorrect): ");
- mouse_control_help += mouse_control_defaults;
- Pmulti->Set_help(mouse_control_help);
-
+ Pmulti = sdl_sec->AddMultiVal("capture_mouse", deprecated, ",");
+ Pmulti->Set_help("Moved to [mouse] section.");
Pmulti = sdl_sec->AddMultiVal("sensitivity", deprecated, ",");
Pmulti->Set_help("Moved to [mouse] section.");
pbool = sdl_sec->Add_bool("raw_mouse_input", deprecated, false);
diff --git a/src/hardware/mouse/mouse.cpp b/src/hardware/mouse/mouse.cpp
index 6f99a6e1e..891c7a194 100644
--- a/src/hardware/mouse/mouse.cpp
+++ b/src/hardware/mouse/mouse.cpp
@@ -37,15 +37,263 @@
CHECK_NARROWING();
-bool seamless_driver = false;
-bool seamless_setting = false;
-
static Bitu int74_ret_callback = 0;
static MouseQueue &mouse_queue = MouseQueue::GetInstance();
static ManyMouseGlue &manymouse = ManyMouseGlue::GetInstance();
// ***************************************************************************
+// GFX-related decision making
+// ***************************************************************************
+
+static struct {
+ bool is_fullscreen = false; // if full screen mode is active
+ uint32_t clip_x = 0; // clipping = size of black border (one side)
+ uint32_t clip_y = 0;
+
+ uint32_t cursor_x_abs = 0; // absolute position from start of drawing area
+ uint32_t cursor_y_abs = 0;
+ bool cursor_is_outside = true; // if mouse cursor is outside of drawing area
+
+ bool has_focus = false; // if our window has focus
+ bool gui_has_taken_over = false; // if a GUI requested to take over the mouse
+ bool capture_was_requested = false; // if user requested mouse to be captured
+
+ bool is_captured = false; // if GFX was requested to capture mouse
+ bool is_visible = false; // if GFX was requested to make cursor visible
+ bool is_input_raw = false; // if GFX was requested to provide raw movements
+ bool is_seamless = false; // if seamless mouse integration is in effect
+
+ bool should_drop_events = true; // if we should drop mouse events
+ bool should_capture_on_click = false; // if any button click should capture the mouse
+ bool should_capture_on_middle = false; // if middle button press should capture the mouse
+ bool should_release_on_middle = false; // if middle button press should release the mouse
+ bool should_toggle_on_hotkey = false; // if hotkey should toggle mouse capture
+
+} state;
+
+static void update_cursor_absolute_position(const int32_t x_abs, const int32_t y_abs)
+{
+ state.cursor_is_outside = false;
+
+ auto calculate = [&](const int32_t absolute,
+ const uint32_t clipping,
+ const uint32_t resolution) -> uint32_t {
+ assert(resolution > 1u);
+ assert(clipping * 2 < resolution);
+
+ if (absolute < 0 || static_cast<uint32_t>(absolute) < clipping) {
+ // cursor is over the top or left black bar
+ state.cursor_is_outside = true;
+ return 0;
+ } else if (static_cast<uint32_t>(absolute) >= resolution + clipping) {
+ // cursor is over the bottom or right black bar
+ state.cursor_is_outside = true;
+ return check_cast<uint32_t>(resolution - 1);
+ }
+
+ const auto result = static_cast<uint32_t>(absolute) - clipping;
+ return static_cast<uint32_t>(result);
+ };
+
+ auto &x = state.cursor_x_abs;
+ auto &y = state.cursor_y_abs;
+
+ x = calculate(x_abs, state.clip_x, mouse_shared.resolution_x);
+ y = calculate(y_abs, state.clip_y, mouse_shared.resolution_y);
+}
+
+static void update_cursor_visibility()
+{
+ // If mouse subsystem not started yet, do nothing
+ if (!mouse_shared.started)
+ return;
+
+ static bool first_time = true;
+
+ // Store internally old settings, to avoid unnecessary GFX calls
+ const auto old_is_visible = state.is_visible;
+
+ if (!state.has_focus) {
+
+ // No change to cursor visibility
+
+ } else if (state.gui_has_taken_over) {
+
+ state.is_visible = true;
+
+ } else { // Window has focus, no GUI running
+
+ // Host cursor should be hidden if any of:
+ // - mouse cursor is captured, for any reason
+ // - seamless integration is in effect
+ // But show it nevertheless if:
+ // - seamless integration is in effect and
+ // - cursor is outside of drawing area
+ state.is_visible = !(state.is_captured || state.is_seamless) ||
+ (state.is_seamless && state.cursor_is_outside);
+ }
+
+ // Apply calculated settings if changed or if this is the first run
+ if (first_time || old_is_visible != state.is_visible)
+ GFX_SetMouseVisibility(state.is_visible);
+
+ // And take a note that this is no longer the first run
+ first_time = false;
+}
+
+static void update_state() // updates whole 'state' structure, except cursor visibility
+{
+ // If mouse subsystem not started yet, do nothing
+ if (!mouse_shared.started)
+ return;
+
+ const bool is_config_on_start = (mouse_config.capture == MouseCapture::OnStart);
+ const bool is_config_on_click = (mouse_config.capture == MouseCapture::OnClick);
+ const bool is_config_no_mouse = (mouse_config.capture == MouseCapture::NoMouse);
+
+ // If running for the first time, capture the mouse if this was configured
+ static bool first_time = true;
+ if (first_time && is_config_on_start)
+ state.capture_was_requested = true;
+
+ // We are running in seamless mode:
+ // - we are not in windowed mode, and
+ // - NoMouse is not configured, and
+ // - seamless driver is running or Seamless capture is configured
+ const bool is_seamless_config = (mouse_config.capture == MouseCapture::Seamless);
+ const bool is_seamless_driver = mouse_shared.active_vmm;
+ state.is_seamless = !state.is_fullscreen &&
+ !is_config_no_mouse &&
+ (is_seamless_driver || is_seamless_config);
+
+ // Due to ManyMouse API limitation, we are unable to support seamless
+ // integration if mapping is in effect
+ const bool is_mapping = manymouse.IsMappingInEffect();
+ if (state.is_seamless && is_mapping) {
+ state.is_seamless = false;
+ static bool already_warned = false;
+ if (!already_warned) {
+ LOG_WARNING("MOUSE: Mapping disables seamless pointer integration");
+ already_warned = true;
+ }
+ }
+
+ // Store internally old settings, to avoid unnecessary GFX calls
+ const auto old_is_captured = state.is_captured;
+ const auto old_is_input_raw = state.is_input_raw;
+
+ // Raw input depends on the user configuration
+ state.is_input_raw = mouse_config.raw_input;
+
+ if (!state.has_focus) {
+
+ state.should_drop_events = true;
+
+ // No change to:
+ // - state.is_captured
+
+ } else if (state.gui_has_taken_over) {
+
+ state.is_captured = false;
+ state.should_drop_events = true;
+
+ // Override user configuration, for the GUI we want
+ // host OS mouse acceleration applied
+ state.is_input_raw = false;
+
+ } else { // Window has focus, no GUI running
+
+ // Capture mouse cursor if any of:
+ // - we are in fullscreen mode
+ // - user asked to capture the mouse
+ state.is_captured = state.is_fullscreen ||
+ state.capture_was_requested;
+
+ // Drop mouse events if NoMouse is configured
+ state.should_drop_events = is_config_no_mouse;
+ // Also drop events if:
+ // - mouse not captured, and
+ // - mouse not in seamless mode (due to user setting or seamless driver)
+ if (!state.is_captured && !state.is_seamless)
+ state.should_drop_events = true;
+ }
+
+ // Use a hotkey to toggle mouse capture if:
+ // - windowed mode, and
+ // - capture type is different than NoMouse
+ state.should_toggle_on_hotkey = !state.is_fullscreen &&
+ !is_config_no_mouse;
+
+ // Use any mouse click to capture the mouse if:
+ // - windowed mode, and
+ // - mouse is not captured, and
+ // - we are not in seamless mode, and
+ // - no GUI has taken over the mouse, and
+ // - no NoMouse mode is in effect, and
+ // - capture on start/click was configured or mapping is in effect
+ state.should_capture_on_click = !state.is_fullscreen &&
+ !state.is_captured &&
+ !state.is_seamless &&
+ !state.gui_has_taken_over &&
+ !is_config_no_mouse &&
+ (is_config_on_start || is_config_on_click || is_mapping);
+
+ // Use a middle click to capture the mouse if:
+ // - windowed mode, and
+ // - mouse is not captured, and
+ // - no GUI has taken over the mouse, and
+ // - no NoMouse mode is in effect, and
+ // - seamless mode is in effect, and
+ // - middle release was configured
+ state.should_capture_on_middle = !state.is_fullscreen &&
+ !state.is_captured &&
+ !state.gui_has_taken_over &&
+ !is_config_no_mouse &&
+ state.is_seamless &&
+ mouse_config.middle_release;
+
+ // Use a middle click to release the mouse if:
+ // - windowed mode, and
+ // - mouse is captured, and
+ // - release by middle button was configured
+ state.should_release_on_middle = !state.is_fullscreen &&
+ state.is_captured &&
+ mouse_config.middle_release;
+
+ // Apply calculated settings if changed or if this is the first run
+ if (first_time || old_is_captured != state.is_captured)
+ GFX_SetMouseCapture(state.is_captured);
+ if (first_time || old_is_input_raw != state.is_input_raw)
+ GFX_SetMouseRawInput(state.is_input_raw);
+
+ for (auto &interface : mouse_interfaces)
+ interface->UpdateInputType();
+
+ // And take a note that this is no longer the first run
+ first_time = false;
+}
+
+static bool should_drop_event()
+{
+ // Decide whether to drop mouse events, depending on both
+ // mouse cursor position and general event dropping policy
+ return (state.is_seamless && state.cursor_is_outside) ||
+ state.should_drop_events;
+}
+
+void MOUSE_UpdateGFX()
+{
+ update_state();
+ update_cursor_visibility();
+}
+
+bool MOUSE_IsCaptured()
+{
+ return state.is_captured;
+}
+
+// ***************************************************************************
// Interrupt 74 implementation
// ***************************************************************************
@@ -118,71 +366,65 @@ Bitu int74_ret_handler()
}
// ***************************************************************************
-// Information for the GFX subsystem
-// ***************************************************************************
-
-bool MOUSE_IsUsingSeamlessDriver()
-{
- return seamless_driver;
-}
-
-bool MOUSE_IsUsingSeamlessSetting()
-{
- return seamless_setting;
-}
-
-// ***************************************************************************
// External notifications
// ***************************************************************************
-void MOUSE_NewScreenParams(const uint16_t clip_x, const uint16_t clip_y,
- const uint16_t res_x, const uint16_t res_y,
- const bool fullscreen, const uint16_t x_abs,
- const uint16_t y_abs)
+void MOUSE_NewScreenParams(const uint32_t clip_x, const uint32_t clip_y,
+ const uint32_t res_x, const uint32_t res_y,
+ const int32_t x_abs, const int32_t y_abs,
+ const bool is_fullscreen)
{
- mouse_video.clip_x = clip_x;
- mouse_video.clip_y = clip_y;
+ assert(clip_x <= INT32_MAX);
+ assert(clip_y <= INT32_MAX);
+ assert(res_x <= INT32_MAX);
+ assert(res_y <= INT32_MAX);
+
+ state.clip_x = clip_x;
+ state.clip_y = clip_y;
// Protection against strange window sizes,
// to prevent division by 0 in some places
- mouse_video.res_x = std::max(res_x, static_cast<uint16_t>(2));
- mouse_video.res_y = std::max(res_y, static_cast<uint16_t>(2));
+ constexpr uint32_t min = 2;
+ mouse_shared.resolution_x = std::max(res_x, min);
+ mouse_shared.resolution_y = std::max(res_y, min);
- mouse_video.fullscreen = fullscreen;
+ // If we are switching back from fullscreen,
+ // clear the user capture request
+ if (state.is_fullscreen && !is_fullscreen)
+ state.capture_was_requested = false;
- MOUSEVMM_NewScreenParams(x_abs, y_abs);
- MOUSE_NotifyStateChanged();
-}
+ state.is_fullscreen = is_fullscreen;
-void MOUSE_NotifyResetDOS()
-{
- mouse_queue.ClearEventsDOS();
+ update_cursor_absolute_position(x_abs, y_abs);
+
+ MOUSE_UpdateGFX();
+ MOUSEVMM_NewScreenParams(state.cursor_x_abs, state.cursor_y_abs);
}
-void MOUSE_NotifyStateChanged()
+void MOUSE_ToggleUserCapture(const bool pressed)
{
- const auto old_seamless_driver = seamless_driver;
- const auto old_seamless_setting = seamless_setting;
+ if (!pressed || !state.should_toggle_on_hotkey)
+ return;
- const auto is_mapping_in_effect = manymouse.IsMappingInEffect();
+ state.capture_was_requested = !state.capture_was_requested;
+ MOUSE_UpdateGFX();
+}
- static bool already_warned = false;
- if (!already_warned && is_mapping_in_effect &&
- (mouse_shared.active_vmm || mouse_config.seamless)) {
- LOG_WARNING("MOUSE: Mapping disables seamless pointer integration");
- already_warned = true;
- }
+void MOUSE_NotifyTakeOver(const bool gui_has_taken_over)
+{
+ state.gui_has_taken_over = gui_has_taken_over;
+ MOUSE_UpdateGFX();
+}
- // Prepare suggestions to the GFX subsystem
- seamless_driver = mouse_shared.active_vmm && !mouse_video.fullscreen &&
- !is_mapping_in_effect;
- seamless_setting = mouse_config.seamless && !mouse_video.fullscreen &&
- !is_mapping_in_effect;
+void MOUSE_NotifyHasFocus(const bool has_focus)
+{
+ state.has_focus = has_focus;
+ MOUSE_UpdateGFX();
+}
- // If state has really changed, update GFX subsystem
- if (seamless_driver != old_seamless_driver ||
- seamless_setting != old_seamless_setting)
- GFX_UpdateMouseState();
+void MOUSE_NotifyResetDOS()
+{
+ mouse_queue.ClearEventsDOS();
}
void MOUSE_NotifyDisconnect(const MouseInterfaceId interface_id)
@@ -210,10 +452,16 @@ void MOUSE_NotifyBooting()
}
void MOUSE_EventMoved(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs)
+ const int32_t x_abs, const int32_t y_abs)
{
+ // Event from GFX
+
+ // Update cursor position and visibility
+ update_cursor_absolute_position(x_abs, y_abs);
+ update_cursor_visibility();
+
// Drop unneeded events
- if (!mouse_is_captured && !seamless_driver && !seamless_setting)
+ if (should_drop_event())
return;
// From the GUI we are getting mouse movement data in two
@@ -237,13 +485,21 @@ void MOUSE_EventMoved(const float x_rel, const float y_rel,
MouseEvent ev;
for (auto &interface : mouse_interfaces)
if (interface->IsUsingHostPointer())
- interface->NotifyMoved(ev, x_rel, y_rel, x_abs, y_abs);
+ interface->NotifyMoved(ev, x_rel, y_rel,
+ state.cursor_x_abs,
+ state.cursor_y_abs);
mouse_queue.AddEvent(ev);
}
void MOUSE_EventMoved(const float x_rel, const float y_rel,
const MouseInterfaceId interface_id)
{
+ // Event from ManyMouse
+
+ // Drop unneeded events
+ if (should_drop_event())
+ return;
+
auto interface = MouseInterface::Get(interface_id);
if (interface && interface->IsUsingEvents()) {
MouseEvent ev;
@@ -254,6 +510,37 @@ void MOUSE_EventMoved(const float x_rel, const float y_rel,
void MOUSE_EventButton(const uint8_t idx, const bool pressed)
{
+ // Event from GFX
+
+ // Never ignore any button releases - always pass them
+ // to concrete interfaces, they will decide whether to
+ // ignore them or not.
+ if (pressed) {
+ // Handle mouse capture by button click
+ if (state.should_capture_on_click) {
+ state.capture_was_requested = true;
+ MOUSE_UpdateGFX();
+ return;
+ }
+
+ // Handle mouse capture toggle by middle click
+ constexpr uint8_t idx_middle = 2;
+ if (idx == idx_middle && state.should_capture_on_middle) {
+ state.capture_was_requested = true;
+ MOUSE_UpdateGFX();
+ return;
+ }
+ if (idx == idx_middle && state.should_release_on_middle) {
+ state.capture_was_requested = false;
+ MOUSE_UpdateGFX();
+ return;
+ }
+
+ /// Drop unneeded events
+ if (should_drop_event())
+ return;
+ }
+
MouseEvent ev;
for (auto &interface : mouse_interfaces)
if (interface->IsUsingHostPointer())
@@ -264,6 +551,14 @@ void MOUSE_EventButton(const uint8_t idx, const bool pressed)
void MOUSE_EventButton(const uint8_t idx, const bool pressed,
const MouseInterfaceId interface_id)
{
+ // Event from ManyMouse
+
+ // Drop unneeded events - but never drop any button
+ // releases events; pass them to concrete interfaces,
+ // they will decide whether to ignore them or not.
+ if (pressed && should_drop_event())
+ return;
+
auto interface = MouseInterface::Get(interface_id);
if (interface && interface->IsUsingEvents()) {
MouseEvent ev;
@@ -274,6 +569,12 @@ void MOUSE_EventButton(const uint8_t idx, const bool pressed,
void MOUSE_EventWheel(const int16_t w_rel)
{
+ // Event from GFX
+
+ // Drop unneeded events
+ if (should_drop_event())
+ return;
+
MouseEvent ev;
for (auto &interface : mouse_interfaces)
if (interface->IsUsingHostPointer())
@@ -283,6 +584,12 @@ void MOUSE_EventWheel(const int16_t w_rel)
void MOUSE_EventWheel(const int16_t w_rel, const MouseInterfaceId interface_id)
{
+ // Event from ManyMouse
+
+ // Drop unneeded events
+ if (state.should_drop_events)
+ return;
+
auto interface = MouseInterface::Get(interface_id);
if (interface && interface->IsUsingEvents()) {
MouseEvent ev;
@@ -328,12 +635,12 @@ MouseControlAPI::MouseControlAPI()
MouseControlAPI::~MouseControlAPI()
{
manymouse.StopConfigAPI();
- MOUSE_NotifyStateChanged();
+ MOUSE_UpdateGFX();
}
bool MouseControlAPI::IsNoMouseMode()
{
- return mouse_config.no_mouse;
+ return mouse_config.capture == MouseCapture::NoMouse;
}
const std::vector<MouseInterfaceInfoEntry> &MouseControlAPI::GetInfoInterfaces() const
@@ -387,7 +694,7 @@ bool MouseControlAPI::PatternToRegex(const std::string &pattern, std::regex &reg
bool MouseControlAPI::ProbeForMapping(uint8_t &device_id)
{
- if (mouse_config.no_mouse)
+ if (IsNoMouseMode())
return false;
manymouse.RescanIfSafe();
@@ -396,7 +703,7 @@ bool MouseControlAPI::ProbeForMapping(uint8_t &device_id)
bool MouseControlAPI::Map(const MouseInterfaceId interface_id, const uint8_t device_idx)
{
- if (mouse_config.no_mouse)
+ if (IsNoMouseMode())
return false;
auto mouse_interface = MouseInterface::Get(interface_id);
@@ -408,15 +715,17 @@ bool MouseControlAPI::Map(const MouseInterfaceId interface_id, const uint8_t dev
bool MouseControlAPI::Map(const MouseInterfaceId interface_id, const std::regex &regex)
{
- if (mouse_config.no_mouse)
+ if (IsNoMouseMode())
return false;
manymouse.RescanIfSafe();
const auto idx = manymouse.GetIdx(regex);
if (idx >= mouse_info.physical.size())
return false;
+ const auto result = Map(interface_id, idx);
- return Map(interface_id, idx);
+ MOUSE_UpdateGFX();
+ return result;
}
bool MouseControlAPI::UnMap(const MouseControlAPI::ListIDs &list_ids)
@@ -425,6 +734,7 @@ bool MouseControlAPI::UnMap(const MouseControlAPI::ListIDs &list_ids)
for (auto &interface : list)
interface->ConfigUnMap();
+ MOUSE_UpdateGFX();
return !list.empty();
}
@@ -443,6 +753,7 @@ bool MouseControlAPI::Reset(const MouseControlAPI::ListIDs &list_ids)
for (auto &interface : list)
interface->ConfigReset();
+ MOUSE_UpdateGFX();
return !list.empty();
}
@@ -546,8 +857,8 @@ const std::string &MouseControlAPI::GetValidMinRateStr()
std::string MouseControlAPI::GetInterfaceNameStr(const MouseInterfaceId interface_id)
{
switch (interface_id) {
- case MouseInterfaceId::DOS: return "DOS";
- case MouseInterfaceId::PS2: return "PS/2";
+ case MouseInterfaceId::DOS: return "DOS";
+ case MouseInterfaceId::PS2: return "PS/2";
case MouseInterfaceId::COM1: return "COM1";
case MouseInterfaceId::COM2: return "COM2";
case MouseInterfaceId::COM3: return "COM3";
@@ -586,38 +897,36 @@ bool MouseControlAPI::ResetMinRate(const MouseControlAPI::ListIDs &list_ids)
// Initialization
// ***************************************************************************
-void MOUSE_SetConfigSeamless(const bool seamless)
+void MOUSE_StartupIfReady()
{
- // Called during SDL initialization
- mouse_config.seamless = seamless;
- MOUSE_NotifyStateChanged();
-
- // Just in case it is also called later
- for (auto &interface : mouse_interfaces)
- interface->UpdateConfig();
-
- // Start mouse emulation if ready
- mouse_shared.ready_config_sdl = true;
- MOUSE_Startup();
-}
-
-void MOUSE_SetConfigNoMouse()
-{
- // NOTE: if it is decided to not allow enabling/disabling
- // this during runtime, add button click releases for all
- // the mouse buttons
- mouse_config.no_mouse = true;
+ if (mouse_shared.started ||
+ !mouse_shared.ready_init ||
+ !mouse_shared.ready_config ||
+ !mouse_shared.ready_gfx)
+ return;
- // Start mouse emulation if ready
- mouse_shared.ready_config_sdl = true;
- MOUSE_Startup();
-}
+ switch (mouse_config.capture) {
+ case MouseCapture::Seamless:
+ LOG_MSG("MOUSE: Will move seamlessly: left and right button clicks won't capture the mouse");
+ break;
+ case MouseCapture::OnClick:
+ LOG_MSG("MOUSE: Will be captured after the first left or right button click");
+ break;
+ case MouseCapture::OnStart:
+ LOG_MSG("MOUSE: Will be captured immediately on start");
+ break;
+ case MouseCapture::NoMouse:
+ LOG_MSG("MOUSE: Control is disabled");
+ break;
+ default: assert(false); break;
+ }
-void MOUSE_Startup()
-{
- if (mouse_shared.started || !mouse_shared.ready_startup_sequence ||
- !mouse_shared.ready_config_mouse || !mouse_shared.ready_config_sdl)
- return;
+ if (mouse_config.capture != MouseCapture::NoMouse) {
+ LOG_MSG("MOUSE: Middle button will %s",
+ mouse_config.middle_release
+ ? "capture/release the mouse (clicks not sent to the game/program)"
+ : "be sent to the game/program (clicks not used to capture/release)");
+ }
// Callback for ps2 irq
auto call_int74 = CALLBACK_Allocate();
@@ -656,11 +965,19 @@ void MOUSE_Startup()
MouseInterface::InitAllInstances();
mouse_shared.started = true;
+
+ MOUSE_UpdateGFX();
+}
+
+void MOUSE_NotifyReadyGFX()
+{
+ mouse_shared.ready_gfx = true;
+ MOUSE_StartupIfReady();
}
void MOUSE_Init(Section * /*sec*/)
{
// Start mouse emulation if ready
- mouse_shared.ready_startup_sequence = true;
- MOUSE_Startup();
+ mouse_shared.ready_init = true;
+ MOUSE_StartupIfReady();
}
diff --git a/src/hardware/mouse/mouse_common.cpp b/src/hardware/mouse/mouse_common.cpp
index eb526ce9b..e63de4a7d 100644
--- a/src/hardware/mouse/mouse_common.cpp
+++ b/src/hardware/mouse/mouse_common.cpp
@@ -29,9 +29,8 @@ CHECK_NARROWING();
// Common variables
// ***************************************************************************
-MouseInfo mouse_info;
+MouseInfo mouse_info;
MouseShared mouse_shared;
-MouseVideo mouse_video;
// ***************************************************************************
// Common helper calculations
diff --git a/src/hardware/mouse/mouse_common.h b/src/hardware/mouse/mouse_common.h
index a44779c84..8dedd9216 100644
--- a/src/hardware/mouse/mouse_common.h
+++ b/src/hardware/mouse/mouse_common.h
@@ -30,28 +30,21 @@
class MouseShared {
public:
bool active_bios = false; // true = BIOS has a registered callback
- bool active_dos = false; // true = DOS driver has a functioning callback
- bool active_vmm = false; // true = VMware-compatible driver is active
+ bool active_dos = false; // true = DOS driver has a functioning callback
+ bool active_vmm = false; // true = VMware-compatible driver is active
bool dos_cb_running = false; // true = DOS callback is running
// Readiness for initialization
- bool ready_startup_sequence = false;
- bool ready_config_mouse = false;
- bool ready_config_sdl = false;
+ bool ready_init = false; // if allowed to init in the main startup sequence
+ bool ready_config = false; // if configuration was read
+ bool ready_gfx = false; // if GFX subsystem is ready
bool started = false;
-};
-
-class MouseVideo {
-public:
- bool fullscreen = true;
- uint16_t res_x = 640; // resolution to which guest image is scaled,
- uint16_t res_y = 400; // excluding black borders
-
- uint16_t clip_x = 0; // clipping = size of black border (one side)
- uint16_t clip_y = 0;
+ // Screen size
+ uint32_t resolution_x = 640; // resolution to which guest image is scaled,
+ uint32_t resolution_y = 400; // excluding black borders
};
class MouseInfo {
@@ -60,11 +53,8 @@ public:
std::vector<MousePhysicalInfoEntry> physical = {};
};
-extern MouseInfo mouse_info; // information which can be shared externally
+extern MouseInfo mouse_info; // information which can be shared externally
extern MouseShared mouse_shared; // shared internal information
-extern MouseVideo mouse_video; // video information - resolution, clipping, etc.
-
-extern bool mouse_is_captured;
// ***************************************************************************
// Common helper calculations
diff --git a/src/hardware/mouse/mouse_config.cpp b/src/hardware/mouse/mouse_config.cpp
index f81735790..6474e54f0 100644
--- a/src/hardware/mouse/mouse_config.cpp
+++ b/src/hardware/mouse/mouse_config.cpp
@@ -26,7 +26,6 @@
#include "setup.h"
#include "string_utils.h"
#include "support.h"
-#include "video.h"
#include <cmath>
@@ -39,44 +38,53 @@ CHECK_NARROWING();
// #define ENABLE_EXPLORER_MOUSE
-MouseConfig mouse_config;
+MouseConfig mouse_config;
MousePredefined mouse_predefined;
-static struct {
- const std::string param_standard = "standard";
- const std::string param_intellimouse = "intellimouse";
+constexpr auto capture_type_seamless_str = "seamless";
+constexpr auto capture_type_onclick_str = "onclick";
+constexpr auto capture_type_onstart_str = "onstart";
+constexpr auto capture_type_nomouse_str = "nomouse";
+
+constexpr auto model_ps2_standard_str = "standard";
+constexpr auto model_ps2_intellimouse_str = "intellimouse";
#ifdef ENABLE_EXPLORER_MOUSE
- const std::string param_explorer = "explorer";
+constexpr auto model_ps2_explorer_str = "explorer";
#endif
-} models_ps2;
-
-static struct {
- const std::string param_2button = "2button";
- const std::string param_3button = "3button";
- const std::string param_wheel = "wheel";
- const std::string param_msm = "msm";
- const std::string param_2button_msm = "2button+msm";
- const std::string param_3button_msm = "3button+msm";
- const std::string param_wheel_msm = "wheel+msm";
-} models_com;
+
+constexpr auto model_com_2button_str = "2button";
+constexpr auto model_com_3button_str = "3button";
+constexpr auto model_com_wheel_str = "wheel";
+constexpr auto model_com_msm_str = "msm";
+constexpr auto model_com_2button_msm_str = "2button+msm";
+constexpr auto model_com_3button_msm_str = "3button+msm";
+constexpr auto model_com_wheel_msm_str = "wheel+msm";
+
+static const char *list_capture_types[] = {
+ capture_type_seamless_str,
+ capture_type_onclick_str,
+ capture_type_onstart_str,
+ capture_type_nomouse_str,
+ nullptr
+};
static const char *list_models_ps2[] = {
- models_ps2.param_standard.c_str(),
- models_ps2.param_intellimouse.c_str(),
+ model_ps2_standard_str,
+ model_ps2_intellimouse_str,
#ifdef ENABLE_EXPLORER_MOUSE
- models_ps2.param_explorer.c_str(),
+ model_ps2_explorer_str,
#endif
nullptr
};
static const char *list_models_com[] = {
- models_com.param_2button.c_str(),
- models_com.param_3button.c_str(),
- models_com.param_wheel.c_str(),
- models_com.param_msm.c_str(),
- models_com.param_2button_msm.c_str(),
- models_com.param_3button_msm.c_str(),
- models_com.param_wheel_msm.c_str(),
+ model_com_2button_str,
+ model_com_3button_str,
+ model_com_wheel_str,
+ model_com_msm_str,
+ model_com_2button_msm_str,
+ model_com_3button_msm_str,
+ model_com_wheel_msm_str,
nullptr
};
@@ -105,34 +113,49 @@ static const std::vector<uint16_t> list_rates = {
// issues.
};
+bool MouseConfig::ParseCaptureType(const std::string &capture_str, MouseCapture &capture)
+{
+ if (capture_str == capture_type_seamless_str)
+ capture = MouseCapture::Seamless;
+ else if (capture_str == capture_type_onclick_str)
+ capture = MouseCapture::OnClick;
+ else if (capture_str == capture_type_onstart_str)
+ capture = MouseCapture::OnStart;
+ else if (capture_str == capture_type_nomouse_str)
+ capture = MouseCapture::NoMouse;
+ else
+ return false;
+ return true;
+}
+
bool MouseConfig::ParseCOMModel(const std::string &model_str,
MouseModelCOM &model, bool &auto_msm)
{
- if (model_str == models_com.param_2button) {
+ if (model_str == model_com_2button_str) {
model = MouseModelCOM::Microsoft;
auto_msm = false;
return true;
- } else if (model_str == models_com.param_3button) {
+ } else if (model_str == model_com_3button_str) {
model = MouseModelCOM::Logitech;
auto_msm = false;
return true;
- } else if (model_str == models_com.param_wheel) {
+ } else if (model_str == model_com_wheel_str) {
model = MouseModelCOM::Wheel;
auto_msm = false;
return true;
- } else if (model_str == models_com.param_msm) {
+ } else if (model_str == model_com_msm_str) {
model = MouseModelCOM::MouseSystems;
auto_msm = false;
return true;
- } else if (model_str == models_com.param_2button_msm) {
+ } else if (model_str == model_com_2button_msm_str) {
model = MouseModelCOM::Microsoft;
auto_msm = true;
return true;
- } else if (model_str == models_com.param_3button_msm) {
+ } else if (model_str == model_com_3button_msm_str) {
model = MouseModelCOM::Logitech;
auto_msm = true;
return true;
- } else if (model_str == models_com.param_wheel_msm) {
+ } else if (model_str == model_com_wheel_msm_str) {
model = MouseModelCOM::Wheel;
auto_msm = true;
return true;
@@ -143,12 +166,12 @@ bool MouseConfig::ParseCOMModel(const std::string &model_str,
bool MouseConfig::ParsePS2Model(const std::string &model_str, MouseModelPS2 &model)
{
- if (model_str == models_ps2.param_standard)
+ if (model_str == model_ps2_standard_str)
model = MouseModelPS2::Standard;
- else if (model_str == models_ps2.param_intellimouse)
+ else if (model_str == model_ps2_intellimouse_str)
model = MouseModelPS2::IntelliMouse;
#ifdef ENABLE_EXPLORER_MOUSE
- else if (model_str == models_ps2.param_explorer)
+ else if (model_str == model_ps2_explorer_str)
model = MouseModelPS2::Explorer;
#endif
else
@@ -171,14 +194,25 @@ static void config_read(Section *section)
// Settings changeable during runtime
- mouse_config.dos_immediate = conf->Get_bool("dos_mouse_immediate");
- mouse_config.raw_input = conf->Get_bool("mouse_raw_input");
- GFX_SetMouseRawInput(mouse_config.raw_input);
+ std::string prop_str = conf->Get_string("mouse_capture");
+ MouseConfig::ParseCaptureType(prop_str, mouse_config.capture);
+
+ mouse_config.middle_release = conf->Get_bool("mouse_middle_release");
+ mouse_config.raw_input = conf->Get_bool("mouse_raw_input");
+ mouse_config.dos_immediate = conf->Get_bool("dos_mouse_immediate");
// Settings below should be read only once
- if (mouse_shared.ready_config_mouse) {
- MOUSE_NotifyStateChanged();
+ if (mouse_shared.ready_config) {
+
+ if (mouse_config.capture == MouseCapture::NoMouse) {
+ // If NoMouse got configured in runtime,
+ // immediately clear all the mapping
+ MouseControlAPI mouse_config_api;
+ mouse_config_api.UnMap(MouseControlAPI::ListIDs());
+ }
+
+ MOUSE_UpdateGFX();
return;
}
@@ -196,7 +230,7 @@ static void config_read(Section *section)
// PS/2 AUX port mouse configuration
- std::string prop_str = conf->Get_string("ps2_mouse_model");
+ prop_str = conf->Get_string("ps2_mouse_model");
MouseConfig::ParsePS2Model(prop_str, mouse_config.model_ps2);
// COM port mouse configuration
@@ -206,9 +240,9 @@ static void config_read(Section *section)
mouse_config.model_com,
mouse_config.model_com_auto_msm);
- // Start mouse emulation if ready
- mouse_shared.ready_config_mouse = true;
- MOUSE_Startup();
+ // Start mouse emulation if everything is ready
+ mouse_shared.ready_config = true;
+ MOUSE_StartupIfReady();
}
static void config_init(Section_prop &secprop)
@@ -216,13 +250,29 @@ static void config_init(Section_prop &secprop)
constexpr auto always = Property::Changeable::Always;
constexpr auto only_at_start = Property::Changeable::OnlyAtStart;
- Prop_bool *prop_bool = nullptr;
- Prop_int *prop_int = nullptr;
- Prop_string *prop_str = nullptr;
+ Prop_bool *prop_bool = nullptr;
+ Prop_int *prop_int = nullptr;
+ Prop_string *prop_str = nullptr;
PropMultiVal *prop_multi = nullptr;
// General configuration
+ prop_str = secprop.Add_string("mouse_capture", always,
+ capture_type_onstart_str);
+ assert(prop_str);
+ prop_str->Set_values(list_capture_types);
+ prop_str->Set_help(
+ "Choose a mouse control method:\n"
+ " onclick: Capture the mouse when clicking any button in the window.\n"
+ " onstart: Capture the mouse immediately on start.\n"
+ " seamless: Let the mouse move seamlessly; captures only with middle-click or\n"
+ " hotkey.\n"
+ " nomouse: Hide the mouse and don't send input to the game.");
+
+ prop_bool = secprop.Add_bool("mouse_middle_release", always, true);
+ prop_bool->Set_help("If true, middle-click will release the captured mouse, and also\n"
+ "capture when seamless.");
+
prop_multi = secprop.AddMultiVal("mouse_sensitivity", only_at_start, ",");
prop_multi->Set_help(
"Default mouse sensitivity. 100 is a base value, 150 is 150% sensitivity, etc.\n"
@@ -269,7 +319,8 @@ static void config_init(Section_prop &secprop)
// Physical mice configuration
- prop_str = secprop.Add_string("ps2_mouse_model", only_at_start, "intellimouse");
+ prop_str = secprop.Add_string("ps2_mouse_model", only_at_start,
+ model_ps2_intellimouse_str);
assert(prop_str);
prop_str->Set_values(list_models_ps2);
prop_str->Set_help(
@@ -282,7 +333,8 @@ static void config_init(Section_prop &secprop)
#endif
"Default: intellimouse");
- prop_str = secprop.Add_string("com_mouse_model", only_at_start, "wheel+msm");
+ prop_str = secprop.Add_string("com_mouse_model", only_at_start,
+ model_com_wheel_msm_str);
assert(prop_str);
prop_str->Set_values(list_models_com);
prop_str->Set_help(
diff --git a/src/hardware/mouse/mouse_config.h b/src/hardware/mouse/mouse_config.h
index b8e757342..caa52c2a9 100644
--- a/src/hardware/mouse/mouse_config.h
+++ b/src/hardware/mouse/mouse_config.h
@@ -59,6 +59,8 @@ extern MousePredefined mouse_predefined;
// Configuration file content
// ***************************************************************************
+enum class MouseCapture : uint8_t { Seamless, OnClick, OnStart, NoMouse };
+
enum class MouseModelPS2 : uint8_t {
// Values must match PS/2 protocol IDs
Standard = 0x00,
@@ -74,19 +76,9 @@ enum class MouseModelCOM : uint8_t {
MouseSystems
};
-enum class MouseModelBus : uint8_t {
- NoMouse,
- Bus,
- InPort,
-};
-
struct MouseConfig {
- // From [sdl] section
-
- bool no_mouse = false; // true = NoMouse selected in GUI
- bool seamless = false; // true = seamless mouse integration
-
- // From [mouse] section
+ MouseCapture capture = MouseCapture::OnStart;
+ bool middle_release = true;
int16_t sensitivity_x = 50; // default sensitivity values
int16_t sensitivity_y = 50;
@@ -103,6 +95,8 @@ struct MouseConfig {
// Helper functions for external modules
static const std::vector<uint16_t> &GetValidMinRateList();
+ static bool ParseCaptureType(const std::string &capture_str,
+ MouseCapture &capture);
static bool ParseCOMModel(const std::string &model_str,
MouseModelCOM &model, bool &auto_msm);
static bool ParsePS2Model(const std::string &model_str, MouseModelPS2 &model);
diff --git a/src/hardware/mouse/mouse_interfaces.cpp b/src/hardware/mouse/mouse_interfaces.cpp
index f2a3620a4..4015256c2 100644
--- a/src/hardware/mouse/mouse_interfaces.cpp
+++ b/src/hardware/mouse/mouse_interfaces.cpp
@@ -148,13 +148,14 @@ public:
~InterfaceDos() = default;
void NotifyMoved(MouseEvent &ev, const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs) override;
+ const uint32_t x_abs, const uint32_t y_abs) override;
void NotifyButton(MouseEvent &ev, const uint8_t idx,
const bool pressed) override;
void NotifyWheel(MouseEvent &ev, const int16_t w_rel) override;
-
void NotifyBooting() override;
+ void UpdateInputType() override;
+
private:
friend class MouseInterface;
@@ -163,7 +164,6 @@ private:
void Init() override;
- void UpdateRawMapped() override;
void UpdateMinRate() override;
void UpdateRate() override;
};
@@ -174,11 +174,13 @@ public:
~InterfacePS2() = default;
void NotifyMoved(MouseEvent &ev, const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs) override;
+ const uint32_t x_abs, const uint32_t y_abs) override;
void NotifyButton(MouseEvent &ev, const uint8_t idx,
const bool pressed) override;
void NotifyWheel(MouseEvent &ev, const int16_t w_rel) override;
+ void UpdateInputType() override;
+
private:
friend class MouseInterface;
@@ -187,7 +189,6 @@ private:
void Init() override;
- void UpdateRawMapped() override;
void UpdateSensitivity() override;
void UpdateRate() override;
@@ -201,7 +202,7 @@ public:
~InterfaceCOM() = default;
void NotifyMoved(MouseEvent &ev, const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs) override;
+ const uint32_t x_abs, const uint32_t y_abs) override;
void NotifyButton(MouseEvent &ev, const uint8_t idx,
const bool pressed) override;
void NotifyWheel(MouseEvent &ev, const int16_t w_rel) override;
@@ -263,8 +264,10 @@ void MouseInterface::InitAllInstances()
default: assert(false); break;
}
- for (auto interface : mouse_interfaces)
+ for (auto interface : mouse_interfaces) {
interface->Init();
+ interface->UpdateConfig();
+ }
}
MouseInterface *MouseInterface::Get(const MouseInterfaceId interface_id)
@@ -415,7 +418,7 @@ void MouseInterface::SetMapStatus(const MouseMapStatus status, const uint8_t dev
if (map_status != new_map_status || mapped_idx != new_mapped_idx)
ResetButtons();
if (map_status != new_map_status)
- UpdateRawMapped();
+ UpdateInputType();
if (mapped_idx != new_mapped_idx)
ManyMouseGlue::GetInstance().Map(new_mapped_idx, interface_id);
@@ -514,11 +517,11 @@ void MouseInterface::UnRegisterListener()
void MouseInterface::UpdateConfig()
{
- UpdateRawMapped();
+ UpdateInputType();
UpdateSensitivity();
}
-void MouseInterface::UpdateRawMapped() {}
+void MouseInterface::UpdateInputType() {}
void MouseInterface::UpdateSensitivity()
{
@@ -630,7 +633,7 @@ void InterfaceDos::Init()
}
void InterfaceDos::NotifyMoved(MouseEvent &ev, const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs)
+ const uint32_t x_abs, const uint32_t y_abs)
{
ev.dos_moved = MOUSEDOS_NotifyMoved(x_rel * sensitivity_coeff_x,
y_rel * sensitivity_coeff_y,
@@ -668,10 +671,12 @@ void InterfaceDos::NotifyBooting()
ManyMouseGlue::GetInstance().ShutdownIfSafe();
}
-void InterfaceDos::UpdateRawMapped()
+void InterfaceDos::UpdateInputType()
{
- MOUSEDOS_NotifyMapped(IsMapped());
- MOUSEDOS_NotifyRawInput(mouse_config.raw_input || IsMapped());
+ const bool use_relative = IsMapped() || MOUSE_IsCaptured();
+ const bool is_input_raw = IsMapped() || mouse_config.raw_input;
+
+ MOUSEDOS_NotifyInputType(use_relative, is_input_raw);
}
void InterfaceDos::UpdateMinRate()
@@ -698,7 +703,7 @@ void InterfacePS2::Init()
}
void InterfacePS2::NotifyMoved(MouseEvent &ev, const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs)
+ const uint32_t x_abs, const uint32_t y_abs)
{
const bool request_ps2 = MOUSEPS2_NotifyMoved(x_rel * sensitivity_coeff_x,
y_rel * sensitivity_coeff_y);
@@ -731,10 +736,12 @@ void InterfacePS2::NotifyWheel(MouseEvent &ev, const int16_t w_rel)
ev.request_ps2 = request_ps2 || request_vmm;
}
-void InterfacePS2::UpdateRawMapped()
+void InterfacePS2::UpdateInputType()
{
- MOUSEVMM_NotifyMapped(IsMapped());
- MOUSEVMM_NotifyRawInput(mouse_config.raw_input || IsMapped());
+ const bool use_relative = IsMapped() || MOUSE_IsCaptured();
+ const bool is_input_raw = IsMapped() || mouse_config.raw_input;
+
+ MOUSEVMM_NotifyInputType(use_relative, is_input_raw);
}
void InterfacePS2::UpdateSensitivity()
@@ -759,8 +766,8 @@ InterfaceCOM::InterfaceCOM(const uint8_t port_id)
mouse_predefined.sensitivity_com)
{}
-void InterfaceCOM::NotifyMoved(MouseEvent &, const float x_rel,
- const float y_rel, const uint16_t, const uint16_t)
+void InterfaceCOM::NotifyMoved(MouseEvent &, const float x_rel, const float y_rel,
+ const uint32_t, const uint32_t)
{
assert(listener);
diff --git a/src/hardware/mouse/mouse_interfaces.h b/src/hardware/mouse/mouse_interfaces.h
index 8974add8a..063ce34f6 100644
--- a/src/hardware/mouse/mouse_interfaces.h
+++ b/src/hardware/mouse/mouse_interfaces.h
@@ -27,20 +27,22 @@
// Main mouse module
// ***************************************************************************
-void MOUSE_Startup();
+void MOUSE_StartupIfReady();
void MOUSE_NotifyDisconnect(const MouseInterfaceId interface_id);
void MOUSE_NotifyFakePS2(); // fake PS/2 event, for VMware protocol support
void MOUSE_NotifyResetDOS();
-void MOUSE_NotifyStateChanged();
+
+bool MOUSE_IsCaptured();
+void MOUSE_UpdateGFX();
// ***************************************************************************
// DOS mouse driver
// ***************************************************************************
void MOUSEDOS_Init();
-void MOUSEDOS_NotifyMapped(const bool enabled);
-void MOUSEDOS_NotifyRawInput(const bool enabled);
+void MOUSEDOS_NotifyInputType(const bool new_use_relative,
+ const bool new_is_input_raw);
void MOUSEDOS_NotifyMinRate(const uint16_t value_hz);
void MOUSEDOS_DrawCursor();
@@ -51,7 +53,7 @@ Bitu MOUSEDOS_DoCallback(const uint8_t mask, const MouseButtons12S buttons_12S);
// - understands up to 3 buttons
bool MOUSEDOS_NotifyMoved(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs);
+ const uint32_t x_abs, const uint32_t y_abs);
bool MOUSEDOS_NotifyWheel(const int16_t w_rel);
uint8_t MOUSEDOS_UpdateMoved();
@@ -88,16 +90,16 @@ Bitu MOUSEBIOS_DoCallback();
// ***************************************************************************
void MOUSEVMM_Init();
-void MOUSEVMM_NotifyMapped(const bool enabled);
-void MOUSEVMM_NotifyRawInput(const bool enabled);
-void MOUSEVMM_NewScreenParams(const uint16_t x_abs, const uint16_t y_abs);
+void MOUSEVMM_NotifyInputType(const bool new_use_relative,
+ const bool new_is_input_raw);
+void MOUSEVMM_NewScreenParams(const uint32_t x_abs, const uint32_t y_abs);
void MOUSEVMM_Deactivate();
// - needs absolute mouse position
// - understands up to 3 buttons
bool MOUSEVMM_NotifyMoved(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs);
+ const uint32_t x_abs, const uint32_t y_abs);
bool MOUSEVMM_NotifyButton(const MouseButtons12S buttons_12S);
bool MOUSEVMM_NotifyWheel(const int16_t w_rel);
@@ -128,7 +130,7 @@ public:
static MouseInterface *GetSerial(const uint8_t port_id);
virtual void NotifyMoved(MouseEvent &ev, const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs) = 0;
+ const uint32_t x_abs, const uint32_t y_abs) = 0;
virtual void NotifyButton(MouseEvent &ev, const uint8_t idx,
const bool pressed) = 0;
virtual void NotifyWheel(MouseEvent &ev, const int16_t w_rel) = 0;
@@ -166,6 +168,7 @@ public:
void ConfigResetMinRate();
virtual void UpdateConfig();
+ virtual void UpdateInputType();
virtual void RegisterListener(CSerialMouse &listener_object);
virtual void UnRegisterListener();
@@ -182,7 +185,6 @@ protected:
void SetMapStatus(const MouseMapStatus status,
const uint8_t device_idx = idx_host_pointer);
- virtual void UpdateRawMapped();
virtual void UpdateSensitivity();
virtual void UpdateMinRate();
virtual void UpdateRate();
diff --git a/src/hardware/mouse/mouse_manymouse.cpp b/src/hardware/mouse/mouse_manymouse.cpp
index b4c736b3e..a2cd51023 100644
--- a/src/hardware/mouse/mouse_manymouse.cpp
+++ b/src/hardware/mouse/mouse_manymouse.cpp
@@ -229,6 +229,10 @@ void ManyMouseGlue::RescanIfSafe()
bool ManyMouseGlue::ProbeForMapping(uint8_t &device_id)
{
+ // Do not even try if NoMouse is configured
+ if (mouse_config.capture == MouseCapture::NoMouse)
+ return false;
+
// Wait a little to speedup screen update
constexpr uint32_t ticks_threshold = 50; // time to wait idle in PIC ticks
const auto pic_ticks_start = PIC_Ticks;
@@ -281,7 +285,7 @@ bool ManyMouseGlue::ProbeForMapping(uint8_t &device_id)
break;
}
- if (is_mapping_in_effect && !mouse_config.no_mouse)
+ if (is_mapping_in_effect)
PIC_AddEvent(manymouse_tick, tick_interval);
return success;
}
@@ -346,7 +350,7 @@ void ManyMouseGlue::MapFinalize()
continue;
is_mapping_in_effect = true;
- if (!mouse_config.no_mouse)
+ if (mouse_config.capture != MouseCapture::NoMouse)
PIC_AddEvent(manymouse_tick, tick_interval);
break;
}
@@ -361,7 +365,7 @@ void ManyMouseGlue::HandleEvent(const ManyMouseEvent &event, const bool critical
{
if (GCC_UNLIKELY(event.device >= mouse_info.physical.size()))
return; // device ID out of supported range
- if (GCC_UNLIKELY(mouse_config.no_mouse &&
+ if (GCC_UNLIKELY(mouse_config.capture == MouseCapture::NoMouse &&
event.type != MANYMOUSE_EVENT_DISCONNECT))
return; // mouse control disabled in GUI
@@ -435,7 +439,7 @@ void ManyMouseGlue::HandleEvent(const ManyMouseEvent &event, const bool critical
void ManyMouseGlue::Tick()
{
- assert(!mouse_config.no_mouse);
+ assert(mouse_config.capture != MouseCapture::NoMouse);
// Handle all the events from the queue
ManyMouseEvent event;
diff --git a/src/hardware/mouse/mouseif_dos_driver.cpp b/src/hardware/mouse/mouseif_dos_driver.cpp
index 81587c2e5..a1a5be573 100644
--- a/src/hardware/mouse/mouseif_dos_driver.cpp
+++ b/src/hardware/mouse/mouseif_dos_driver.cpp
@@ -76,8 +76,9 @@ static MouseButtons12S buttons = 0;
static float pos_x = 0.0f;
static float pos_y = 0.0f;
static int8_t counter_w = 0; // wheel counter
-static bool is_mapped = false; // true = physical mouse is mapped to this interface
-static bool raw_input = true; // true = no host mouse acceleration pre-applied
+
+static bool use_relative = true; // true = ignore absolute mouse position, use relative
+static bool is_input_raw = true; // true = no host mouse acceleration pre-applied
static bool rate_is_set = false; // true = rate was set by DOS application
static uint16_t rate_hz = 0;
@@ -90,8 +91,8 @@ static struct {
// Mouse movement
float x_rel = 0.0f;
float y_rel = 0.0f;
- uint16_t x_abs = 0;
- uint16_t y_abs = 0;
+ uint32_t x_abs = 0;
+ uint32_t y_abs = 0;
// Wheel movement
int16_t w_rel = 0;
@@ -569,7 +570,7 @@ void MOUSEDOS_DrawCursor()
static void update_driver_active()
{
mouse_shared.active_dos = (state.user_callback_mask != 0);
- MOUSE_NotifyStateChanged();
+ MOUSE_UpdateGFX();
}
static uint8_t get_reset_wheel_8bit()
@@ -895,22 +896,21 @@ static void move_cursor_captured(const float x_rel, const float y_rel)
}
static void move_cursor_seamless(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs)
+ const uint32_t x_abs, const uint32_t y_abs)
{
// Update mickey counters
update_mickeys_on_move(x_rel, y_rel);
- auto calculate = [](const uint16_t absolute,
- const uint16_t res,
- const uint16_t clip) {
- assert(res > 1u);
- return (static_cast<float>(absolute) - clip) /
- static_cast<float>(res - 1);
+ auto calculate = [](const uint32_t absolute,
+ const uint32_t resolution) {
+ assert(resolution > 1u);
+ return static_cast<float>(absolute) /
+ static_cast<float>(resolution - 1);
};
// Apply mouse movement to mimic host OS
- const float x = calculate(x_abs, mouse_video.res_x, mouse_video.clip_x);
- const float y = calculate(y_abs, mouse_video.res_y, mouse_video.clip_y);
+ const float x = calculate(x_abs, mouse_shared.resolution_x);
+ const float y = calculate(y_abs, mouse_shared.resolution_y);
// TODO: this is probably overcomplicated, especially
// the usage of relative movement - to be investigated
@@ -938,14 +938,6 @@ static void move_cursor_seamless(const float x_rel, const float y_rel,
}
}
-static bool is_captured()
-{
- // If DOS driver uses a mapped physical mouse, always consider it
- // captured, as we have no absolute mouse position from the host OS
-
- return mouse_is_captured || is_mapped;
-}
-
static uint8_t move_cursor()
{
const auto old_pos_x = get_pos_x();
@@ -954,14 +946,14 @@ static uint8_t move_cursor()
const auto old_mickey_x = static_cast<int16_t>(state.mickey_counter_x);
const auto old_mickey_y = static_cast<int16_t>(state.mickey_counter_y);
- if (is_captured()) {
+ if (use_relative) {
// For raw mouse input use our built-in pointer acceleration model
const float acceleration_coeff =
- raw_input ? MOUSE_GetBallisticsCoeff(
+ is_input_raw ? MOUSE_GetBallisticsCoeff(
speed_mickeys.Get() /
state.double_speed_threshold) *
2.0f
- : 2.0f;
+ : 2.0f;
const float tmp_x = pending.x_rel * acceleration_coeff *
state.sensitivity_coeff_x;
@@ -1076,16 +1068,15 @@ uint8_t MOUSEDOS_UpdateWheel()
}
bool MOUSEDOS_NotifyMoved(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs)
+ const uint32_t x_abs, const uint32_t y_abs)
{
// Check if an event is needed
bool event_needed = false;
- if (is_captured()) {
+ if (use_relative) {
// Uses relative mouse movements - processing is too complicated
// to easily predict whether the event can be safely omitted
event_needed = true;
- // TODO: it actually can be done - but it will require some
- // refactoring
+ // TODO: this can be done, but requyires refactoring
} else {
// Uses absolute mouse position (seamless mode), relative
// movements can wait to be reported - they are completely
@@ -1635,13 +1626,10 @@ Bitu MOUSEDOS_DoCallback(const uint8_t mask, const MouseButtons12S buttons_12S)
// which allows seamless mouse integration. It is also included in
// DOSBox-X and Dosemu2:
// - https://github.com/joncampbell123/dosbox-x/pull/3424
- // -
- // https://github.com/dosemu2/dosemu2/issues/1552#issuecomment-1100777880
- // -
- // https://github.com/dosemu2/dosemu2/commit/cd9d2dbc8e3d58dc7cbc92f172c0d447881526be
- // -
- // https://github.com/joncampbell123/dosbox-x/commit/aec29ce28eb4b520f21ead5b2debf370183b9f28
- reg_ah = (!is_captured() && mouse_moved) ? 1 : 0;
+ // - https://github.com/dosemu2/dosemu2/issues/1552#issuecomment-1100777880
+ // - https://github.com/dosemu2/dosemu2/commit/cd9d2dbc8e3d58dc7cbc92f172c0d447881526be
+ // - https://github.com/joncampbell123/dosbox-x/commit/aec29ce28eb4b520f21ead5b2debf370183b9f28
+ reg_ah = (!use_relative && mouse_moved) ? 1 : 0;
reg_al = mask;
reg_bl = buttons_12S.data;
@@ -1659,14 +1647,11 @@ Bitu MOUSEDOS_DoCallback(const uint8_t mask, const MouseButtons12S buttons_12S)
return CBRET_NONE;
}
-void MOUSEDOS_NotifyMapped(const bool enabled)
-{
- is_mapped = enabled;
-}
-
-void MOUSEDOS_NotifyRawInput(const bool enabled)
+void MOUSEDOS_NotifyInputType(const bool new_use_relative,
+ const bool new_is_input_raw)
{
- raw_input = enabled;
+ use_relative = new_use_relative;
+ is_input_raw = new_is_input_raw;
}
void MOUSEDOS_Init()
diff --git a/src/hardware/mouse/mouseif_ps2_bios.cpp b/src/hardware/mouse/mouseif_ps2_bios.cpp
index 5ea009bb6..b4ad95c63 100644
--- a/src/hardware/mouse/mouseif_ps2_bios.cpp
+++ b/src/hardware/mouse/mouseif_ps2_bios.cpp
@@ -438,14 +438,14 @@ void MOUSEBIOS_SetScaling21(const bool enable)
bool MOUSEBIOS_Enable()
{
mouse_shared.active_bios = callback_init;
- MOUSE_NotifyStateChanged();
+ MOUSE_UpdateGFX();
return callback_init;
}
bool MOUSEBIOS_Disable()
{
mouse_shared.active_bios = false;
- MOUSE_NotifyStateChanged();
+ MOUSE_UpdateGFX();
return true;
}
diff --git a/src/hardware/mouse/mouseif_virtual_machines.cpp b/src/hardware/mouse/mouseif_virtual_machines.cpp
index b2133bab6..f17b8455f 100644
--- a/src/hardware/mouse/mouseif_virtual_machines.cpp
+++ b/src/hardware/mouse/mouseif_virtual_machines.cpp
@@ -62,19 +62,17 @@ union VMwareButtons {
bit_view<3, 1> middle;
};
-static constexpr io_port_t VMWARE_PORT = 0x5658u; // communication port
-// static constexpr io_port_t VMWARE_PORTHB = 0x5659u; // communication port,
-// high bandwidth
-static constexpr uint32_t VMWARE_MAGIC = 0x564D5868u; // magic number for all
- // VMware calls
-static constexpr uint32_t ABS_UPDATED = 4; // tells that new pointer
- // position is available
+static constexpr io_port_t VMWARE_PORT = 0x5658u; // communication port
+// static constexpr io_port_t VMWARE_PORTHB = 0x5659u; // communication port, high bandwidth
+static constexpr uint32_t VMWARE_MAGIC = 0x564D5868u; // magic number for all VMware calls
+static constexpr uint32_t ABS_UPDATED = 4; // tells about new pointer position
static constexpr uint32_t ABS_NOT_UPDATED = 0;
-static bool raw_input = true; // true = no host mouse acceleration pre-applied
-static bool is_mapped = false; // true = physical mouse is mapped to this interface
-static bool updated = false; // true = mouse state update waits to be picked up
-static VMwareButtons buttons; // state of mouse buttons, in VMware format
+static bool use_relative = true; // true = ignore absolute mouse position, use relative
+static bool is_input_raw = true; // true = no host mouse acceleration pre-applied
+
+static bool updated = false; // true = mouse state update waits to be picked up
+static VMwareButtons buttons; // state of mouse buttons, in VMware format
static uint16_t scaled_x = 0x7fff; // absolute position scaled from 0 to 0xffff
static uint16_t scaled_y = 0x7fff; // 0x7fff is a center position
static int8_t counter_w = 0; // wheel movement counter
@@ -96,16 +94,17 @@ static void MOUSEVMM_Activate()
if (!mouse_shared.active_vmm) {
mouse_shared.active_vmm = true;
LOG_MSG("MOUSE (PS/2): VMware protocol enabled");
- if (mouse_is_captured) {
- // If mouse is captured, prepare sane start settings
- // (center of the screen, will trigger mouse move event)
- pos_x = mouse_video.res_x / 2.0f;
- pos_y = mouse_video.res_y / 2.0f;
+ MOUSEPS2_UpdateButtonSquish();
+ MOUSE_UpdateGFX();
+ if (use_relative) {
+ // If no seamless integration, prepare sane
+ // cursor star position
+ pos_x = static_cast<float>(mouse_shared.resolution_x) / 2.0f;
+ pos_y = static_cast<float>(mouse_shared.resolution_y) / 2.0f;
scaled_x = 0;
scaled_y = 0;
+ MOUSE_NotifyFakePS2();
}
- MOUSEPS2_UpdateButtonSquish();
- MOUSE_NotifyStateChanged();
}
buttons.data = 0;
counter_w = 0;
@@ -117,20 +116,17 @@ void MOUSEVMM_Deactivate()
mouse_shared.active_vmm = false;
LOG_MSG("MOUSE (PS/2): VMware protocol disabled");
MOUSEPS2_UpdateButtonSquish();
- MOUSE_NotifyStateChanged();
+ MOUSE_UpdateGFX();
}
buttons.data = 0;
counter_w = 0;
}
-void MOUSEVMM_NotifyMapped(const bool enabled)
+void MOUSEVMM_NotifyInputType(const bool new_use_relative,
+ const bool new_is_input_raw)
{
- is_mapped = enabled;
-}
-
-void MOUSEVMM_NotifyRawInput(const bool enabled)
-{
- raw_input = enabled;
+ use_relative = new_use_relative;
+ is_input_raw = new_is_input_raw;
}
static void cmd_get_version()
@@ -189,7 +185,7 @@ static uint32_t port_read_vmware(const io_port_t, const io_width_t)
}
bool MOUSEVMM_NotifyMoved(const float x_rel, const float y_rel,
- const uint16_t x_abs, const uint16_t y_abs)
+ const uint32_t x_abs, const uint32_t y_abs)
{
if (!mouse_shared.active_vmm)
return false;
@@ -201,42 +197,38 @@ bool MOUSEVMM_NotifyMoved(const float x_rel, const float y_rel,
auto calculate = [](float &position,
const float relative,
- const uint16_t absolute,
- const uint16_t resolution,
- const uint16_t clip) {
+ const uint32_t absolute,
+ const uint32_t resolution) {
assert(resolution > 1u);
- if (mouse_is_captured || is_mapped) {
- // Mouse is captured, there is no need for pointer
- // integration with host OS - we can use relative
- // movement with configured sensitivity and (for
- // raw mouse input) our built-in pointer acceleration
- // model
-
- if (raw_input) {
- const auto coeff = MOUSE_GetBallisticsCoeff(
- speed_xy.Get());
- position += MOUSE_ClampRelativeMovement(
- relative * coeff);
+ if (use_relative) {
+ // Mouse is captured or mapped, there is no need for
+ // pointer integration with host OS - we can use
+ // relative movement with configured sensitivity and
+ // (for raw mouse input) our built-in pointer
+ // acceleration model
+
+ if (is_input_raw) {
+ const auto coeff = MOUSE_GetBallisticsCoeff(speed_xy.Get());
+ position += MOUSE_ClampRelativeMovement(relative * coeff);
} else
position += MOUSE_ClampRelativeMovement(relative);
} else
// Cursor position controlled by the host OS
- position = static_cast<float>(std::max(absolute - clip, 0));
+ position = static_cast<float>(absolute);
position = std::clamp(position, 0.0f, static_cast<float>(resolution));
const auto scale = static_cast<float>(UINT16_MAX) /
static_cast<float>(resolution - 1);
const auto tmp = std::min(static_cast<uint32_t>(UINT16_MAX),
- static_cast<uint32_t>(
- std::lround(position * scale)));
+ static_cast<uint32_t>(std::lround(position * scale)));
return static_cast<uint16_t>(tmp);
};
- scaled_x = calculate(pos_x, x_rel, x_abs, mouse_video.res_x, mouse_video.clip_x);
- scaled_y = calculate(pos_y, y_rel, y_abs, mouse_video.res_y, mouse_video.clip_y);
+ scaled_x = calculate(pos_x, x_rel, x_abs, mouse_shared.resolution_x);
+ scaled_y = calculate(pos_y, y_rel, y_abs, mouse_shared.resolution_y);
// Filter out unneeded events (like sub-pixel mouse movements,
// which won't change guest side mouse state)
@@ -282,7 +274,7 @@ bool MOUSEVMM_NotifyWheel(const int16_t w_rel)
return true;
}
-void MOUSEVMM_NewScreenParams(const uint16_t x_abs, const uint16_t y_abs)
+void MOUSEVMM_NewScreenParams(const uint32_t x_abs, const uint32_t y_abs)
{
// Report a fake mouse movement
if (MOUSEVMM_NotifyMoved(0.0f, 0.0f, x_abs, y_abs) && mouse_shared.active_vmm)