Mouse wheel: Centralize the sending of KEY_UP events on a timer.

This commit is contained in:
Henrik Rydgård 2023-12-17 19:40:59 +01:00
parent e5af1f8bd0
commit 818471a2d7
5 changed files with 41 additions and 63 deletions

View File

@ -708,31 +708,6 @@ static void EmuThreadJoin() {
} }
struct InputStateTracker { struct InputStateTracker {
void TranslateMouseWheel() {
// SDL2 doesn't consider the mousewheel a button anymore
// so let's send the KEY_UP if it was moved after some frames
if (mouseWheelMovedUpFrames > 0) {
mouseWheelMovedUpFrames--;
if (mouseWheelMovedUpFrames == 0) {
KeyInput key;
key.deviceId = DEVICE_ID_MOUSE;
key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP;
key.flags = KEY_UP;
NativeKey(key);
}
}
if (mouseWheelMovedDownFrames > 0) {
mouseWheelMovedDownFrames--;
if (mouseWheelMovedDownFrames == 0) {
KeyInput key;
key.deviceId = DEVICE_ID_MOUSE;
key.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN;
key.flags = KEY_UP;
NativeKey(key);
}
}
}
void MouseCaptureControl() { void MouseCaptureControl() {
bool captureMouseCondition = g_Config.bMouseControl && ((GetUIState() == UISTATE_INGAME && g_Config.bMouseConfine) || g_Config.bMapMouse); bool captureMouseCondition = g_Config.bMouseControl && ((GetUIState() == UISTATE_INGAME && g_Config.bMouseConfine) || g_Config.bMapMouse);
if (mouseCaptured != captureMouseCondition) { if (mouseCaptured != captureMouseCondition) {
@ -745,8 +720,6 @@ struct InputStateTracker {
} }
bool mouseDown; bool mouseDown;
int mouseWheelMovedUpFrames;
int mouseWheelMovedDownFrames;
bool mouseCaptured; bool mouseCaptured;
}; };
@ -1019,11 +992,9 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
#endif #endif
if (event.wheel.y > 0) { if (event.wheel.y > 0) {
key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP; key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP;
inputTracker->mouseWheelMovedUpFrames = 5;
NativeKey(key); NativeKey(key);
} else if (event.wheel.y < 0) { } else if (event.wheel.y < 0) {
key.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN; key.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN;
inputTracker->mouseWheelMovedDownFrames = 5;
NativeKey(key); NativeKey(key);
} }
break; break;
@ -1448,8 +1419,6 @@ int main(int argc, char *argv[]) {
if (!mainThreadIsRender) { if (!mainThreadIsRender) {
// We should only be a message pump // We should only be a message pump
while (true) { while (true) {
inputTracker.TranslateMouseWheel();
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
ProcessSDLEvent(window, event, &inputTracker); ProcessSDLEvent(window, event, &inputTracker);
@ -1461,7 +1430,6 @@ int main(int argc, char *argv[]) {
inputTracker.MouseCaptureControl(); inputTracker.MouseCaptureControl();
{ {
std::lock_guard<std::mutex> guard(g_mutexWindow); std::lock_guard<std::mutex> guard(g_mutexWindow);
if (g_windowState.update) { if (g_windowState.update) {
@ -1470,8 +1438,6 @@ int main(int argc, char *argv[]) {
} }
} }
} else while (true) { } else while (true) {
inputTracker.TranslateMouseWheel();
{ {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {

View File

@ -159,6 +159,7 @@
#include <Core/HLE/Plugins.h> #include <Core/HLE/Plugins.h>
bool HandleGlobalMessage(UIMessage message, const std::string &value); bool HandleGlobalMessage(UIMessage message, const std::string &value);
static void ProcessWheelRelease(InputKeyCode keyCode, double now, bool keyPress);
ScreenManager *g_screenManager; ScreenManager *g_screenManager;
std::string config_filename; std::string config_filename;
@ -1040,6 +1041,9 @@ void NativeFrame(GraphicsContext *graphicsContext) {
double startTime = time_now_d(); double startTime = time_now_d();
ProcessWheelRelease(NKCODE_EXT_MOUSEWHEEL_UP, startTime, false);
ProcessWheelRelease(NKCODE_EXT_MOUSEWHEEL_DOWN, startTime, false);
std::vector<PendingMessage> toProcess; std::vector<PendingMessage> toProcess;
{ {
std::lock_guard<std::mutex> lock(pendingMutex); std::lock_guard<std::mutex> lock(pendingMutex);
@ -1262,7 +1266,29 @@ void NativeTouch(const TouchInput &touch) {
g_screenManager->touch(touch); g_screenManager->touch(touch);
} }
// up, down
static double g_wheelReleaseTime[2]{};
static const double RELEASE_TIME = 0.1; // about 3 frames at 30hz.
static void ProcessWheelRelease(InputKeyCode keyCode, double now, bool keyPress) {
int dir = keyCode - NKCODE_EXT_MOUSEWHEEL_UP;
if (g_wheelReleaseTime[dir] != 0.0 && (keyPress || now >= g_wheelReleaseTime[dir])) {
g_wheelReleaseTime[dir] = 0.0;
KeyInput key{};
key.deviceId = DEVICE_ID_MOUSE;
key.keyCode = keyCode;
key.flags = KEY_UP;
NativeKey(key);
}
if (keyPress) {
g_wheelReleaseTime[dir] = now + RELEASE_TIME;
}
}
bool NativeKey(const KeyInput &key) { bool NativeKey(const KeyInput &key) {
double now = time_now_d();
// VR actions // VR actions
if (IsVREnabled() && !UpdateVRKeys(key)) { if (IsVREnabled() && !UpdateVRKeys(key)) {
return false; return false;
@ -1290,12 +1316,19 @@ bool NativeKey(const KeyInput &key) {
} }
#endif #endif
bool retval = false; if (!g_screenManager) {
if (g_screenManager) { return false;
HLEPlugins::SetKey(key.keyCode, (key.flags & KEY_DOWN) ? 1 : 0);
retval = g_screenManager->key(key);
} }
// Handle releases of mousewheel keys.
if ((key.flags & KEY_DOWN) && key.deviceId == DEVICE_ID_MOUSE && (key.keyCode == NKCODE_EXT_MOUSEWHEEL_UP || key.keyCode == NKCODE_EXT_MOUSEWHEEL_DOWN)) {
ProcessWheelRelease(key.keyCode, now, true);
}
HLEPlugins::SetKey(key.keyCode, (key.flags & KEY_DOWN) ? 1 : 0);
// Dispatch the key event.
bool retval = g_screenManager->key(key);
// The Mode key can have weird consequences on some devices, see #17245. // The Mode key can have weird consequences on some devices, see #17245.
if (key.keyCode == NKCODE_BUTTON_MODE) { if (key.keyCode == NKCODE_BUTTON_MODE) {
// Tell the caller that we handled the key. // Tell the caller that we handled the key.

View File

@ -241,8 +241,10 @@ void PPSSPP_UWPMain::OnMouseWheel(float delta) {
KeyInput keyInput{}; KeyInput keyInput{};
keyInput.keyCode = key; keyInput.keyCode = key;
keyInput.deviceId = DEVICE_ID_MOUSE; keyInput.deviceId = DEVICE_ID_MOUSE;
keyInput.flags = KEY_DOWN | KEY_UP; keyInput.flags = KEY_DOWN;
NativeKey(keyInput); NativeKey(keyInput);
// KEY_UP is now sent automatically afterwards for mouse wheel events, see NativeKey.
} }
bool PPSSPP_UWPMain::OnHardwareButton(HardwareButton button) { bool PPSSPP_UWPMain::OnHardwareButton(HardwareButton button) {

View File

@ -112,10 +112,8 @@ static std::wstring windowTitle;
#define TIMER_CURSORUPDATE 1 #define TIMER_CURSORUPDATE 1
#define TIMER_CURSORMOVEUPDATE 2 #define TIMER_CURSORMOVEUPDATE 2
#define TIMER_WHEELRELEASE 3
#define CURSORUPDATE_INTERVAL_MS 1000 #define CURSORUPDATE_INTERVAL_MS 1000
#define CURSORUPDATE_MOVE_TIMESPAN_MS 500 #define CURSORUPDATE_MOVE_TIMESPAN_MS 500
#define WHEELRELEASE_DELAY_MS 16
namespace MainWindow namespace MainWindow
{ {
@ -267,17 +265,6 @@ namespace MainWindow
} }
} }
void ReleaseMouseWheel() {
// For simplicity release both wheel events
KeyInput key;
key.deviceId = DEVICE_ID_MOUSE;
key.flags = KEY_UP;
key.keyCode = NKCODE_EXT_MOUSEWHEEL_DOWN;
NativeKey(key);
key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP;
NativeKey(key);
}
static void HandleSizeChange(int newSizingType) { static void HandleSizeChange(int newSizingType) {
SavePosition(); SavePosition();
Core_NotifyWindowHidden(false); Core_NotifyWindowHidden(false);
@ -927,10 +914,8 @@ namespace MainWindow
} else { } else {
key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP; key.keyCode = NKCODE_EXT_MOUSEWHEEL_UP;
} }
// There's no separate keyup event for mousewheel events, // There's no release event, but we simulate it in NativeKey/NativeFrame.
// so we release it with a slight delay.
key.flags = KEY_DOWN | KEY_HASWHEELDELTA | (wheelDelta << 16); key.flags = KEY_DOWN | KEY_HASWHEELDELTA | (wheelDelta << 16);
SetTimer(hwndMain, TIMER_WHEELRELEASE, WHEELRELEASE_DELAY_MS, 0);
NativeKey(key); NativeKey(key);
} }
break; break;
@ -946,11 +931,6 @@ namespace MainWindow
hideCursor = true; hideCursor = true;
KillTimer(hWnd, TIMER_CURSORMOVEUPDATE); KillTimer(hWnd, TIMER_CURSORMOVEUPDATE);
return 0; return 0;
// Hack: need to release wheel event with a delay for games to register it was "pressed down".
case TIMER_WHEELRELEASE:
ReleaseMouseWheel();
KillTimer(hWnd, TIMER_WHEELRELEASE);
return 0;
} }
break; break;
@ -1045,7 +1025,6 @@ namespace MainWindow
case WM_DESTROY: case WM_DESTROY:
KillTimer(hWnd, TIMER_CURSORUPDATE); KillTimer(hWnd, TIMER_CURSORUPDATE);
KillTimer(hWnd, TIMER_CURSORMOVEUPDATE); KillTimer(hWnd, TIMER_CURSORMOVEUPDATE);
KillTimer(hWnd, TIMER_WHEELRELEASE);
// Main window is gone, this tells the message loop to exit. // Main window is gone, this tells the message loop to exit.
PostQuitMessage(0); PostQuitMessage(0);
return 0; return 0;

View File

@ -1300,8 +1300,6 @@ extern "C" jboolean Java_org_ppsspp_ppsspp_NativeApp_mouseWheelEvent(
// so we release it with a slight delay. // so we release it with a slight delay.
key.flags = KEY_DOWN | KEY_HASWHEELDELTA | (wheelDelta << 16); key.flags = KEY_DOWN | KEY_HASWHEELDELTA | (wheelDelta << 16);
NativeKey(key); NativeKey(key);
key.flags = KEY_UP;
NativeKey(key);
return true; return true;
} }