#include "common.hh" #include "input-manager.hh" #include "../xemu-input.h" InputManager g_input_mgr; InputManager::InputManager() { m_last_mouse_pos = ImVec2(0, 0); m_navigating_with_controller = false; } void InputManager::Update() { ImGuiIO& io = ImGui::GetIO(); // Combine all controller states to allow any controller to navigate m_buttons = 0; int16_t axis[CONTROLLER_AXIS__COUNT] = {0}; ControllerState *iter; QTAILQ_FOREACH(iter, &available_controllers, entry) { if (iter->type != INPUT_DEVICE_SDL_GAMECONTROLLER) continue; m_buttons |= iter->buttons; // We simply take any axis that is >10 % activation for (int i = 0; i < CONTROLLER_AXIS__COUNT; i++) { if ((iter->axis[i] > 3276) || (iter->axis[i] < -3276)) { axis[i] = iter->axis[i]; } } } // If the mouse is moved, wake the ui ImVec2 current_mouse_pos = ImGui::GetMousePos(); m_mouse_moved = false; if ((current_mouse_pos.x != m_last_mouse_pos.x) || (current_mouse_pos.y != m_last_mouse_pos.y) || ImGui::IsMouseDown(0) || ImGui::IsMouseDown(1) || ImGui::IsMouseDown(2)) { m_mouse_moved = true; m_last_mouse_pos = current_mouse_pos; m_navigating_with_controller = false; } // If mouse capturing is enabled (we are in a dialog), ensure the UI is alive bool controller_focus_capture = false; if (io.NavActive) { controller_focus_capture = true; m_navigating_with_controller |= !!m_buttons; } // Prevent controller events from going to the guest if they are being used // to navigate the HUD xemu_input_set_test_mode(controller_focus_capture); // FIXME: Rename 'test mode' // Update gamepad inputs #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, !!(m_buttons & BUTTON_NO)); } #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(axis[AXIS_NO] - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); } const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. MAP_BUTTON(ImGuiKey_GamepadStart, CONTROLLER_BUTTON_START); MAP_BUTTON(ImGuiKey_GamepadBack, CONTROLLER_BUTTON_BACK); MAP_BUTTON(ImGuiKey_GamepadFaceDown, CONTROLLER_BUTTON_A); // Xbox A, PS Cross MAP_BUTTON(ImGuiKey_GamepadFaceRight, CONTROLLER_BUTTON_B); // Xbox B, PS Circle MAP_BUTTON(ImGuiKey_GamepadFaceLeft, CONTROLLER_BUTTON_X); // Xbox X, PS Square MAP_BUTTON(ImGuiKey_GamepadFaceUp, CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle MAP_BUTTON(ImGuiKey_GamepadDpadLeft, CONTROLLER_BUTTON_DPAD_LEFT); MAP_BUTTON(ImGuiKey_GamepadDpadRight, CONTROLLER_BUTTON_DPAD_RIGHT); MAP_BUTTON(ImGuiKey_GamepadDpadUp, CONTROLLER_BUTTON_DPAD_UP); MAP_BUTTON(ImGuiKey_GamepadDpadDown, CONTROLLER_BUTTON_DPAD_DOWN); MAP_BUTTON(ImGuiKey_GamepadL1, CONTROLLER_BUTTON_WHITE); MAP_BUTTON(ImGuiKey_GamepadR1, CONTROLLER_BUTTON_BLACK); //MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767); //MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767); //MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK); //MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK); MAP_ANALOG(ImGuiKey_GamepadLStickLeft, CONTROLLER_AXIS_LSTICK_X, -thumb_dead_zone, -32768); MAP_ANALOG(ImGuiKey_GamepadLStickRight, CONTROLLER_AXIS_LSTICK_X, +thumb_dead_zone, +32767); MAP_ANALOG(ImGuiKey_GamepadLStickUp, CONTROLLER_AXIS_LSTICK_Y, +thumb_dead_zone, +32768); MAP_ANALOG(ImGuiKey_GamepadLStickDown, CONTROLLER_AXIS_LSTICK_Y, -thumb_dead_zone, -32767); MAP_ANALOG(ImGuiKey_GamepadRStickLeft, CONTROLLER_AXIS_RSTICK_X, -thumb_dead_zone, -32768); MAP_ANALOG(ImGuiKey_GamepadRStickRight, CONTROLLER_AXIS_RSTICK_X, +thumb_dead_zone, +32767); MAP_ANALOG(ImGuiKey_GamepadRStickUp, CONTROLLER_AXIS_RSTICK_Y, +thumb_dead_zone, +32768); MAP_ANALOG(ImGuiKey_GamepadRStickDown, CONTROLLER_AXIS_RSTICK_Y, -thumb_dead_zone, -32767); #undef MAP_BUTTON #undef MAP_ANALOG #undef IM_SATURATE io.BackendUsingLegacyNavInputArray = true; // Map to nav inputs #define NAV_MAP_KEY(_KEY, _NAV_INPUT, _ACTIVATE_NAV) \ do { \ io.NavInputs[_NAV_INPUT] = io.KeysData[_KEY - ImGuiKey_KeysData_OFFSET].AnalogValue; \ if (_ACTIVATE_NAV && io.NavInputs[_NAV_INPUT] > 0.0f) { \ ImGui::GetCurrentContext()->NavInputSource = ImGuiInputSource_Gamepad; \ } \ } while (0) NAV_MAP_KEY(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate, true); NAV_MAP_KEY(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel, true); //NAV_MAP_KEY(ImGuiKey_Menu, ImGuiNavInput_Menu, true); NAV_MAP_KEY(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input, true); NAV_MAP_KEY(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft, true); NAV_MAP_KEY(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight, true); NAV_MAP_KEY(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp, true); NAV_MAP_KEY(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown, true); NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, false); NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, false); NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_TweakSlow, false); NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_TweakFast, false); NAV_MAP_KEY(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft, false); NAV_MAP_KEY(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight, false); NAV_MAP_KEY(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp, false); NAV_MAP_KEY(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown, false); #undef NAV_MAP_KEY }