diff --git a/Common/System/NativeApp.h b/Common/System/NativeApp.h index 4799fa6f11a8..4bf2e995bf99 100644 --- a/Common/System/NativeApp.h +++ b/Common/System/NativeApp.h @@ -56,6 +56,7 @@ void NativeTouch(const TouchInput &touch); bool NativeKey(const KeyInput &key); void NativeAxis(const AxisInput *axis, size_t count); void NativeAccelerometer(float tiltX, float tiltY, float tiltZ); +void NativeMouseDelta(float dx, float dy); // Called when it's process a frame, including rendering. If the device can keep up, this // will be called sixty times per second. Main thread. diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index b7e0572d96a7..2ec6b16be3e8 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -733,28 +733,6 @@ struct InputStateTracker { } } - void MouseControl() { - // Disabled by default, needs a workaround to map to psp keys. - if (g_Config.bMouseControl) { - float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity; - float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity; - - AxisInput axis[2]; - axis[0].axisId = JOYSTICK_AXIS_MOUSE_REL_X; - axis[0].deviceId = DEVICE_ID_MOUSE; - axis[0].value = std::max(-1.0f, std::min(1.0f, mouseDeltaX * scaleFactor_x)); - axis[1].axisId = JOYSTICK_AXIS_MOUSE_REL_Y; - axis[1].deviceId = DEVICE_ID_MOUSE; - axis[1].value = std::max(-1.0f, std::min(1.0f, mouseDeltaY * scaleFactor_y)); - - if (GetUIState() == UISTATE_INGAME || g_Config.bMapMouse) { - NativeAxis(axis, 2); - } - mouseDeltaX *= g_Config.fMouseSmoothing; - mouseDeltaY *= g_Config.fMouseSmoothing; - } - } - void MouseCaptureControl() { bool captureMouseCondition = g_Config.bMouseControl && ((GetUIState() == UISTATE_INGAME && g_Config.bMouseConfine) || g_Config.bMapMouse); if (mouseCaptured != captureMouseCondition) { @@ -767,8 +745,6 @@ struct InputStateTracker { } bool mouseDown; - float mouseDeltaX; - float mouseDeltaY; int mouseWheelMovedUpFrames; int mouseWheelMovedDownFrames; bool mouseCaptured; @@ -1061,8 +1037,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta input.id = 0; NativeTouch(input); } - inputTracker->mouseDeltaX += event.motion.xrel; - inputTracker->mouseDeltaY += event.motion.yrel; + NativeMouseDelta(event.motion.xrel, event.motion.yrel); break; case SDL_MOUSEBUTTONUP: switch (event.button.button) { @@ -1484,7 +1459,6 @@ int main(int argc, char *argv[]) { UpdateSDLCursor(); - inputTracker.MouseControl(); inputTracker.MouseCaptureControl(); @@ -1514,7 +1488,6 @@ int main(int argc, char *argv[]) { UpdateSDLCursor(); - inputTracker.MouseControl(); inputTracker.MouseCaptureControl(); bool renderThreadPaused = Core_IsWindowHidden() && g_Config.bPauseWhenMinimized && emuThreadState != (int)EmuThreadState::DISABLED; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9d144bb1a923..1037f4039b01 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -729,18 +729,34 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings) return UI::EVENT_CONTINUE; }); controlsSettings->Add(new PopupSliderChoice(&g_Config.iRapidFireInterval, 1, 10, 5, co->T("Rapid fire interval"), screenManager(), "frames")); -#if defined(USING_WIN_UI) || defined(SDL) - controlsSettings->Add(new ItemHeader(co->T("Mouse", "Mouse settings"))); - CheckBox *mouseControl = controlsSettings->Add(new CheckBox(&g_Config.bMouseControl, co->T("Use Mouse Control"))); - mouseControl->OnClick.Add([=](EventParams &e) { - if (g_Config.bMouseControl) - settingInfo_->Show(co->T("MouseControl Tip", "You can now map mouse in control mapping screen by pressing the 'M' icon."), e.v); - return UI::EVENT_CONTINUE; - }); - controlsSettings->Add(new CheckBox(&g_Config.bMouseConfine, co->T("Confine Mouse", "Trap mouse within window/display area")))->SetEnabledPtr(&g_Config.bMouseControl); - controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMouseSensitivity, 0.01f, 1.0f, 0.1f, co->T("Mouse sensitivity"), 0.01f, screenManager(), "x"))->SetEnabledPtr(&g_Config.bMouseControl); - controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMouseSmoothing, 0.0f, 0.95f, 0.9f, co->T("Mouse smoothing"), 0.05f, screenManager(), "x"))->SetEnabledPtr(&g_Config.bMouseControl); +#if defined(USING_WIN_UI) || defined(SDL) || PPSSPP_PLATFORM(ANDROID) + bool enableMouseSettings = true; +#if PPSSPP_PLATFORM(ANDROID) + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) < 12) { + enableMouseSettings = false; + } #endif +#else + bool enableMouseSettings = false; +#endif + if (enableMouseSettings) { + controlsSettings->Add(new ItemHeader(co->T("Mouse", "Mouse settings"))); + CheckBox *mouseControl = controlsSettings->Add(new CheckBox(&g_Config.bMouseControl, co->T("Use Mouse Control"))); + mouseControl->OnClick.Add([=](EventParams &e) { + if (g_Config.bMouseControl) + settingInfo_->Show(co->T("MouseControl Tip", "You can now map mouse in control mapping screen by pressing the 'M' icon."), e.v); + return UI::EVENT_CONTINUE; + }); +#if !PPSSPP_PLATFORM(ANDROID) + controlsSettings->Add(new CheckBox(&g_Config.bMouseConfine, co->T("Confine Mouse", "Trap mouse within window/display area")))->SetEnabledPtr(&g_Config.bMouseControl); +#endif + auto sensitivitySlider = controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMouseSensitivity, 0.01f, 1.0f, 0.1f, co->T("Mouse sensitivity"), 0.01f, screenManager(), "x")); + sensitivitySlider->SetEnabledPtr(&g_Config.bMouseControl); + sensitivitySlider->SetLiveUpdate(true); + auto smoothingSlider = controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMouseSmoothing, 0.0f, 0.95f, 0.9f, co->T("Mouse smoothing"), 0.05f, screenManager(), "x")); + smoothingSlider->SetEnabledPtr(&g_Config.bMouseControl); + smoothingSlider->SetLiveUpdate(true); + } } } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 22059e4ec550..1945da4c0200 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1071,6 +1071,8 @@ static Matrix4x4 ComputeOrthoMatrix(float xres, float yres) { return ortho; } +static void SendMouseDeltaAxis(); + void NativeFrame(GraphicsContext *graphicsContext) { PROFILE_END_FRAME(); @@ -1203,6 +1205,8 @@ void NativeFrame(GraphicsContext *graphicsContext) { if (sleepTime > 0) sleep_ms(sleepTime); } + + SendMouseDeltaAxis(); } bool HandleGlobalMessage(UIMessage message, const std::string &value) { @@ -1358,6 +1362,60 @@ void NativeAxis(const AxisInput *axes, size_t count) { } } +float g_mouseDeltaX = 0; +float g_mouseDeltaY = 0; + +void NativeMouseDelta(float dx, float dy) { + // Remap, shared code. Then send it as a regular axis event. + if (!g_Config.bMouseControl) + return; + + // Accumulate mouse deltas, for some kind of smoothing. + g_mouseDeltaX += dx; + g_mouseDeltaY += dy; +} + +// Called from NativeFrame. +static void SendMouseDeltaAxis() { + static double lastTime = 0.0f; + double now = time_now_d(); + if (lastTime == 0.0) { + lastTime = now; + return; + } + double dt = now - lastTime; + lastTime = now; + + float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity; + float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity; + + float mx = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f); + float my = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f); + + // Decay the mouse deltas. This is where we should use dt. + float decay = expf(-dt * 50.0f * (1.0f - g_Config.fMouseSmoothing)); + g_mouseDeltaX *= decay; + g_mouseDeltaY *= decay; + + AxisInput axis[2]; + axis[0].axisId = JOYSTICK_AXIS_MOUSE_REL_X; + axis[0].deviceId = DEVICE_ID_MOUSE; + axis[0].value = mx; + axis[1].axisId = JOYSTICK_AXIS_MOUSE_REL_Y; + axis[1].deviceId = DEVICE_ID_MOUSE; + axis[1].value = my; + + HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_X] = mx; + HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_Y] = my; + + //NOTICE_LOG(SYSTEM, "delta: %0.2f %0.2f mx/my: %0.2f %0.2f dpi: %f sens: %f ", + // g_mouseDeltaX, g_mouseDeltaY, mx, my, g_display.dpi_scale_x, g_Config.fMouseSensitivity); + + if (GetUIState() == UISTATE_INGAME || g_Config.bMapMouse) { + NativeAxis(axis, 2); + } +} + void NativeAccelerometer(float tiltX, float tiltY, float tiltZ) { if (g_Config.iTiltInputType == TILT_NULL) { // if tilt events are disabled, don't do anything special. diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index 486c20e627ed..81f833681ee5 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -317,11 +317,7 @@ namespace WindowsRawInput { KeyInput key; key.deviceId = DEVICE_ID_MOUSE; - float mx, my; - g_inputManager.AccumulateMouseDeltas(raw->data.mouse.lLastX, raw->data.mouse.lLastY, &mx, &my); - - HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_X] = mx; - HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_Y] = my; + NativeMouseDelta(raw->data.mouse.lLastX, raw->data.mouse.lLastY); static const int rawInputDownID[5] = { RI_MOUSE_LEFT_BUTTON_DOWN, diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index ef0e715740c6..8a693f3c5979 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -65,9 +65,6 @@ void UpdateConsolePosition() { } void WindowsInputManager::Init() { - mouseDeltaX_ = 0; - mouseDeltaY_ = 0; - //add first XInput device to respond input.push_back(std::make_unique()); #ifndef _M_ARM @@ -102,22 +99,7 @@ void WindowsInputManager::PollControllers() { // Disabled by default, needs a workaround to map to psp keys. if (g_Config.bMouseControl) { - float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity; - float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity; - - float mx = std::max(-1.0f, std::min(1.0f, mouseDeltaX_ * scaleFactor_x)); - float my = std::max(-1.0f, std::min(1.0f, mouseDeltaY_ * scaleFactor_y)); - AxisInput axis[2]; - axis[0].axisId = JOYSTICK_AXIS_MOUSE_REL_X; - axis[0].deviceId = DEVICE_ID_MOUSE; - axis[0].value = mx; - axis[1].axisId = JOYSTICK_AXIS_MOUSE_REL_Y; - axis[1].deviceId = DEVICE_ID_MOUSE; - axis[1].value = my; - - if (GetUIState() == UISTATE_INGAME || g_Config.bMapMouse) { - NativeAxis(axis, 2); - } + NativeMouseDelta(mouseDeltaX_, mouseDeltaY_); } mouseDeltaX_ *= g_Config.fMouseSmoothing; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 1970db87dbed..bc4626d175ec 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1278,6 +1278,13 @@ extern "C" jboolean Java_org_ppsspp_ppsspp_NativeApp_mouseWheelEvent( return true; } +extern "C" void Java_org_ppsspp_ppsspp_NativeApp_mouseDelta( + JNIEnv * env, jclass, jfloat x, jfloat y) { + if (!renderer_inited) + return; + NativeMouseDelta(x, y); +} + extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_accelerometer(JNIEnv *, jclass, float x, float y, float z) { if (!renderer_inited) return; diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index dc826497cee4..cc0309af02a5 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -1019,6 +1019,12 @@ public boolean onGenericMotionEvent(MotionEvent event) { } if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + if ((event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { + float dx = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); + float dy = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + NativeApp.mouseDelta(dx, dy); + } + switch (event.getAction()) { case MotionEvent.ACTION_HOVER_MOVE: // process the mouse hover movement... diff --git a/android/src/org/ppsspp/ppsspp/NativeApp.java b/android/src/org/ppsspp/ppsspp/NativeApp.java index 0e3bbcb712b5..0e714be16909 100644 --- a/android/src/org/ppsspp/ppsspp/NativeApp.java +++ b/android/src/org/ppsspp/ppsspp/NativeApp.java @@ -50,6 +50,7 @@ public class NativeApp { public static native void accelerometer(float x, float y, float z); + public static native void mouseDelta(float x, float y); public static native void sendMessageFromJava(String msg, String arg); public static native void sendRequestResult(int seqID, boolean result, String value, int iValue); public static native String queryConfig(String queryName); diff --git a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java index a01bd380cb85..93e3471c18f7 100644 --- a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java +++ b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java @@ -15,6 +15,7 @@ import android.os.Build; import android.os.Handler; import android.util.Log; +import android.view.InputDevice; import android.view.MotionEvent; import android.view.SurfaceView; @@ -23,6 +24,8 @@ import com.bda.controller.KeyEvent; import com.bda.controller.StateEvent; +import java.lang.annotation.Native; + public class NativeSurfaceView extends SurfaceView implements SensorEventListener, ControllerListener { private static String TAG = "NativeSurfaceView"; private SensorManager mSensorManager; @@ -58,6 +61,15 @@ private int getToolType(final MotionEvent ev, int pointer) { return ev.getToolType(pointer); } + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) + private void processMouseDelta(final MotionEvent ev) { + if ((ev.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { + float dx = ev.getAxisValue(MotionEvent.AXIS_RELATIVE_X); + float dy = ev.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + NativeApp.mouseDelta(dx, dy); + } + } + @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(final MotionEvent ev) { @@ -81,9 +93,13 @@ public boolean onTouchEvent(final MotionEvent ev) { if (ev.getActionIndex() == i) code = 4; break; - case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_MOVE: { code = 1; + if (Build.VERSION.SDK_INT >= 12) { + processMouseDelta(ev); + } break; + } default: break; }