Add support for mouse input as cursor position relative to the rendering window
This commit is contained in:
parent
bf6d8b804f
commit
240dc03dd5
|
@ -947,12 +947,9 @@ void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision)
|
||||||
std::string current_section = std::string(section_input_port) + std::to_string(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 (StrEndsWith(device_name, kb_str)) {
|
||||||
if (device_name.length() >= kb_str.length()) {
|
device_name += "Mouse";
|
||||||
if (device_name.compare(device_name.length() - kb_str.length(), kb_str.length(), kb_str) == 0) {
|
m_si.SetValue(current_section.c_str(), sect_input_port.device, device_name.c_str(), nullptr, true);
|
||||||
device_name += "Mouse";
|
|
||||||
m_si.SetValue(current_section.c_str(), sect_input_port.device, device_name.c_str(), nullptr, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,16 @@ LRESULT CALLBACK ButtonDukeSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
|
||||||
|
|
||||||
case WM_RBUTTONDOWN: {
|
case WM_RBUTTONDOWN: {
|
||||||
Button *button = reinterpret_cast<Button *>(dwRefData);
|
Button *button = reinterpret_cast<Button *>(dwRefData);
|
||||||
button->ClearText();
|
if (wParam & MK_SHIFT) {
|
||||||
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
static_cast<DukeInputWindow *>(button->GetWnd())->SwapMoCursorAxis(button);
|
||||||
if (button->GetId() == IDC_SET_MOTOR) {
|
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_SWAP);
|
||||||
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), RUMBLE_CLEAR);
|
}
|
||||||
|
else if (!(wParam & ~MK_RBUTTON)) {
|
||||||
|
button->ClearText();
|
||||||
|
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
||||||
|
if (button->GetId() == IDC_SET_MOTOR) {
|
||||||
|
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), RUMBLE_CLEAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -88,8 +94,14 @@ LRESULT CALLBACK ButtonSbcSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
|
||||||
|
|
||||||
case WM_RBUTTONDOWN: {
|
case WM_RBUTTONDOWN: {
|
||||||
Button *button = reinterpret_cast<Button *>(dwRefData);
|
Button *button = reinterpret_cast<Button *>(dwRefData);
|
||||||
button->ClearText();
|
if (wParam & MK_SHIFT) {
|
||||||
static_cast<SbcInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
static_cast<SbcInputWindow *>(button->GetWnd())->SwapMoCursorAxis(button);
|
||||||
|
static_cast<SbcInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_SWAP);
|
||||||
|
}
|
||||||
|
else if (!(wParam & ~MK_RBUTTON)) {
|
||||||
|
button->ClearText();
|
||||||
|
static_cast<SbcInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,12 @@ namespace DInput
|
||||||
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_neg : mo_axis_range_neg));
|
||||||
AddInput(new Axis(i, ax, (2 == i) ? mo_wheel_range_pos : mo_axis_range_pos));
|
AddInput(new Axis(i, ax, (2 == i) ? mo_wheel_range_pos : mo_axis_range_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mouse cursor
|
||||||
|
AddInput(new Cursor(0, m_state_in.cursor.x, -1.0));
|
||||||
|
AddInput(new Cursor(0, m_state_in.cursor.x, 1.0));
|
||||||
|
AddInput(new Cursor(1, m_state_in.cursor.y, -1.0));
|
||||||
|
AddInput(new Cursor(1, m_state_in.cursor.y, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyboardMouse::~KeyboardMouse()
|
KeyboardMouse::~KeyboardMouse()
|
||||||
|
@ -178,6 +184,7 @@ namespace DInput
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons));
|
std::memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons));
|
||||||
|
UpdateCursorPosition();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -185,6 +192,21 @@ namespace DInput
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeyboardMouse::UpdateCursorPosition()
|
||||||
|
{
|
||||||
|
POINT point = {};
|
||||||
|
GetCursorPos(&point);
|
||||||
|
ScreenToClient(m_hwnd, &point);
|
||||||
|
RECT rect;
|
||||||
|
GetClientRect(m_hwnd, &rect);
|
||||||
|
const auto width = std::max(rect.right - rect.left, 1l);
|
||||||
|
const auto height = std::max(rect.bottom - rect.top, 1l);
|
||||||
|
|
||||||
|
// Convert the window client coordinates to normalized device coordinates
|
||||||
|
m_state_in.cursor.x = ((2 * static_cast<ControlState>(point.x)) / width) - 1;
|
||||||
|
m_state_in.cursor.y = ((-2 * static_cast<ControlState>(point.y)) / height) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
std::string KeyboardMouse::GetDeviceName() const
|
std::string KeyboardMouse::GetDeviceName() const
|
||||||
{
|
{
|
||||||
return "KeyboardMouse";
|
return "KeyboardMouse";
|
||||||
|
@ -213,6 +235,14 @@ namespace DInput
|
||||||
return tmpstr;
|
return tmpstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string KeyboardMouse::Cursor::GetName() const
|
||||||
|
{
|
||||||
|
static char tmpstr[] = "Cursor ..";
|
||||||
|
tmpstr[7] = (char)('X' + m_index);
|
||||||
|
tmpstr[8] = (m_range == 1.0 ? '+' : '-');
|
||||||
|
return tmpstr;
|
||||||
|
}
|
||||||
|
|
||||||
ControlState KeyboardMouse::Key::GetState() const
|
ControlState KeyboardMouse::Key::GetState() const
|
||||||
{
|
{
|
||||||
return (m_key != 0);
|
return (m_key != 0);
|
||||||
|
@ -227,4 +257,9 @@ namespace DInput
|
||||||
{
|
{
|
||||||
return std::clamp(ControlState(m_axis) / m_range, 0.0, 1.0);
|
return std::clamp(ControlState(m_axis) / m_range, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ControlState KeyboardMouse::Cursor::GetState() const
|
||||||
|
{
|
||||||
|
return std::max(0.0, m_cursor / m_range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace DInput
|
||||||
std::string GetDeviceName() const override;
|
std::string GetDeviceName() const override;
|
||||||
std::string GetAPI() const override;
|
std::string GetAPI() const override;
|
||||||
bool UpdateInput() override;
|
bool UpdateInput() override;
|
||||||
|
void SetHwnd(HWND hwnd) { m_hwnd = hwnd; }
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -78,6 +79,7 @@ namespace DInput
|
||||||
const uint8_t m_index;
|
const uint8_t m_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// gives mouse input based on relative motion
|
||||||
class Axis : public Input
|
class Axis : public Input
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -91,14 +93,37 @@ namespace DInput
|
||||||
const uint8_t m_index;
|
const uint8_t m_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// gives mouse input based on cursor position relative to the rendering window
|
||||||
|
class Cursor : public Input
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Cursor(uint8_t index, const ControlState &cursor, const ControlState range)
|
||||||
|
: m_cursor(cursor), m_index(index), m_range(range) {}
|
||||||
|
std::string GetName() const override;
|
||||||
|
ControlState GetState() const override;
|
||||||
|
bool IsDetectable() const override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ControlState &m_cursor;
|
||||||
|
const ControlState m_range;
|
||||||
|
const uint8_t m_index;
|
||||||
|
};
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
BYTE keyboard[256];
|
BYTE keyboard[256];
|
||||||
DIMOUSESTATE2 mouse;
|
DIMOUSESTATE2 mouse;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ControlState x, y;
|
||||||
|
} cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void UpdateCursorPosition();
|
||||||
|
|
||||||
const LPDIRECTINPUTDEVICE8 m_kb_device;
|
const LPDIRECTINPUTDEVICE8 m_kb_device;
|
||||||
const LPDIRECTINPUTDEVICE8 m_mo_device;
|
const LPDIRECTINPUTDEVICE8 m_mo_device;
|
||||||
State m_state_in;
|
State m_state_in;
|
||||||
|
HWND m_hwnd;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ControlState GetState() const = 0;
|
virtual ControlState GetState() const = 0;
|
||||||
|
virtual bool IsDetectable() const { return true; };
|
||||||
};
|
};
|
||||||
|
|
||||||
class Output : public IoControl
|
class Output : public IoControl
|
||||||
|
|
|
@ -71,11 +71,12 @@ extern CXBX_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4]; // hle xinput
|
||||||
|
|
||||||
InputDeviceManager g_InputDeviceManager;
|
InputDeviceManager g_InputDeviceManager;
|
||||||
|
|
||||||
void InputDeviceManager::Initialize(bool is_gui)
|
void InputDeviceManager::Initialize(bool is_gui, HWND hwnd)
|
||||||
{
|
{
|
||||||
// Sdl::Init must be called last since it blocks when it succeeds
|
// Sdl::Init must be called last since it blocks when it succeeds
|
||||||
std::unique_lock<std::mutex> lck(m_Mtx);
|
std::unique_lock<std::mutex> lck(m_Mtx);
|
||||||
m_bPendingShutdown = false;
|
m_bPendingShutdown = false;
|
||||||
|
m_hwnd = hwnd;
|
||||||
|
|
||||||
m_PollingThread = std::thread([this, is_gui]() {
|
m_PollingThread = std::thread([this, is_gui]() {
|
||||||
XInput::Init(m_Mtx);
|
XInput::Init(m_Mtx);
|
||||||
|
@ -623,6 +624,12 @@ void InputDeviceManager::RefreshDevices()
|
||||||
m_Cv.wait(lck, []() {
|
m_Cv.wait(lck, []() {
|
||||||
return Sdl::SdlPopulateOK;
|
return Sdl::SdlPopulateOK;
|
||||||
});
|
});
|
||||||
|
for (auto &dev : m_Devices) {
|
||||||
|
if (StrStartsWith(dev->GetDeviceName(), "KeyboardMouse")) {
|
||||||
|
static_cast<DInput::KeyboardMouse *>(dev.get())->SetHwnd(m_hwnd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> InputDeviceManager::GetDeviceList() const
|
std::vector<std::string> InputDeviceManager::GetDeviceList() const
|
||||||
|
|
|
@ -123,7 +123,7 @@ CXBX_CONTROLLER_HOST_BRIDGE, *PCXBX_CONTROLLER_HOST_BRIDGE;
|
||||||
class InputDeviceManager
|
class InputDeviceManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Initialize(bool is_gui);
|
void Initialize(bool is_gui, HWND hwnd);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
// read/write the input/output from/to the device attached to the supplied xbox port
|
// read/write the input/output from/to the device attached to the supplied xbox port
|
||||||
bool UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type);
|
bool UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type);
|
||||||
|
@ -169,6 +169,8 @@ private:
|
||||||
std::thread m_PollingThread;
|
std::thread m_PollingThread;
|
||||||
// used to indicate that the manager is shutting down
|
// used to indicate that the manager is shutting down
|
||||||
bool m_bPendingShutdown;
|
bool m_bPendingShutdown;
|
||||||
|
// handle of the rendering or the input gui window
|
||||||
|
HWND m_hwnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern InputDeviceManager g_InputDeviceManager;
|
extern InputDeviceManager g_InputDeviceManager;
|
||||||
|
|
|
@ -121,7 +121,7 @@ InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms)
|
||||||
Device->UpdateInput();
|
Device->UpdateInput();
|
||||||
std::vector<bool>::iterator state = initial_states.begin();
|
std::vector<bool>::iterator state = initial_states.begin();
|
||||||
for (; i != e && s == e; i++, state++) {
|
for (; i != e && s == e; i++, state++) {
|
||||||
if ((*i)->GetState() > INPUT_DETECT_THRESHOLD) {
|
if ((*i)->IsDetectable() && ((*i)->GetState() > INPUT_DETECT_THRESHOLD)) {
|
||||||
if (*state == false) {
|
if (*state == false) {
|
||||||
// input was not initially pressed or it was but released afterwards
|
// input was not initially pressed or it was but released afterwards
|
||||||
s = i;
|
s = i;
|
||||||
|
@ -290,3 +290,65 @@ void InputWindow::UpdateCurrentDevice()
|
||||||
m_host_dev = device_name;
|
m_host_dev = device_name;
|
||||||
EnableDefaultButton();
|
EnableDefaultButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputWindow::SwapMoCursorAxis(Button *button)
|
||||||
|
{
|
||||||
|
// Axis X+ <-> Cursor X+
|
||||||
|
// Axis X- <-> Cursor X-
|
||||||
|
// Axis Y+ <-> Cursor Y-
|
||||||
|
// Axis Y- <-> Cursor Y+
|
||||||
|
if (StrEndsWith(m_host_dev, "KeyboardMouse")) {
|
||||||
|
assert(button != nullptr);
|
||||||
|
char control_name[HOST_BUTTON_NAME_LENGTH];
|
||||||
|
button->GetText(control_name, sizeof(control_name));
|
||||||
|
if (StrStartsWith(control_name, "Axis")) {
|
||||||
|
switch (control_name[5])
|
||||||
|
{
|
||||||
|
case 'X':
|
||||||
|
if (control_name[6] == '+') {
|
||||||
|
button->UpdateText("Cursor X+");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
button->UpdateText("Cursor X-");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Y':
|
||||||
|
if (control_name[6] == '+') {
|
||||||
|
button->UpdateText("Cursor Y-");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
button->UpdateText("Cursor Y+");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrStartsWith(control_name, "Cursor")) {
|
||||||
|
switch (control_name[7])
|
||||||
|
{
|
||||||
|
case 'X':
|
||||||
|
if (control_name[8] == '+') {
|
||||||
|
button->UpdateText("Axis X+");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
button->UpdateText("Axis X-");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Y':
|
||||||
|
if (control_name[8] == '+') {
|
||||||
|
button->UpdateText("Axis Y-");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
button->UpdateText("Axis Y+");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#define RUMBLE_TEST 6
|
#define RUMBLE_TEST 6
|
||||||
#define RUMBLE_CLEAR 7
|
#define RUMBLE_CLEAR 7
|
||||||
#define BUTTON_CLEAR 8
|
#define BUTTON_CLEAR 8
|
||||||
|
#define BUTTON_SWAP 9
|
||||||
|
|
||||||
#define XINPUT_DEFAULT 0
|
#define XINPUT_DEFAULT 0
|
||||||
#define DINPUT_DEFAULT 1
|
#define DINPUT_DEFAULT 1
|
||||||
|
@ -60,6 +61,7 @@ public:
|
||||||
virtual void UpdateProfile(const std::string& name, int command) = 0;
|
virtual void UpdateProfile(const std::string& name, int command) = 0;
|
||||||
void UpdateCurrentDevice();
|
void UpdateCurrentDevice();
|
||||||
bool IsProfileSaved();
|
bool IsProfileSaved();
|
||||||
|
void SwapMoCursorAxis(Button *button);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -280,3 +280,27 @@ std::string StripQuotes(const std::string& str)
|
||||||
{
|
{
|
||||||
return StripChars(str, "\"");
|
return StripChars(str, "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: with C++20, this can be replaced by simply calling full_str.ends_with()
|
||||||
|
bool StrEndsWith(const std::string &full_str, const std::string &substr)
|
||||||
|
{
|
||||||
|
if (full_str.length() >= substr.length()) {
|
||||||
|
if (full_str.compare(full_str.length() - substr.length(), substr.length(), substr) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: with C++20, this can be replaced by simply calling full_str.starts_with()
|
||||||
|
bool StrStartsWith(const std::string &full_str, const std::string &substr)
|
||||||
|
{
|
||||||
|
if (!full_str.empty()) {
|
||||||
|
if (full_str.rfind(substr, 0) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ bool Memory_RW(void* Addr, void* Buf, size_t Num, bool bIsWrite);
|
||||||
void unix2dos(std::string& string);
|
void unix2dos(std::string& string);
|
||||||
std::string StripSpaces(const std::string& str);
|
std::string StripSpaces(const std::string& str);
|
||||||
std::string StripQuotes(const std::string& str);
|
std::string StripQuotes(const std::string& str);
|
||||||
|
bool StrEndsWith(const std::string &full_str, const std::string &substr);
|
||||||
|
bool StrStartsWith(const std::string &full_str, const std::string &substr);
|
||||||
|
|
||||||
// Retrieves the underlying integer value of a scoped enumerator. It allows to avoid using static_cast every time
|
// Retrieves the underlying integer value of a scoped enumerator. It allows to avoid using static_cast every time
|
||||||
template <typename E>
|
template <typename E>
|
||||||
|
|
|
@ -1497,7 +1497,7 @@ __declspec(noreturn) void CxbxKrnlInit
|
||||||
// Read Xbox video mode from the SMC, store it in HalBootSMCVideoMode
|
// Read Xbox video mode from the SMC, store it in HalBootSMCVideoMode
|
||||||
xbox::HalReadSMBusValue(SMBUS_ADDRESS_SYSTEM_MICRO_CONTROLLER, SMC_COMMAND_AV_PACK, FALSE, (xbox::PULONG)&xbox::HalBootSMCVideoMode);
|
xbox::HalReadSMBusValue(SMBUS_ADDRESS_SYSTEM_MICRO_CONTROLLER, SMC_COMMAND_AV_PACK, FALSE, (xbox::PULONG)&xbox::HalBootSMCVideoMode);
|
||||||
|
|
||||||
g_InputDeviceManager.Initialize(false);
|
g_InputDeviceManager.Initialize(false, g_hEmuWindow);
|
||||||
|
|
||||||
// Now the hardware devices exist, couple the EEPROM buffer to it's device
|
// Now the hardware devices exist, couple the EEPROM buffer to it's device
|
||||||
g_EEPROM->SetEEPROM((uint8_t*)EEPROM);
|
g_EEPROM->SetEEPROM((uint8_t*)EEPROM);
|
||||||
|
|
|
@ -98,7 +98,7 @@ void UpdateInputOpt(HWND hwnd)
|
||||||
|
|
||||||
void ShowInputConfig(HWND hwnd, HWND ChildWnd)
|
void ShowInputConfig(HWND hwnd, HWND ChildWnd)
|
||||||
{
|
{
|
||||||
g_InputDeviceManager.Initialize(true);
|
g_InputDeviceManager.Initialize(true, hwnd);
|
||||||
g_ChildWnd = ChildWnd;
|
g_ChildWnd = ChildWnd;
|
||||||
|
|
||||||
// Show dialog box
|
// Show dialog box
|
||||||
|
|
|
@ -196,7 +196,8 @@ void DukeInputWindow::UpdateProfile(const std::string &name, int command)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_CLEAR: {
|
case BUTTON_CLEAR:
|
||||||
|
case BUTTON_SWAP: {
|
||||||
m_bHasChanges = true;
|
m_bHasChanges = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -100,7 +100,8 @@ void SbcInputWindow::UpdateProfile(const std::string &name, int command)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_CLEAR: {
|
case BUTTON_CLEAR:
|
||||||
|
case BUTTON_SWAP: {
|
||||||
m_bHasChanges = true;
|
m_bHasChanges = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue