xemu/ui/xui/input-manager.cc
Matt Borgerson 9c06980275 ui: Redesign user interface
Introduces a new user interface that looks much nicer, is easier to
navigate with controllers, provides more context to users, and is
scalable. Some additional features are included.

* Adds 'popup menu' with actions that can be used easily from controller
* Adds 'main menu', unifying other configuration dialogs
* Adds port-forwarding user interface
* Adds screenshot feature
* Adds volume control feature
* Adds gamepad auto-bind option
* Adds vsync configuration option
* Adds auto UI scaling
* Adds preferred window size selection
* Adds AV pack selection
* Exposes some existing config items in GUI
2022-05-07 16:09:34 -07:00

117 lines
6.1 KiB
C++

#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
}