From 1ea6c5485e212b2c64bcd1d9112d2560f8fb654d Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Thu, 17 Sep 2020 15:16:45 +0200 Subject: [PATCH 01/13] Added mouse support to input gui --- src/common/input/DInputKeyboardMouse.cpp | 125 ++++++++--------------- src/common/input/DInputKeyboardMouse.h | 18 ++-- 2 files changed, 51 insertions(+), 92 deletions(-) diff --git a/src/common/input/DInputKeyboardMouse.cpp b/src/common/input/DInputKeyboardMouse.cpp index 15debc8af..e47f7f62c 100644 --- a/src/common/input/DInputKeyboardMouse.cpp +++ b/src/common/input/DInputKeyboardMouse.cpp @@ -60,26 +60,27 @@ namespace DInput // other devices so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse" LPDIRECTINPUTDEVICE8 kb_device = nullptr; - //LPDIRECTINPUTDEVICE8 mo_device = nullptr; + LPDIRECTINPUTDEVICE8 mo_device = nullptr; if (SUCCEEDED(idi8->CreateDevice(GUID_SysKeyboard, &kb_device, nullptr)) && SUCCEEDED(kb_device->SetDataFormat(&c_dfDIKeyboard)) && - SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) //&& - //SUCCEEDED(idi8->CreateDevice(GUID_SysMouse, &mo_device, nullptr)) && - //SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2)) && - //SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)) && + SUCCEEDED(idi8->CreateDevice(GUID_SysMouse, &mo_device, nullptr)) && + SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2)) && + SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) { - g_InputDeviceManager.AddDevice(std::make_shared(kb_device)); + g_InputDeviceManager.AddDevice(std::make_shared(kb_device, mo_device)); bKbMoEnumerated = true; return; } - if (kb_device) + if (kb_device) { kb_device->Release(); -#if 0 - if (mo_device) + } + + if (mo_device) { mo_device->Release(); -#endif + } } void PopulateDevices() @@ -104,36 +105,40 @@ namespace DInput PopulateDevices(); } - KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device) - : m_kb_device(kb_device)//, m_mo_device(mo_device) + KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device) + : m_kb_device(kb_device), m_mo_device(mo_device) { m_kb_device->Acquire(); - //m_mo_device->Acquire(); + m_mo_device->Acquire(); - memset(&m_state_in, 0, sizeof(m_state_in)); + std::memset(&m_state_in, 0, sizeof(m_state_in)); // KEYBOARD // add keys for (uint8_t i = 0; i < sizeof(named_keys) / sizeof(*named_keys); ++i) { AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code])); } -#if 0 + // MOUSE // get caps DIDEVCAPS mouse_caps; - memset(&mouse_caps, 0, sizeof(mouse_caps)); + std::memset(&mouse_caps, 0, sizeof(mouse_caps)); mouse_caps.dwSize = sizeof(mouse_caps); m_mo_device->GetCapabilities(&mouse_caps); + // mouse buttons for (unsigned char i = 0; i < mouse_caps.dwButtons; ++i) { AddInput(new Button(i, m_state_in.mouse.rgbButtons[i])); } - // cursor, with a hax for-loop - for (unsigned int i = 0; i < 4; ++i) { - AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1))); + // mouse axes + for (unsigned int i = 0; i < mouse_caps.dwAxes; ++i) { + const LONG &ax = (&m_state_in.mouse.lX)[i]; + + // each axis gets a negative and a positive input instance associated with it + AddInput(new Axis(i, ax, (2 == i) ? -10 : -80)); + AddInput(new Axis(i, ax, -(2 == i) ? 10 : 80)); } -#endif } KeyboardMouse::~KeyboardMouse() @@ -141,85 +146,45 @@ namespace DInput // kb m_kb_device->Unacquire(); m_kb_device->Release(); -#if 0 + // mouse m_mo_device->Unacquire(); m_mo_device->Release(); -#endif - } - - void GetMousePos(ControlState* const x, ControlState* const y) - { - POINT point = { 1, 1 }; - GetCursorPos(&point); - // Get the cursor position relative to the upper left corner of the current window - HWND hwnd = WindowFromPoint(point); - DWORD processId; - GetWindowThreadProcessId(hwnd, &processId); - if (processId == GetCurrentProcessId()) - { - ScreenToClient(hwnd, &point); - - // Get the size of the current window. - RECT rect; - GetClientRect(hwnd, &rect); - // Width and height is the size of the rendering window - unsigned int win_width = rect.right - rect.left; - unsigned int win_height = rect.bottom - rect.top; - - // Return the mouse position as a range from -1 to 1 - *x = (ControlState)point.x / (ControlState)win_width * 2 - 1; - *y = (ControlState)point.y / (ControlState)win_height * 2 - 1; - } - else - { - *x = (ControlState)0; - *y = (ControlState)0; - } } bool KeyboardMouse::UpdateInput() { - // Update keyboard and mouse button states + DIMOUSESTATE2 tmp_mouse; + HRESULT kb_hr = m_kb_device->GetDeviceState(sizeof(m_state_in.keyboard), &m_state_in.keyboard); - //HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(m_state_in.mouse), &m_state_in.mouse); + HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse); if (DIERR_INPUTLOST == kb_hr || DIERR_NOTACQUIRED == kb_hr) { m_kb_device->Acquire(); } -#if 0 + if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr) { m_mo_device->Acquire(); } -#endif - if (SUCCEEDED(kb_hr)) //&& SUCCEEDED(mo_hr)) + + if (SUCCEEDED(kb_hr) && SUCCEEDED(mo_hr)) { -#if 0 - ControlState temp_x, temp_y; + // NOTE: the /= 2 will cause the mouse input to naturally decay to zero if the mouse did not change its position + for (unsigned int i = 0; i < 3; ++i) { + ((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2; + } - // Update absolute mouse position - GetMousePos(&m_state_in.cursor.x, &m_state_in.cursor.y); + std::memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons)); - // Save current absolute mouse position - temp_x = m_state_in.cursor.x; - temp_y = m_state_in.cursor.y; - - // Update relative mouse motion - m_state_in.cursor.x -= m_state_in.cursor.last_x; - m_state_in.cursor.y -= m_state_in.cursor.last_y; - - // Update previous absolute mouse position - m_state_in.cursor.last_x = temp_x; - m_state_in.cursor.last_y = temp_y; -#endif return true; } + return false; } std::string KeyboardMouse::GetDeviceName() const { - return "Keyboard"; + return "KeyboardMouse"; } std::string KeyboardMouse::GetAPI() const @@ -237,11 +202,11 @@ namespace DInput return std::string("Click ") + char('0' + m_index); } - std::string KeyboardMouse::Cursor::GetName() const + std::string KeyboardMouse::Axis::GetName() const { - static char tmpstr[] = "Cursor .."; - tmpstr[7] = (char)('X' + m_index); - tmpstr[8] = (m_positive ? '+' : '-'); + static char tmpstr[] = "Axis .."; + tmpstr[5] = (char)('X' + m_index); + tmpstr[6] = (m_range < 0 ? '-' : '+'); return tmpstr; } @@ -255,8 +220,8 @@ namespace DInput return (m_button != 0); } - ControlState KeyboardMouse::Cursor::GetState() const + ControlState KeyboardMouse::Axis::GetState() const { - return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0)); + return std::clamp(ControlState(m_axis) / m_range, 0.0, 1.0); } } diff --git a/src/common/input/DInputKeyboardMouse.h b/src/common/input/DInputKeyboardMouse.h index 302e82670..1871c44d1 100644 --- a/src/common/input/DInputKeyboardMouse.h +++ b/src/common/input/DInputKeyboardMouse.h @@ -41,7 +41,7 @@ namespace DInput class KeyboardMouse : public InputDevice { public: - KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device); + KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device); ~KeyboardMouse(); std::string GetDeviceName() const override; std::string GetAPI() const override; @@ -73,33 +73,27 @@ namespace DInput const uint8_t m_index; }; - class Cursor : public Input + class Axis : public Input { public: - Cursor(uint8_t index, const ControlState& axis, const bool positive) - : m_axis(axis), m_index(index), m_positive(positive) {} + Axis(uint8_t index, const LONG &axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {} std::string GetName() const override; - bool IsDetectable() override { return true; } ControlState GetState() const override; private: - const ControlState& m_axis; + const LONG &m_axis; + const LONG m_range; const uint8_t m_index; - const bool m_positive; }; struct State { BYTE keyboard[256]; DIMOUSESTATE2 mouse; - struct - { - ControlState x, y, last_x, last_y; - } cursor; }; const LPDIRECTINPUTDEVICE8 m_kb_device; - //const LPDIRECTINPUTDEVICE8 m_mo_device; + const LPDIRECTINPUTDEVICE8 m_mo_device; State m_state_in; }; } From 6e265244cfced08de38506b6cd8ac75a99e04c9b Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sat, 19 Sep 2020 12:37:55 +0200 Subject: [PATCH 02/13] Allow mouse options to be changed at runtime --- src/common/IPCHybrid.hpp | 2 +- src/common/Settings.cpp | 118 ++++++++++++++----- src/common/Settings.hpp | 10 +- src/common/input/DInputKeyboardMouse.cpp | 6 +- src/common/input/DInputKeyboardMouse.h | 10 +- src/common/input/InputDevice.h | 2 + src/common/input/InputManager.cpp | 24 +++- src/common/input/InputManager.h | 2 + src/common/input/InputWindow.cpp | 18 +-- src/common/input/SdlJoystick.cpp | 14 ++- src/common/input/SdlJoystick.h | 2 +- src/common/win32/EmuShared.h | 12 +- src/common/win32/IPCWindows.cpp | 2 +- src/gui/DlgInputConfig.cpp | 141 ++++++++++++++++++----- src/gui/resource/Cxbx.rc | 34 ++++-- src/gui/resource/ResCxbx.h | 3 + 16 files changed, 306 insertions(+), 94 deletions(-) diff --git a/src/common/IPCHybrid.hpp b/src/common/IPCHybrid.hpp index 5a249f228..25fea5151 100644 --- a/src/common/IPCHybrid.hpp +++ b/src/common/IPCHybrid.hpp @@ -52,6 +52,6 @@ typedef enum class _IPC_UPDATE_KERNEL { , CONFIG_INPUT_SYNC } IPC_UPDATE_KERNEL; -void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const unsigned int value, const unsigned int hwnd); +void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const int value, const unsigned int hwnd); #endif diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 3b5482a3f..712faf5fa 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -62,8 +62,9 @@ uint16_t g_LibVersion_DSOUND = 0; // * 5: (ergo720), added new input gui settings and revision to core // * 6: (RadWolfie), added loader executable member to core, only for clean up loader expertimental setting // * 7: (RadWolfie), fix allowAdminPrivilege not align with other boolean members +// * 8: (ergo720), added general input settings /////////////////////////// -const unsigned int settings_version = 7; +const unsigned int settings_version = 8; Settings* g_Settings = nullptr; @@ -125,15 +126,21 @@ static struct { const char* adapter_name = "adapter_name"; } sect_network_keys; +static const char *section_input_general = "input-general"; +static struct { + const char *mo_axis_range = "MouseAxisRange"; + const char *mo_wheel_range = "MouseWheelRange"; +} sect_input_general; + static const char* section_controller_dinput = "controller-dinput"; static const char* section_controller_port = "controller-port"; -static const char* section_input = "input-port-"; +static const char* section_input_port = "input-port-"; static struct { const char* type = "Type"; const char* device = "DeviceName"; const char* config = "ProfileName"; -} sect_input; +} sect_input_port; static const char* section_input_profiles = "input-profile-"; static struct { @@ -366,6 +373,10 @@ bool Settings::LoadConfig() // ==== Core End ============ + // Delete/update legacy configs from previous revisions + RemoveLegacyConfigs(m_core.Revision); + m_core.Revision = settings_version; + // ==== Hack Begin ========== m_hacks.DisablePixelShaders = m_si.GetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, /*Default=*/false); @@ -435,21 +446,28 @@ bool Settings::LoadConfig() // ==== Network End ========= - // ==== Input Begin ==== + // ==== Input General Begin ==== + + m_input_general.MoAxisRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_axis_range, MO_AXIS_DEFAULT_RANGE); + m_input_general.MoWheelRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_wheel_range, MO_WHEEL_DEFAULT_RANGE); + + // ==== Input General End ============== + + // ==== Input Port Begin ==== for (int port_num = 0; port_num < 4; port_num++) { - std::string current_section = std::string(section_input) + std::to_string(port_num); - int ret = m_si.GetLongValue(current_section.c_str(), sect_input.type, -2); + std::string current_section = std::string(section_input_port) + std::to_string(port_num); + int ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.type, -2); if (ret == -2) { - m_input[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + m_input_port[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); continue; } - m_input[port_num].Type = ret; - m_input[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input.device); - m_input[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input.config)); + m_input_port[port_num].Type = ret; + m_input_port[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input_port.device); + m_input_port[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input_port.config)); } - // ==== Input End ============== + // ==== Input Port End ============== // ==== Input Profile Begin ==== std::array, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names; @@ -488,10 +506,6 @@ bool Settings::LoadConfig() // ==== Input Profile End ====== - // Delete legacy configs from previous revisions - RemoveLegacyConfigs(m_core.Revision); - m_core.Revision = settings_version; - return true; } @@ -582,18 +596,25 @@ bool Settings::Save(std::string file_path) // ==== Network End ========= - // ==== Input Begin ==== + // ==== Input General Begin ======= + + m_si.SetLongValue(section_input_general, sect_input_general.mo_axis_range, m_input_general.MoAxisRange, nullptr, false, true); + m_si.SetLongValue(section_input_general, sect_input_general.mo_wheel_range, m_input_general.MoWheelRange, nullptr, false, true); + + // ==== Input General End ========= + + // ==== Input Port Begin ==== for (int port_num = 0; port_num < 4; port_num++) { - std::string current_section = std::string(section_input) + std::to_string(port_num); - std::string quoted_prf_str = m_input[port_num].ProfileName.insert(0, "\""); + std::string current_section = std::string(section_input_port) + std::to_string(port_num); + std::string quoted_prf_str = m_input_port[port_num].ProfileName.insert(0, "\""); quoted_prf_str += "\""; - m_si.SetLongValue(current_section.c_str(), sect_input.type, m_input[port_num].Type, nullptr, false, true); - m_si.SetValue(current_section.c_str(), sect_input.device, m_input[port_num].DeviceName.c_str(), nullptr, true); - m_si.SetValue(current_section.c_str(), sect_input.config, quoted_prf_str.c_str(), nullptr, true); + m_si.SetLongValue(current_section.c_str(), sect_input_port.type, m_input_port[port_num].Type, nullptr, false, true); + m_si.SetValue(current_section.c_str(), sect_input_port.device, m_input_port[port_num].DeviceName.c_str(), nullptr, true); + m_si.SetValue(current_section.c_str(), sect_input_port.config, quoted_prf_str.c_str(), nullptr, true); } - // ==== Input End ============== + // ==== Input Port End ============== // ==== Input Profile Begin ==== @@ -693,19 +714,19 @@ void Settings::SyncToEmulator() // register input settings for (int i = 0; i < 4; i++) { - g_EmuShared->SetInputDevTypeSettings(&m_input[i].Type, i); - if (m_input[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { - g_EmuShared->SetInputDevNameSettings(m_input[i].DeviceName.c_str(), i); - auto it = std::find_if(m_input_profiles[m_input[i].Type].begin(), - m_input_profiles[m_input[i].Type].end(), [this, i](const auto& profile) { - if (profile.ProfileName == m_input[i].ProfileName) { + g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i); + if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + g_EmuShared->SetInputDevNameSettings(m_input_port[i].DeviceName.c_str(), i); + auto it = std::find_if(m_input_profiles[m_input_port[i].Type].begin(), + m_input_profiles[m_input_port[i].Type].end(), [this, i](const auto& profile) { + if (profile.ProfileName == m_input_port[i].ProfileName) { return true; } return false; }); - if (it != m_input_profiles[m_input[i].Type].end()) { + if (it != m_input_profiles[m_input_port[i].Type].end()) { char controls_name[XBOX_CTRL_NUM_BUTTONS][30]; - for (int index = 0; index < dev_num_buttons[m_input[i].Type]; index++) { + for (int index = 0; index < dev_num_buttons[m_input_port[i].Type]; index++) { strncpy(controls_name[index], it->ControlList[index].c_str(), 30); } g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, i); @@ -713,6 +734,9 @@ void Settings::SyncToEmulator() } } + g_EmuShared->SetInputMoAxisSettings(m_input_general.MoAxisRange); + g_EmuShared->SetInputMoWheelSettings(m_input_general.MoWheelRange); + // register Hacks settings g_EmuShared->SetHackSettings(&m_hacks); @@ -893,4 +917,38 @@ void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision) default: break; } + + if (CurrentRevision < 8) { + const std::string kb_str = "Keyboard"; + + for (unsigned port_num = 0; port_num < 4; ++port_num) { + std::string current_section = std::string(section_input_port) + std::to_string(port_num); + std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_port.device); + + // NOTE: with C++20, this can be simplified by simply calling device_name.ends_with() + if (device_name.length() >= kb_str.length()) { + if (device_name.compare(device_name.length() - kb_str.length(), kb_str.length(), kb_str) == 0) { + device_name += "Mouse"; + m_si.SetValue(current_section.c_str(), sect_input_port.device, device_name.c_str(), nullptr, true); + } + } + } + + for (unsigned index = 0; ; ++index) { + std::string current_section = std::string(section_input_profiles) + std::to_string(index); + if (m_si.GetSectionSize(current_section.c_str()) == -1) { + break; + } + + std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_profiles.device); + + // NOTE: with C++20, this can be simplified by simply calling device_name.ends_with() + if (device_name.length() >= kb_str.length()) { + if (device_name.compare(device_name.length() - kb_str.length(), kb_str.length(), kb_str) == 0) { + device_name += "Mouse"; + m_si.SetValue(current_section.c_str(), sect_input_profiles.device, device_name.c_str(), nullptr, true); + } + } + } + } } diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 0b7db2b0b..00ecba0f0 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -134,12 +134,18 @@ public: } m_audio; static_assert(sizeof(s_audio) == 0x4C, assert_check_shared_memory(s_audio)); - struct s_input { + struct s_input_general { + long MoAxisRange; + long MoWheelRange; + }; + s_input_general m_input_general; + + struct s_input_port { int Type; std::string DeviceName; std::string ProfileName; }; - std::array m_input; + std::array m_input_port; struct s_input_profiles { int Type; diff --git a/src/common/input/DInputKeyboardMouse.cpp b/src/common/input/DInputKeyboardMouse.cpp index e47f7f62c..598c92725 100644 --- a/src/common/input/DInputKeyboardMouse.cpp +++ b/src/common/input/DInputKeyboardMouse.cpp @@ -51,8 +51,6 @@ namespace DInput #include "DInputKeyboardCodes.h" }; - bool bKbMoEnumerated = false; - void InitKeyboardMouse(IDirectInput8* idi8) { // From Dolphin: "mouse and keyboard are a combined device, to allow shift+click and stuff @@ -136,8 +134,8 @@ namespace DInput const LONG &ax = (&m_state_in.mouse.lX)[i]; // each axis gets a negative and a positive input instance associated with it - AddInput(new Axis(i, ax, (2 == i) ? -10 : -80)); - AddInput(new Axis(i, ax, -(2 == i) ? 10 : 80)); + AddInput(new Axis(i, ax, (2 == i) ? mo_wheel_range_neg : mo_axis_range_neg)); + AddInput(new Axis(i, ax, (2 == i) ? mo_wheel_range_pos : mo_axis_range_pos)); } } diff --git a/src/common/input/DInputKeyboardMouse.h b/src/common/input/DInputKeyboardMouse.h index 1871c44d1..201b1febd 100644 --- a/src/common/input/DInputKeyboardMouse.h +++ b/src/common/input/DInputKeyboardMouse.h @@ -34,7 +34,11 @@ namespace DInput { - extern bool bKbMoEnumerated; + inline bool bKbMoEnumerated = false; + inline LONG mo_axis_range_pos = 0; + inline LONG mo_axis_range_neg = 0; + inline LONG mo_wheel_range_pos = 0; + inline LONG mo_wheel_range_neg = 0; void GetDeviceChanges(); void PopulateDevices(); @@ -76,13 +80,13 @@ namespace DInput class Axis : public Input { public: - Axis(uint8_t index, const LONG &axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {} + Axis(uint8_t index, const LONG &axis, const LONG &range) : m_axis(axis), m_range(range), m_index(index) {} std::string GetName() const override; ControlState GetState() const override; private: const LONG &m_axis; - const LONG m_range; + const LONG &m_range; const uint8_t m_index; }; diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index 4ff6d4465..be42e4cf3 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -48,6 +48,8 @@ #define DIRECTION_IN 0 #define DIRECTION_OUT 1 +#define MO_AXIS_DEFAULT_RANGE 10l +#define MO_WHEEL_DEFAULT_RANGE 80l typedef double ControlState; diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 826399a9f..ed96eb186 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -78,9 +78,9 @@ void InputDeviceManager::Initialize(bool is_gui) std::unique_lock lck(m_Mtx); m_bPendingShutdown = false; - m_PollingThread = std::thread([this]() { + m_PollingThread = std::thread([this, is_gui]() { XInput::Init(m_Mtx); - Sdl::Init(m_Mtx, m_Cv); + Sdl::Init(m_Mtx, m_Cv, is_gui); }); m_Cv.wait(lck, []() { @@ -93,6 +93,7 @@ void InputDeviceManager::Initialize(bool is_gui) CxbxKrnlCleanup("Failed to initialize input subsystem! Consult debug log for more information"); } + UpdateOpt(is_gui); RefreshDevices(); if (!is_gui) { @@ -519,3 +520,22 @@ std::shared_ptr InputDeviceManager::FindDevice(int usb_port, int du return nullptr; } } + +void InputDeviceManager::UpdateOpt(bool is_gui) +{ + if (!is_gui) { + long axis_range, wheel_range; + g_EmuShared->GetInputMoAxisSettings(&axis_range); + g_EmuShared->GetInputMoWheelSettings(&wheel_range); + DInput::mo_axis_range_pos = axis_range; + DInput::mo_wheel_range_pos = wheel_range; + DInput::mo_axis_range_neg = -(axis_range); + DInput::mo_wheel_range_neg = -(wheel_range); + } + else { + DInput::mo_axis_range_pos = g_Settings->m_input_general.MoAxisRange; + DInput::mo_wheel_range_pos = g_Settings->m_input_general.MoWheelRange; + DInput::mo_axis_range_neg = -(g_Settings->m_input_general.MoAxisRange); + DInput::mo_wheel_range_neg = -(g_Settings->m_input_general.MoWheelRange); + } +} diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index 60776d7fe..e3db17fea 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -82,6 +82,8 @@ public: std::shared_ptr FindDevice(int usb_port, int dummy) const; // attach/detach guest devices to the emulated machine void UpdateDevices(int port, bool ack); + // update input options + void UpdateOpt(bool is_gui); private: diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index c877cd9a2..eea57c8f5 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -337,8 +337,8 @@ void InputWindow::LoadProfile(const std::string& name) for (int index = 0; index < m_max_num_buttons; index++) { m_DeviceConfig->FindButtonByIndex(index)->UpdateText(profile->ControlList[index].c_str()); } - g_Settings->m_input[m_port_num].DeviceName = profile->DeviceName; - g_Settings->m_input[m_port_num].ProfileName = profile->ProfileName; + g_Settings->m_input_port[m_port_num].DeviceName = profile->DeviceName; + g_Settings->m_input_port[m_port_num].ProfileName = profile->ProfileName; m_bHasChanges = false; } @@ -364,8 +364,8 @@ bool InputWindow::SaveProfile(const std::string& name) } SendMessage(m_hwnd_profile_list, CB_SETCURSEL, SendMessage(m_hwnd_profile_list, CB_ADDSTRING, 0, reinterpret_cast(profile.ProfileName.c_str())), 0); - g_Settings->m_input[m_port_num].DeviceName = profile.DeviceName; - g_Settings->m_input[m_port_num].ProfileName = profile.ProfileName; + g_Settings->m_input_port[m_port_num].DeviceName = profile.DeviceName; + g_Settings->m_input_port[m_port_num].ProfileName = profile.ProfileName; g_Settings->m_input_profiles[m_dev_type].push_back(std::move(profile)); m_bHasChanges = false; return true; @@ -379,16 +379,16 @@ void InputWindow::DeleteProfile(const std::string& name) } SendMessage(m_hwnd_profile_list, CB_DELETESTRING, SendMessage(m_hwnd_profile_list, CB_FINDSTRINGEXACT, 1, reinterpret_cast(profile->ProfileName.c_str())), 0); - if (profile->ProfileName == g_Settings->m_input[m_port_num].ProfileName) { + if (profile->ProfileName == g_Settings->m_input_port[m_port_num].ProfileName) { SendMessage(m_hwnd_profile_list, CB_SETCURSEL, -1, 0); UpdateCurrentDevice(); ClearBindings(); - g_Settings->m_input[m_port_num].DeviceName = ""; - g_Settings->m_input[m_port_num].ProfileName = ""; + g_Settings->m_input_port[m_port_num].DeviceName = ""; + g_Settings->m_input_port[m_port_num].ProfileName = ""; m_bHasChanges = false; } else { - LoadProfile(g_Settings->m_input[m_port_num].ProfileName); + LoadProfile(g_Settings->m_input_port[m_port_num].ProfileName); } g_Settings->m_input_profiles[m_dev_type].erase(profile); } @@ -411,7 +411,7 @@ void InputWindow::LoadDefaultProfile() SendMessage(m_hwnd_profile_list, CB_ADDSTRING, 0, reinterpret_cast(g_Settings->m_input_profiles[m_dev_type][index].ProfileName.c_str())); } - LoadProfile(g_Settings->m_input[m_port_num].ProfileName); + LoadProfile(g_Settings->m_input_port[m_port_num].ProfileName); } void InputWindow::UpdateCurrentDevice() diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp index 9122aed22..33e19a747 100644 --- a/src/common/input/SdlJoystick.cpp +++ b/src/common/input/SdlJoystick.cpp @@ -57,7 +57,7 @@ namespace Sdl int SdlInitStatus = SDL_NOT_INIT; bool SdlPopulateOK = false; - void Init(std::mutex& Mtx, std::condition_variable& Cv) + void Init(std::mutex& Mtx, std::condition_variable& Cv, bool is_gui) { SDL_Event Event; uint32_t CustomEvent_t; @@ -155,9 +155,15 @@ namespace Sdl break; } else if (Event.type == UpdateInputEvent_t) { - XInput::GetDeviceChanges(); - DInput::GetDeviceChanges(); - g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), false); + if ((*static_cast(Event.user.data1)) == PORT_INVALID) { + g_InputDeviceManager.UpdateOpt(is_gui); + } + else { + XInput::GetDeviceChanges(); + DInput::GetDeviceChanges(); + g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), false); + } + delete Event.user.data1; Event.user.data1 = nullptr; } diff --git a/src/common/input/SdlJoystick.h b/src/common/input/SdlJoystick.h index 9cd646710..b6d18008e 100644 --- a/src/common/input/SdlJoystick.h +++ b/src/common/input/SdlJoystick.h @@ -51,7 +51,7 @@ namespace Sdl extern bool SdlPopulateOK; // initialize SDL - void Init(std::mutex& Mtx, std::condition_variable& Cv); + void Init(std::mutex& Mtx, std::condition_variable& Cv, bool is_gui); // shutdown SDL void DeInit(std::thread& Thr); // open the sdl joystick with the specified index diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index 7fb732120..f00fb99e2 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -149,6 +149,14 @@ class EmuShared : public Mutex Unlock(); } + // ****************************************************************** + // * Input option Accessors + // ****************************************************************** + void GetInputMoAxisSettings(long *axis) { Lock(); *axis = m_MoAxisRange; Unlock(); } + void SetInputMoAxisSettings(const long axis) { Lock(); m_MoAxisRange = axis; Unlock(); } + void GetInputMoWheelSettings(long *wheel) { Lock(); *wheel = m_MoWheelRange; Unlock(); } + void SetInputMoWheelSettings(const long wheel) { Lock(); m_MoWheelRange = wheel; Unlock(); } + // ****************************************************************** // * LLE Flags Accessors // ****************************************************************** @@ -291,7 +299,9 @@ class EmuShared : public Mutex int m_DeviceType[4]; char m_DeviceControlNames[4][XBOX_CTRL_NUM_BUTTONS][30]; // macro should be num of buttons of dev with highest num buttons char m_DeviceName[4][50]; - int m_Reserved99[28]; // Reserve space + long m_MoAxisRange; + long m_MoWheelRange; + int m_Reserved99[26]; // Reserve space // Settings class in memory should not be tampered by third-party. // Third-party program should only be allow to edit settings.ini file. diff --git a/src/common/win32/IPCWindows.cpp b/src/common/win32/IPCWindows.cpp index 19eb2b681..fc3c41228 100644 --- a/src/common/win32/IPCWindows.cpp +++ b/src/common/win32/IPCWindows.cpp @@ -76,7 +76,7 @@ void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value) } } -void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const unsigned int value, const unsigned int hwnd) +void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const int value, const unsigned int hwnd) { // Don't send if GUI process didn't create kernel process. if (hwnd == NULL) { diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index e2f24a9d4..7df6031a9 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -37,35 +37,45 @@ // Windows dialog procedure for the input menu static INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +// Window procedure of the subclass +LRESULT CALLBACK EditControlSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); HWND g_ChildWnd = NULL; +static bool g_bHasOptChanges = false; -void SyncInputSettings(int port_num, int dev_type) +void SyncInputSettings(int port_num, int dev_type, bool is_opt) { if (g_ChildWnd) { - // Sync updated input to kernel process to use run-time settings. - g_EmuShared->SetInputDevTypeSettings(&g_Settings->m_input[port_num].Type, port_num); + if (!is_opt) { + // Sync updated input to kernel process to use run-time settings. + g_EmuShared->SetInputDevTypeSettings(&g_Settings->m_input_port[port_num].Type, port_num); - if (dev_type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { - std::string dev_name = g_Settings->m_input[port_num].DeviceName; - std::string profile_name = g_Settings->m_input[port_num].ProfileName; + if (dev_type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + std::string dev_name = g_Settings->m_input_port[port_num].DeviceName; + std::string profile_name = g_Settings->m_input_port[port_num].ProfileName; - g_EmuShared->SetInputDevNameSettings(dev_name.c_str(), port_num); - auto it = std::find_if(g_Settings->m_input_profiles[dev_type].begin(), - g_Settings->m_input_profiles[dev_type].end(), [&profile_name](const auto& profile) { - if (profile.ProfileName == profile_name) { - return true; + g_EmuShared->SetInputDevNameSettings(dev_name.c_str(), port_num); + auto it = std::find_if(g_Settings->m_input_profiles[dev_type].begin(), + g_Settings->m_input_profiles[dev_type].end(), [&profile_name](const auto &profile) { + if (profile.ProfileName == profile_name) { + return true; + } + return false; + }); + if (it != g_Settings->m_input_profiles[dev_type].end()) { + char controls_name[XBOX_CTRL_NUM_BUTTONS][30]; + for (int index = 0; index < dev_num_buttons[dev_type]; index++) { + strncpy(controls_name[index], it->ControlList[index].c_str(), 30); } - return false; - }); - if (it != g_Settings->m_input_profiles[dev_type].end()) { - char controls_name[XBOX_CTRL_NUM_BUTTONS][30]; - for (int index = 0; index < dev_num_buttons[dev_type]; index++) { - strncpy(controls_name[index], it->ControlList[index].c_str(), 30); + g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, port_num); } - g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, port_num); } } + else { + g_EmuShared->SetInputMoAxisSettings(g_Settings->m_input_general.MoAxisRange); + g_EmuShared->SetInputMoWheelSettings(g_Settings->m_input_general.MoWheelRange); + port_num = PORT_INVALID; + } #if 0 // lle usb ipc_send_kernel_update(IPC_UPDATE_KERNEL::CONFIG_INPUT_SYNC, PORT_DEC(Gui2XboxPortArray[port_num]), reinterpret_cast(g_ChildWnd)); @@ -75,6 +85,15 @@ void SyncInputSettings(int port_num, int dev_type) } } +void UpdateInputOpt(HWND hwnd) +{ + char buffer[30]; + SendMessage(GetDlgItem(hwnd, IDC_MOUSE_RANGE), WM_GETTEXT, 30, reinterpret_cast(buffer)); + g_Settings->m_input_general.MoAxisRange = std::stol(buffer); + SendMessage(GetDlgItem(hwnd, IDC_WHEEL_RANGE), WM_GETTEXT, 30, reinterpret_cast(buffer)); + g_Settings->m_input_general.MoWheelRange = std::stol(buffer); +} + void ShowInputConfig(HWND hwnd, HWND ChildWnd) { g_InputDeviceManager.Initialize(true); @@ -90,20 +109,18 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR { case WM_INITDIALOG: { - HWND hHandle; - // Set window icon SetClassLong(hWndDlg, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_CXBX))); for (int i = 0, j = 0; i != 4; i++) { - hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + i); + HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + i); for (auto str : { "None", "MS Controller Duke", "MS Controller S" }) { LRESULT index = SendMessage(hHandle, CB_ADDSTRING, 0, reinterpret_cast(str)); SendMessage(hHandle, CB_SETITEMDATA, index, to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) + j); - if (g_Settings->m_input[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) + j) { + if (g_Settings->m_input_port[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) + j) { SendMessage(hHandle, CB_SETCURSEL, index, 0); - if (g_Settings->m_input[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + if (g_Settings->m_input_port[i].Type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { EnableWindow(GetDlgItem(hWndDlg, IDC_CONFIGURE_PORT1 + i), FALSE); } } @@ -111,11 +128,28 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR } j = 0; } + + for (auto i : { IDC_MOUSE_RANGE, IDC_WHEEL_RANGE }) { + HWND hEditControlArray = GetDlgItem(hWndDlg, i); + SetWindowSubclass(hEditControlArray, EditControlSubclassProc, i, 0); + SendMessage(hEditControlArray, EM_SETLIMITTEXT, 6, 0); + SendMessage(hEditControlArray, WM_SETTEXT, 0, reinterpret_cast((i == IDC_MOUSE_RANGE) ? + std::to_string(g_Settings->m_input_general.MoAxisRange).c_str() : + std::to_string(g_Settings->m_input_general.MoWheelRange).c_str())); + } + + // Reset option changes flag + g_bHasOptChanges = false; } break; case WM_CLOSE: { + if (g_bHasOptChanges) { + UpdateInputOpt(hWndDlg); + SyncInputSettings(0, 0, true); + } + g_InputDeviceManager.Shutdown(); g_ChildWnd = NULL; EndDialog(hWndDlg, wParam); @@ -144,6 +178,11 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { + if (g_bHasOptChanges) { + UpdateInputOpt(hWndDlg); + g_InputDeviceManager.UpdateOpt(true); + } + DialogBoxParam(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_XID_DUKE_CFG), hWndDlg, DlgXidControllerConfigProc, (DeviceType << 8) | port); } @@ -156,7 +195,7 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR DeviceType < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)); // Also inform the kernel process if it exists - SyncInputSettings(port, DeviceType); + SyncInputSettings(port, DeviceType, false); } } break; @@ -183,16 +222,66 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR EnableWindow(GetDlgItem(hWndDlg, IDC_CONFIGURE_PORT1 + port), TRUE); } - g_Settings->m_input[port].Type = dev_type; + g_Settings->m_input_port[port].Type = dev_type; // Also inform the kernel process if it exists - SyncInputSettings(port, dev_type); + SyncInputSettings(port, dev_type, false); } } break; + + case IDC_MOUSE_RANGE: + case IDC_WHEEL_RANGE: + { + if (HIWORD(wParam) == EN_CHANGE) { + g_bHasOptChanges = true; + } + } } } break; } return FALSE; } + +LRESULT CALLBACK EditControlSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + switch (uMsg) + { + // Remove the window subclass when this window is destroyed + case WM_NCDESTROY: + RemoveWindowSubclass(hWnd, EditControlSubclassProc, uIdSubclass); + break; + + // Override the default system behaviour and process WM_CHAR ourselves + case WM_GETDLGCODE: + if (lParam) { + LPMSG lpmsg = reinterpret_cast(lParam); + if (lpmsg->message == WM_CHAR) { + return DLGC_WANTCHARS; + } + } + break; + + case WM_CHAR: + { + // Make sure we only allow decimal numbers and some special keys to delete characters + if (!((wParam >= '0' && wParam <= '9') + || wParam == VK_CANCEL + || wParam == VK_CLEAR + || wParam == VK_DELETE + || wParam == VK_BACK)) + { + return FALSE; + } + } + break; + + // Don't allow pasting operations, they can be used to bypass the filtering done in WM_CHAR + case WM_PASTE: + return FALSE; + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} diff --git a/src/gui/resource/Cxbx.rc b/src/gui/resource/Cxbx.rc index c45e44164..7951e04c3 100644 --- a/src/gui/resource/Cxbx.rc +++ b/src/gui/resource/Cxbx.rc @@ -27,6 +27,10 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN + IDD_INPUT_CFG, DIALOG + BEGIN + END + IDD_VIRTUAL_SBC_FEEDBACK, DIALOG BEGIN LEFTMARGIN, 7 @@ -83,7 +87,7 @@ END // Dialog // -IDD_INPUT_CFG DIALOGEX 0, 0, 243, 124 +IDD_INPUT_CFG DIALOGEX 0, 0, 243, 175 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Cxbx-Reloaded : Input Configuration" FONT 8, "Verdana", 0, 0, 0x1 @@ -101,6 +105,11 @@ BEGIN LTEXT "Port 2",IDC_STATIC,23,48,20,10 LTEXT "Port 3",IDC_STATIC,23,69,20,10 LTEXT "Port 4",IDC_STATIC,23,90,20,10 + GROUPBOX "Options",IDC_INPUT_OPTIONS,13,119,217,49,WS_GROUP,WS_EX_CLIENTEDGE + EDITTEXT IDC_MOUSE_RANGE,95,129,121,14 + EDITTEXT IDC_WHEEL_RANGE,95,147,121,14 + LTEXT "Mouse axis range",IDC_STATIC,23,129,69,14,SS_CENTERIMAGE + LTEXT "Mouse wheel range",IDC_STATIC,23,146,68,14,SS_CENTERIMAGE END IDD_XID_DUKE_CFG DIALOGEX 0, 0, 528, 280 @@ -531,6 +540,11 @@ BEGIN 0 END +IDD_INPUT_CFG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -589,10 +603,10 @@ BEGIN MENUITEM "&Open Xbe...", ID_FILE_OPEN_XBE,MFT_STRING,MFS_ENABLED MENUITEM "Open D&ashboard...\tF7", ID_FILE_OPEN_DASHBOARD,MFT_STRING,MFS_ENABLED MENUITEM "&Close Xbe", ID_FILE_CLOSE_XBE,MFT_STRING,MFS_ENABLED - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR MENUITEM "&Save Xbe", ID_FILE_SAVEXBEFILE,MFT_STRING,MFS_ENABLED MENUITEM "Save Xbe &As...", ID_FILE_SAVEXBEFILEAS,MFT_STRING,MFS_ENABLED - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR POPUP "&Recent Xbe Files", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&0 : Recent Placeholder", ID_FILE_RXBE_0,MFT_STRING,MFS_ENABLED @@ -606,7 +620,7 @@ BEGIN MENUITEM "&8 : Recent Placeholder", ID_FILE_RXBE_8,MFT_STRING,MFS_ENABLED MENUITEM "&9 : Recent Placeholder", ID_FILE_RXBE_9,MFT_STRING,MFS_ENABLED END - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR MENUITEM "E&xit", ID_FILE_EXIT,MFT_STRING,MFS_ENABLED END POPUP "&Edit", 65535,MFT_STRING,MFS_ENABLED @@ -621,7 +635,7 @@ BEGIN MENUITEM "&Allow >64 MB", ID_EDIT_PATCH_ALLOW64MB,MFT_STRING,MFS_ENABLED MENUITEM "&Debug Mode", ID_EDIT_PATCH_DEBUGMODE,MFT_STRING,MFS_ENABLED END - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR POPUP "Dump &Xbe Info To...", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&File...", ID_EDIT_DUMPXBEINFOTO_FILE,MFT_STRING,MFS_ENABLED @@ -660,7 +674,7 @@ BEGIN MENUITEM "&Clear entire Symbol Cache", ID_CACHE_CLEARHLECACHE_ALL,MFT_STRING,MFS_ENABLED MENUITEM "&Rescan title Symbol Cache", ID_CACHE_CLEARHLECACHE_CURRENT,MFT_STRING,MFS_ENABLED END - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR POPUP "Experimental", 65535,MFT_STRING,MFS_ENABLED BEGIN POPUP "&LLE", 65535,MFT_STRING,MFS_ENABLED @@ -679,22 +693,22 @@ BEGIN END MENUITEM "Use Loader Executable", ID_USELOADEREXEC,MFT_STRING,MFS_ENABLED MENUITEM "Ignore Invalid Xbe Signature", ID_SETTINGS_IGNOREINVALIDXBESIG,MFT_STRING,MFS_ENABLED - MENUITEM "Ignore Invalid Xbe Sections", ID_SETTINGS_IGNOREINVALIDXBESEC, MFT_STRING, MFS_ENABLED + MENUITEM "Ignore Invalid Xbe Sections", ID_SETTINGS_IGNOREINVALIDXBESEC,MFT_STRING,MFS_ENABLED MENUITEM "Allow Admin Privilege", ID_SETTINGS_ALLOWADMINPRIVILEGE,MFT_STRING,MFS_ENABLED - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR MENUITEM "Reset To Defaults", ID_SETTINGS_INITIALIZE,MFT_STRING,MFS_ENABLED END POPUP "E&mulation", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&Start\tF5", ID_EMULATION_START,MFT_STRING,MFS_ENABLED MENUITEM "Start &Debugger...\tF9", ID_EMULATION_STARTDEBUGGER,MFT_STRING,MFS_ENABLED - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR MENUITEM "S&top\tF6", ID_EMULATION_STOP,MFT_STRING,MFS_ENABLED END POPUP "&Help", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&Go To The Official Cxbx Web Site...", ID_HELP_HOMEPAGE,MFT_STRING,MFS_ENABLED - MENUITEM "", -1, MFT_SEPARATOR + MENUITEM MFT_SEPARATOR MENUITEM "&About", ID_HELP_ABOUT,MFT_STRING,MFS_ENABLED END MENUITEM " ", ID_FPS,MFT_STRING | MFT_RIGHTJUSTIFY,MFS_ENABLED diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index 3cca3c009..19c3f7a20 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -304,6 +304,9 @@ #define IDC_RUMBLE_TEST 1302 #define IDC_NETWORK_ADAPTER 1303 #define IDC_LOG_POPUP_TESTCASE 1304 +#define IDC_INPUT_OPTIONS 1305 +#define IDC_MOUSE_RANGE 1306 +#define IDC_WHEEL_RANGE 1307 #define ID_FILE_EXIT 40005 #define ID_HELP_ABOUT 40008 #define ID_EMULATION_START 40009 From d091a0ee8f9160b7108c8fe5fdc33cc26bf3aa7e Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sat, 19 Sep 2020 14:20:09 +0200 Subject: [PATCH 03/13] Make binding the mouse in the input gui a bit easier --- src/common/input/InputWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index eea57c8f5..6d390c440 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -38,7 +38,7 @@ #define OUTPUT_TIMEOUT 3000 -constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55; // arbitrary number, using what Dolphin uses +constexpr ControlState INPUT_DETECT_THRESHOLD = 0.35; // NOTE: this should probably be made user configurable InputWindow* g_InputWindow = nullptr; From 92b6a9800d580689663b7c1985021ca68989100c Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sat, 19 Sep 2020 20:27:01 +0200 Subject: [PATCH 04/13] Fix an issue with sdl input binding --- src/common/input/InputDevice.h | 25 ------------------------- src/common/input/SdlJoystick.cpp | 3 ++- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index be42e4cf3..75d2d8210 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -146,31 +146,6 @@ public: m_Bindings[XButton] = Control; } -protected: - class FullAnalogSurface : public Input - { - public: - FullAnalogSurface(Input* Low, Input* High) : m_Low(*Low), m_High(*High) {} - ControlState GetState() const override - { - return (1 + m_High.GetState() - m_Low.GetState()) / 2; - } - - std::string GetName() const override { return m_Low.GetName() + *m_High.GetName().rbegin(); } - - private: - Input& m_Low; - Input& m_High; - }; - - void AddAnalogInputs(Input* Low, Input* High) - { - AddInput(Low); - AddInput(High); - AddInput(new FullAnalogSurface(Low, High)); - AddInput(new FullAnalogSurface(High, Low)); - } - private: // arbitrary ID assigned by to the device int m_ID; diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp index 33e19a747..0fe4ee835 100644 --- a/src/common/input/SdlJoystick.cpp +++ b/src/common/input/SdlJoystick.cpp @@ -301,7 +301,8 @@ namespace Sdl // get axes for (i = 0; i != NumAxes; ++i) { // each axis gets a negative and a positive input instance associated with it - AddAnalogInputs(new Axis(i, m_Joystick, -32768), new Axis(i, m_Joystick, 32767)); + AddInput(new Axis(i, m_Joystick, -32768)); + AddInput(new Axis(i, m_Joystick, 32767)); } // try to get supported ff effects From 6afcd6a3f34b1ffd3603d627da6dd51bf641fd45 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sat, 19 Sep 2020 20:33:59 +0200 Subject: [PATCH 05/13] Removed IsDetectable(), it's no longer necessary --- src/common/input/InputDevice.h | 1 - src/common/input/InputWindow.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index 75d2d8210..b8465fe5e 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -89,7 +89,6 @@ public: { public: virtual ControlState GetState() const = 0; - virtual bool IsDetectable() { return true; } }; class Output : public IoControl diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index 6d390c440..3975403c6 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -186,7 +186,7 @@ InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms) Device->UpdateInput(); std::vector::iterator state = initial_states.begin(); for (; i != e && s == e; i++, state++) { - if ((*i)->IsDetectable() && (*i)->GetState() > INPUT_DETECT_THRESHOLD) { + if ((*i)->GetState() > INPUT_DETECT_THRESHOLD) { if (*state == false) { // input was not initially pressed or it was but released afterwards s = i; From 6ecd89cd275916651e91d8b088fcd9fb79f73eb1 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 20 Sep 2020 00:59:20 +0200 Subject: [PATCH 06/13] Fixed a crash happening when the settings file doesn't exist --- src/common/Settings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 712faf5fa..6390a5b3c 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -923,7 +923,7 @@ void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision) for (unsigned port_num = 0; port_num < 4; ++port_num) { std::string current_section = std::string(section_input_port) + std::to_string(port_num); - std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_port.device); + std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_port.device, ""); // NOTE: with C++20, this can be simplified by simply calling device_name.ends_with() if (device_name.length() >= kb_str.length()) { @@ -940,7 +940,7 @@ void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision) break; } - std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_profiles.device); + std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_profiles.device, ""); // NOTE: with C++20, this can be simplified by simply calling device_name.ends_with() if (device_name.length() >= kb_str.length()) { From cd11b34415c34fc280bb40a8f40ff9b0541b488c Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 20 Sep 2020 11:14:16 +0200 Subject: [PATCH 07/13] Restored optional fields in the resource file for clang --- src/gui/resource/Cxbx.rc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/resource/Cxbx.rc b/src/gui/resource/Cxbx.rc index 7951e04c3..9f7c61b80 100644 --- a/src/gui/resource/Cxbx.rc +++ b/src/gui/resource/Cxbx.rc @@ -603,10 +603,10 @@ BEGIN MENUITEM "&Open Xbe...", ID_FILE_OPEN_XBE,MFT_STRING,MFS_ENABLED MENUITEM "Open D&ashboard...\tF7", ID_FILE_OPEN_DASHBOARD,MFT_STRING,MFS_ENABLED MENUITEM "&Close Xbe", ID_FILE_CLOSE_XBE,MFT_STRING,MFS_ENABLED - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR MENUITEM "&Save Xbe", ID_FILE_SAVEXBEFILE,MFT_STRING,MFS_ENABLED MENUITEM "Save Xbe &As...", ID_FILE_SAVEXBEFILEAS,MFT_STRING,MFS_ENABLED - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR POPUP "&Recent Xbe Files", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&0 : Recent Placeholder", ID_FILE_RXBE_0,MFT_STRING,MFS_ENABLED @@ -620,7 +620,7 @@ BEGIN MENUITEM "&8 : Recent Placeholder", ID_FILE_RXBE_8,MFT_STRING,MFS_ENABLED MENUITEM "&9 : Recent Placeholder", ID_FILE_RXBE_9,MFT_STRING,MFS_ENABLED END - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR MENUITEM "E&xit", ID_FILE_EXIT,MFT_STRING,MFS_ENABLED END POPUP "&Edit", 65535,MFT_STRING,MFS_ENABLED @@ -635,7 +635,7 @@ BEGIN MENUITEM "&Allow >64 MB", ID_EDIT_PATCH_ALLOW64MB,MFT_STRING,MFS_ENABLED MENUITEM "&Debug Mode", ID_EDIT_PATCH_DEBUGMODE,MFT_STRING,MFS_ENABLED END - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR POPUP "Dump &Xbe Info To...", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&File...", ID_EDIT_DUMPXBEINFOTO_FILE,MFT_STRING,MFS_ENABLED @@ -674,7 +674,7 @@ BEGIN MENUITEM "&Clear entire Symbol Cache", ID_CACHE_CLEARHLECACHE_ALL,MFT_STRING,MFS_ENABLED MENUITEM "&Rescan title Symbol Cache", ID_CACHE_CLEARHLECACHE_CURRENT,MFT_STRING,MFS_ENABLED END - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR POPUP "Experimental", 65535,MFT_STRING,MFS_ENABLED BEGIN POPUP "&LLE", 65535,MFT_STRING,MFS_ENABLED @@ -695,20 +695,20 @@ BEGIN MENUITEM "Ignore Invalid Xbe Signature", ID_SETTINGS_IGNOREINVALIDXBESIG,MFT_STRING,MFS_ENABLED MENUITEM "Ignore Invalid Xbe Sections", ID_SETTINGS_IGNOREINVALIDXBESEC,MFT_STRING,MFS_ENABLED MENUITEM "Allow Admin Privilege", ID_SETTINGS_ALLOWADMINPRIVILEGE,MFT_STRING,MFS_ENABLED - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR MENUITEM "Reset To Defaults", ID_SETTINGS_INITIALIZE,MFT_STRING,MFS_ENABLED END POPUP "E&mulation", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&Start\tF5", ID_EMULATION_START,MFT_STRING,MFS_ENABLED MENUITEM "Start &Debugger...\tF9", ID_EMULATION_STARTDEBUGGER,MFT_STRING,MFS_ENABLED - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR MENUITEM "S&top\tF6", ID_EMULATION_STOP,MFT_STRING,MFS_ENABLED END POPUP "&Help", 65535,MFT_STRING,MFS_ENABLED BEGIN MENUITEM "&Go To The Official Cxbx Web Site...", ID_HELP_HOMEPAGE,MFT_STRING,MFS_ENABLED - MENUITEM MFT_SEPARATOR + MENUITEM "", -1, MFT_SEPARATOR MENUITEM "&About", ID_HELP_ABOUT,MFT_STRING,MFS_ENABLED END MENUITEM " ", ID_FPS,MFT_STRING | MFT_RIGHTJUSTIFY,MFS_ENABLED From 01382d7e1d279935248338b2f4acc411e3d0f65b Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 20 Sep 2020 14:58:11 +0200 Subject: [PATCH 08/13] Lock the mouse cursor to the rendering window when the user presses F3 key --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 43 +++++++++++++++++++++++ src/core/kernel/init/CxbxKrnl.cpp | 2 +- src/core/kernel/init/CxbxKrnl.h | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index e91a1f049..d193ccd4d 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -675,6 +675,18 @@ void DrawUEM(HWND hWnd) EndPaint(hWnd, &ps); } +void CxbxClipCursor(HWND hWnd) +{ + RECT wnd_rect; + GetWindowRect(hWnd, &wnd_rect); + ClipCursor(&wnd_rect); +} + +void CxbxReleaseCursor() +{ + ClipCursor(nullptr); +} + inline DWORD GetXboxCommonResourceType(const xbox::DWORD XboxResource_Common) { DWORD dwCommonType = XboxResource_Common & X_D3DCOMMON_TYPE_MASK; @@ -1928,6 +1940,17 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar { VertexBufferConverter.PrintStats(); } + else if (wParam == VK_F3) + { + g_bClipCursor = !g_bClipCursor; + + if (g_bClipCursor) { + CxbxClipCursor(hWnd); + } + else { + CxbxReleaseCursor(); + } + } else if (wParam == VK_F6) { // For some unknown reason, F6 isn't handled in WndMain::WndProc @@ -1990,6 +2013,26 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar } break; } + + if (g_bClipCursor) { + CxbxClipCursor(hWnd); + } + } + break; + + case WM_MOVE: + { + if (g_bClipCursor) { + CxbxClipCursor(hWnd); + } + } + break; + + case WM_MOUSEMOVE: + { + if (g_bClipCursor) { + CxbxClipCursor(hWnd); + } } break; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index ca3a094ce..d8debf2a9 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -112,7 +112,7 @@ size_t g_SystemMaxMemory = 0; HANDLE g_CurrentProcessHandle = 0; // Set in CxbxKrnlMain bool g_bIsWine = false; - +bool g_bClipCursor = false; bool g_CxbxPrintUEM = false; ULONG g_CxbxFatalErrorCode = FATAL_ERROR_NONE; diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index ec93ab32f..09990d4a4 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -200,7 +200,7 @@ bool CxbxIsElevated(); extern uint32_t CxbxKrnl_KernelThunkTable[379]; extern bool g_bIsWine; - +extern bool g_bClipCursor; extern bool g_CxbxPrintUEM; extern ULONG g_CxbxFatalErrorCode; From 4c47d5a6d9d4e8895409edb2b3119ea0b65c4246 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 20 Sep 2020 17:57:16 +0200 Subject: [PATCH 09/13] Store ClipCursor flag in EmuShared --- src/common/win32/EmuShared.cpp | 2 +- src/common/win32/EmuShared.h | 8 +++++++- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 3 +++ src/core/kernel/init/CxbxKrnl.cpp | 3 +++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/common/win32/EmuShared.cpp b/src/common/win32/EmuShared.cpp index cca37b254..0f6dd5b4a 100644 --- a/src/common/win32/EmuShared.cpp +++ b/src/common/win32/EmuShared.cpp @@ -152,9 +152,9 @@ EmuShared::EmuShared() m_bDebugging = false; m_bEmulating_status = false; m_bFirstLaunch = false; + m_bClipCursor = false; // Reserve space (default to 0) - m_bReserved2 = false; m_bReserved3 = false; m_bReserved4 = false; m_Reserved5 = 0; diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index f00fb99e2..dcad678a2 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -244,6 +244,12 @@ class EmuShared : public Mutex void GetStorageLocation(char *path) { Lock(); strncpy(path, m_core.szStorageLocation, MAX_PATH); Unlock(); } void SetStorageLocation(const char *path) { Lock(); strncpy(m_core.szStorageLocation, path, MAX_PATH); Unlock(); } + // ****************************************************************** + // * ClipCursor flag Accessors + // ****************************************************************** + void GetClipCursorFlag(bool *value) { Lock(); *value = m_bClipCursor; Unlock(); } + void SetClipCursorFlag(const bool *value) { Lock(); m_bClipCursor = *value; Unlock(); } + // ****************************************************************** // * Reset specific variables to default for kernel mode. // ****************************************************************** @@ -292,7 +298,7 @@ class EmuShared : public Mutex int m_Reserved7[4]; #endif bool m_bFirstLaunch; - bool m_bReserved2; + bool m_bClipCursor; bool m_bReserved3; bool m_bReserved4; unsigned int m_dwKrnlProcID; // Only used for kernel mode level. diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index d193ccd4d..27a1a3bd2 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -1856,6 +1856,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar { case WM_DESTROY: { + CxbxReleaseCursor(); DeleteObject(g_hBgBrush); PostQuitMessage(0); return D3D_OK; // = 0 @@ -1943,6 +1944,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar else if (wParam == VK_F3) { g_bClipCursor = !g_bClipCursor; + g_EmuShared->SetClipCursorFlag(&g_bClipCursor); if (g_bClipCursor) { CxbxClipCursor(hWnd); @@ -2037,6 +2039,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar break; case WM_CLOSE: + CxbxReleaseCursor(); DestroyWindow(hWnd); CxbxKrnlShutDown(); break; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index d8debf2a9..0312491c3 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -681,6 +681,9 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res //g_EmuShared->SetIsReady(true); } + /* Initialize ClipCursor flag from EmuShared */ + g_EmuShared->GetClipCursorFlag(&g_bClipCursor); + /* Initialize popup message management from kernel side. */ log_init_popup_msg(); From dd24225477f0045ab8791c02682efe5a27736f53 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 20 Sep 2020 22:58:04 +0200 Subject: [PATCH 10/13] Ignore K/M input when the cursor is outside of the rendering window --- src/common/input/DInputKeyboardMouse.cpp | 5 +++++ src/common/input/DInputKeyboardMouse.h | 1 + src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 23 +++++++++++++++++++++++ src/core/kernel/init/CxbxKrnl.cpp | 2 ++ src/core/kernel/init/CxbxKrnl.h | 2 ++ 5 files changed, 33 insertions(+) diff --git a/src/common/input/DInputKeyboardMouse.cpp b/src/common/input/DInputKeyboardMouse.cpp index 598c92725..b0f4a1001 100644 --- a/src/common/input/DInputKeyboardMouse.cpp +++ b/src/common/input/DInputKeyboardMouse.cpp @@ -152,6 +152,11 @@ namespace DInput bool KeyboardMouse::UpdateInput() { + if (mo_leave_wnd) { + std::memset(&m_state_in, 0, sizeof(m_state_in)); + return true; + } + DIMOUSESTATE2 tmp_mouse; HRESULT kb_hr = m_kb_device->GetDeviceState(sizeof(m_state_in.keyboard), &m_state_in.keyboard); diff --git a/src/common/input/DInputKeyboardMouse.h b/src/common/input/DInputKeyboardMouse.h index 201b1febd..373b51611 100644 --- a/src/common/input/DInputKeyboardMouse.h +++ b/src/common/input/DInputKeyboardMouse.h @@ -35,6 +35,7 @@ namespace DInput { inline bool bKbMoEnumerated = false; + inline bool mo_leave_wnd = false; inline LONG mo_axis_range_pos = 0; inline LONG mo_axis_range_neg = 0; inline LONG mo_wheel_range_pos = 0; diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 27a1a3bd2..79f67caa3 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -64,6 +64,7 @@ #include "WalkIndexBuffer.h" #include "core\kernel\common\strings.hpp" // For uem_str #include "common\input\SdlJoystick.h" +#include "common\input\DInputKeyboardMouse.h" #include "common/util/strConverter.hpp" // for utf8_to_utf16 #include "VertexShaderSource.h" @@ -2030,11 +2031,33 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar } break; + case WM_MOUSELEAVE: + { + DInput::mo_leave_wnd = true; + g_bIsTrackingMoLeave = false; + g_bIsTrackingMoMove = true; + } + break; + case WM_MOUSEMOVE: { if (g_bClipCursor) { CxbxClipCursor(hWnd); } + + if (!g_bIsTrackingMoLeave) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.hwndTrack = hWnd; + tme.dwFlags = TME_LEAVE; + TrackMouseEvent(&tme); + g_bIsTrackingMoLeave = true; + + if (g_bIsTrackingMoMove) { + DInput::mo_leave_wnd = false; + g_bIsTrackingMoMove = false; + } + } } break; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 0312491c3..cf0908ad7 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -115,6 +115,8 @@ bool g_bIsWine = false; bool g_bClipCursor = false; bool g_CxbxPrintUEM = false; ULONG g_CxbxFatalErrorCode = FATAL_ERROR_NONE; +bool g_bIsTrackingMoLeave = false; +bool g_bIsTrackingMoMove = false; // Define function located in EmuXApi so we can call it from here void SetupXboxDeviceTypes(); diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index 09990d4a4..7820bff18 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -203,6 +203,8 @@ extern bool g_bIsWine; extern bool g_bClipCursor; extern bool g_CxbxPrintUEM; extern ULONG g_CxbxFatalErrorCode; +extern bool g_bIsTrackingMoLeave; +extern bool g_bIsTrackingMoMove; extern size_t g_SystemMaxMemory; From fc888cac2d71d8f7d7955f590a8e1c168d6dd376 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Mon, 21 Sep 2020 11:02:50 +0200 Subject: [PATCH 11/13] Addressed review remarks --- src/common/input/InputDevice.h | 4 ++++ src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 1 + src/core/kernel/init/CxbxKrnl.cpp | 4 +--- src/core/kernel/init/CxbxKrnl.h | 2 -- src/gui/resource/ResCxbx.h | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index b8465fe5e..155ecce1e 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -67,6 +67,10 @@ typedef enum class _XBOX_INPUT_DEVICE : int { } XBOX_INPUT_DEVICE; +// Flags that indicate that WM_MOUSELEAVE and WM_MOUSEMOVE respectively are being tracked in the rendering window procedure +inline bool g_bIsTrackingMoLeave = false; +inline bool g_bIsTrackingMoMove = false; + // Lookup array used to translate a gui port to an xbox usb port and vice versa extern int Gui2XboxPortArray[4]; diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 79f67caa3..aaca83458 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -82,6 +82,7 @@ using namespace std::literals::chrono_literals; // Global(s) HWND g_hEmuWindow = NULL; // rendering window +bool g_bClipCursor = false; // indicates that the mouse cursor should be confined inside the rendering window IDirect3DDevice *g_pD3DDevice = nullptr; // Direct3D Device // Static Variable(s) diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index cf0908ad7..f5a5dcc59 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -112,11 +112,9 @@ size_t g_SystemMaxMemory = 0; HANDLE g_CurrentProcessHandle = 0; // Set in CxbxKrnlMain bool g_bIsWine = false; -bool g_bClipCursor = false; + bool g_CxbxPrintUEM = false; ULONG g_CxbxFatalErrorCode = FATAL_ERROR_NONE; -bool g_bIsTrackingMoLeave = false; -bool g_bIsTrackingMoMove = false; // Define function located in EmuXApi so we can call it from here void SetupXboxDeviceTypes(); diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index 7820bff18..09990d4a4 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -203,8 +203,6 @@ extern bool g_bIsWine; extern bool g_bClipCursor; extern bool g_CxbxPrintUEM; extern ULONG g_CxbxFatalErrorCode; -extern bool g_bIsTrackingMoLeave; -extern bool g_bIsTrackingMoMove; extern size_t g_SystemMaxMemory; diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index 19c3f7a20..20c2c4b63 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -377,7 +377,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 136 #define _APS_NEXT_COMMAND_VALUE 40117 -#define _APS_NEXT_CONTROL_VALUE 1305 +#define _APS_NEXT_CONTROL_VALUE 1308 #define _APS_NEXT_SYMED_VALUE 109 #endif #endif From cb2bd277cdeda8bd91a582375a09dd678fcac530 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Wed, 23 Sep 2020 12:02:00 +0200 Subject: [PATCH 12/13] Hide the mouse cursor when hovering on the rendering window --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index aaca83458..3c96390cc 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -2037,6 +2037,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar DInput::mo_leave_wnd = true; g_bIsTrackingMoLeave = false; g_bIsTrackingMoMove = true; + ShowCursor(TRUE); } break; @@ -2053,6 +2054,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar tme.dwFlags = TME_LEAVE; TrackMouseEvent(&tme); g_bIsTrackingMoLeave = true; + ShowCursor(FALSE); if (g_bIsTrackingMoMove) { DInput::mo_leave_wnd = false; From cc032120bfcce01f698fe38befbe97cf6e3cae2d Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Thu, 24 Sep 2020 11:42:23 +0200 Subject: [PATCH 13/13] Renamed subclass procedure + moved option synchronization code --- src/gui/DlgInputConfig.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index 7df6031a9..83e437ee1 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -38,7 +38,7 @@ // Windows dialog procedure for the input menu static INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); // Window procedure of the subclass -LRESULT CALLBACK EditControlSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); +LRESULT CALLBACK WindowsCtrlSubProcNumericFilter(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); HWND g_ChildWnd = NULL; static bool g_bHasOptChanges = false; @@ -131,7 +131,7 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR for (auto i : { IDC_MOUSE_RANGE, IDC_WHEEL_RANGE }) { HWND hEditControlArray = GetDlgItem(hWndDlg, i); - SetWindowSubclass(hEditControlArray, EditControlSubclassProc, i, 0); + SetWindowSubclass(hEditControlArray, WindowsCtrlSubProcNumericFilter, i, 0); SendMessage(hEditControlArray, EM_SETLIMITTEXT, 6, 0); SendMessage(hEditControlArray, WM_SETTEXT, 0, reinterpret_cast((i == IDC_MOUSE_RANGE) ? std::to_string(g_Settings->m_input_general.MoAxisRange).c_str() : @@ -174,15 +174,15 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR assert(port != -1); HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + port); int DeviceType = SendMessage(hHandle, CB_GETITEMDATA, SendMessage(hHandle, CB_GETCURSEL, 0, 0), 0); + if (g_bHasOptChanges) { + UpdateInputOpt(hWndDlg); + g_InputDeviceManager.UpdateOpt(true); + } + switch (DeviceType) { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { - if (g_bHasOptChanges) { - UpdateInputOpt(hWndDlg); - g_InputDeviceManager.UpdateOpt(true); - } - DialogBoxParam(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_XID_DUKE_CFG), hWndDlg, DlgXidControllerConfigProc, (DeviceType << 8) | port); } @@ -244,14 +244,14 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR return FALSE; } -LRESULT CALLBACK EditControlSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, +LRESULT CALLBACK WindowsCtrlSubProcNumericFilter(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { switch (uMsg) { // Remove the window subclass when this window is destroyed case WM_NCDESTROY: - RemoveWindowSubclass(hWnd, EditControlSubclassProc, uIdSubclass); + RemoveWindowSubclass(hWnd, WindowsCtrlSubProcNumericFilter, uIdSubclass); break; // Override the default system behaviour and process WM_CHAR ourselves