diff --git a/src/graphics/presentation/window/hostInput.cpp b/src/graphics/presentation/window/hostInput.cpp index b71ba111b..8e6378094 100644 --- a/src/graphics/presentation/window/hostInput.cpp +++ b/src/graphics/presentation/window/hostInput.cpp @@ -29,6 +29,7 @@ struct ControlInfo { uint32_t button = 0; Controller::Axis axis = Controller::Axis::AxisMax; bool positive = false; + float touch_x = 0.0f; }; static constexpr std::array CONTROL_INFO = { @@ -47,7 +48,10 @@ static constexpr std::array CONTROL_INFO = { ControlInfo {"Circle", Controller::PAD_BUTTON_CIRCLE}, ControlInfo {"Cross", Controller::PAD_BUTTON_CROSS}, ControlInfo {"Square", Controller::PAD_BUTTON_SQUARE}, - ControlInfo {"TouchPad", Controller::PAD_BUTTON_TOUCH_PAD}, + ControlInfo {"TouchPad", Controller::PAD_BUTTON_TOUCH_PAD, Controller::Axis::AxisMax, false, + 0.25f}, + ControlInfo {"TouchPadRight", Controller::PAD_BUTTON_TOUCH_PAD, Controller::Axis::AxisMax, + false, 0.75f}, ControlInfo {"LeftStickLeft", 0, Controller::Axis::LeftX, false}, ControlInfo {"LeftStickRight", 0, Controller::Axis::LeftX, true}, ControlInfo {"LeftStickUp", 0, Controller::Axis::LeftY, false}, @@ -83,11 +87,6 @@ std::size_t ControlFromName(std::string_view name) { return static_cast(std::distance(CONTROL_INFO.begin(), info)); } -const ControlInfo& Info(std::size_t control) { - EXIT_IF(control >= CONTROL_INFO.size()); - return CONTROL_INFO[control]; -} - SDL_Keycode NormalizeKey(SDL_Keycode key) { switch (key) { case SDLK_RSHIFT: return SDLK_LSHIFT; @@ -205,6 +204,10 @@ void SetButton(uint32_t button, bool down) { } } +void SetTouchPad(float x, bool down) { + Controller::ControllerTouchPad(Controller::HOST_INPUT_CONTROLLER_ID, 0, down, x, 0.5f); +} + uint32_t DefaultKeyboardButton(int key_code) { switch (NormalizeKey(static_cast(key_code))) { case SDLK_UP: return Controller::PAD_BUTTON_UP; @@ -221,8 +224,6 @@ uint32_t DefaultKeyboardButton(int key_code) { case SDLK_LCTRL: return Controller::PAD_BUTTON_R3; case SDLK_RETURN: case SDLK_RETURN2: return Controller::PAD_BUTTON_OPTIONS; - case SDLK_BACKSPACE: - case SDLK_TAB: return Controller::PAD_BUTTON_TOUCH_PAD; default: return 0; } } @@ -235,7 +236,12 @@ struct StickKeys { }; void SetStickAxis(Controller::Axis axis, bool negative, bool positive) { - const int value = negative == positive ? 128 : negative ? 0 : 255; + int value = 128; + if (negative && !positive) { + value = 0; + } else if (positive && !negative) { + value = 255; + } Controller::ControllerAxis(Controller::HOST_INPUT_CONTROLLER_ID, axis, value); } @@ -244,7 +250,11 @@ void SetControl(std::size_t control, bool down) { return; } - const auto& info = Info(control); + const auto& info = CONTROL_INFO[control]; + if (info.button == Controller::PAD_BUTTON_TOUCH_PAD) { + SetTouchPad(info.touch_x, down); + return; + } if (info.button != 0) { SetButton(info.button, down); return; @@ -271,6 +281,8 @@ void DefaultKeyboardInput(int key_code, bool down) { static StickKeys right; switch (NormalizeKey(static_cast(key_code))) { + case SDLK_BACKSPACE: SetTouchPad(0.25f, down); return; + case SDLK_TAB: SetTouchPad(0.75f, down); return; case SDLK_a: left.left = down; SetStickAxis(Controller::Axis::LeftX, left.left, left.right); diff --git a/src/graphics/presentation/window/window.cpp b/src/graphics/presentation/window/window.cpp index a61afca8e..10877adc0 100644 --- a/src/graphics/presentation/window/window.cpp +++ b/src/graphics/presentation/window/window.cpp @@ -76,7 +76,6 @@ static uint32_t ControllerButtonToPadButton(int button) { case SDL_CONTROLLER_BUTTON_B: return Controller::PAD_BUTTON_CIRCLE; case SDL_CONTROLLER_BUTTON_X: return Controller::PAD_BUTTON_SQUARE; case SDL_CONTROLLER_BUTTON_Y: return Controller::PAD_BUTTON_TRIANGLE; - case SDL_CONTROLLER_BUTTON_BACK: return Controller::PAD_BUTTON_TOUCH_PAD; case SDL_CONTROLLER_BUTTON_START: return Controller::PAD_BUTTON_OPTIONS; case SDL_CONTROLLER_BUTTON_LEFTSTICK: return Controller::PAD_BUTTON_L3; case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return Controller::PAD_BUTTON_R3; @@ -86,6 +85,7 @@ static uint32_t ControllerButtonToPadButton(int button) { case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return Controller::PAD_BUTTON_DOWN; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return Controller::PAD_BUTTON_LEFT; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return Controller::PAD_BUTTON_RIGHT; + case SDL_CONTROLLER_BUTTON_TOUCHPAD: return Controller::PAD_BUTTON_TOUCH_PAD; default: return 0; } } @@ -705,6 +705,16 @@ void WindowContext::ProcessEvent(double time_s) { break; } + case SDL_CONTROLLERTOUCHPADDOWN: + case SDL_CONTROLLERTOUCHPADMOTION: + case SDL_CONTROLLERTOUCHPADUP: + if (event->ctouchpad.touchpad == 0) { + Controller::ControllerTouchPad(event->ctouchpad.which, event->ctouchpad.finger, + event->ctouchpad.type != SDL_CONTROLLERTOUCHPADUP, + event->ctouchpad.x, event->ctouchpad.y); + } + break; + case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEREMOVED: case SDL_CONTROLLERDEVICEREMAPPED: { diff --git a/src/launcher/src/inputMappingDialog.cpp b/src/launcher/src/inputMappingDialog.cpp index e2e29e35f..20952f01b 100644 --- a/src/launcher/src/inputMappingDialog.cpp +++ b/src/launcher/src/inputMappingDialog.cpp @@ -51,7 +51,8 @@ constexpr PadControl PAD_CONTROLS[] = { {"L3", "L3", "Left Shift"}, {"R3", "R3", "Left Ctrl"}, {"Options", "Options", "Return"}, - {"TouchPad", "Touch pad", "Backspace"}, + {"TouchPad", "Touch pad left (SELECT)", "Backspace"}, + {"TouchPadRight", "Touch pad right (START)", "Tab"}, }; QString KeypadName(int key) { diff --git a/src/libs/controller.cpp b/src/libs/controller.cpp index d8712b9c8..14ff5f6ad 100644 --- a/src/libs/controller.cpp +++ b/src/libs/controller.cpp @@ -45,15 +45,22 @@ struct PadVibrationParam { }; struct ControllerState { + struct Touch { + uint8_t id = 0; + bool down = false; + uint16_t x = 0; + uint16_t y = 0; + }; + uint64_t time = 0; uint32_t buttons = 0; int axes[static_cast(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0}; + Touch touch[2]; }; class GameController { public: - GameController() = default; - virtual ~GameController() = default; + GameController() = default; KYTY_CLASS_NO_COPY(GameController); @@ -62,6 +69,7 @@ public: void Button(int id, uint32_t button, bool down); void Axis(int id, Axis axis, int value); void RightStick(int id, int x, int y); + void TouchPad(int id, int finger, bool down, float x, float y); void ResetInputState(); void GetConnectionInfo(bool* flag, int* count); void SetVibration(uint8_t large_motor, uint8_t small_motor); @@ -71,51 +79,49 @@ public: private: static constexpr uint32_t STATES_MAX = 64; - struct StatePrivate { - bool obtained = false; - }; - - void CheckActive(); - [[nodiscard]] ControllerState GetLastState() const; - void AddState(const ControllerState& state); + void CheckActive(); + void AddState(); Common::Mutex m_mutex; std::vector m_connected_ids; int m_active_id = -1; bool m_connected = false; int m_connected_count = 0; + ControllerState m_state; ControllerState m_states[STATES_MAX]; - StatePrivate m_private[STATES_MAX]; - ControllerState m_last_state; - uint32_t m_states_num = 0; - uint32_t m_first_state = 0; + bool m_obtained[STATES_MAX] {}; + uint32_t m_states_num = 0; + uint32_t m_first_state = 0; + uint8_t m_next_touch_id = 1; }; static GameController* g_controller = nullptr; -static uint8_t pad_connected_count_to_u8(int connected_count) { - return static_cast(connected_count > 255 ? 255 : connected_count); -} - static void pad_fill_data(PadData* data, const ControllerState& state, bool connected, int connected_count) { EXIT_IF(data == nullptr); std::memset(data, 0, sizeof(*data)); - data->buttons = state.buttons; - data->left_stick_x = state.axes[static_cast(Axis::LeftX)]; - data->left_stick_y = state.axes[static_cast(Axis::LeftY)]; - data->right_stick_x = state.axes[static_cast(Axis::RightX)]; - data->right_stick_y = state.axes[static_cast(Axis::RightY)]; - data->analog_buttons_l2 = state.axes[static_cast(Axis::TriggerLeft)]; - data->analog_buttons_r2 = state.axes[static_cast(Axis::TriggerRight)]; - data->orientation_w = 1.0f; - data->touch_data_touch0_id = 1; - data->touch_data_touch1_id = 2; + data->buttons = state.buttons; + data->left_stick_x = state.axes[static_cast(Axis::LeftX)]; + data->left_stick_y = state.axes[static_cast(Axis::LeftY)]; + data->right_stick_x = state.axes[static_cast(Axis::RightX)]; + data->right_stick_y = state.axes[static_cast(Axis::RightY)]; + data->analog_buttons_l2 = state.axes[static_cast(Axis::TriggerLeft)]; + data->analog_buttons_r2 = state.axes[static_cast(Axis::TriggerRight)]; + data->orientation_w = 1.0f; + for (const auto& touch: state.touch) { + if (touch.down) { + auto& output = data->touch_data.touch[data->touch_data.touch_num++]; + output.x = touch.x; + output.y = touch.y; + output.id = touch.id; + } + } data->connected = connected; data->timestamp = state.time; - data->connected_count = pad_connected_count_to_u8(connected_count); + data->connected_count = static_cast(std::min(connected_count, 255)); data->device_unique_data_len = 0; } @@ -155,7 +161,6 @@ void GameController::Disconnect(int id) { } void GameController::CheckActive() { - bool reset = false; int new_active_id = -1; bool new_connected = false; @@ -170,46 +175,29 @@ void GameController::CheckActive() { new_connected = true; } - const bool was_connected = m_connected; - - if (m_connected != new_connected || m_active_id != new_active_id) { - m_active_id = new_active_id; - m_connected = new_connected; - if (!was_connected && new_connected) { - m_connected_count++; - } - reset = true; + if (m_connected == new_connected && m_active_id == new_active_id) { + return; } - - if (reset) { - m_states_num = 0; - m_last_state = ControllerState(); + if (!m_connected && new_connected) { + m_connected_count++; } + m_active_id = new_active_id; + m_connected = new_connected; + m_state = {}; + m_states_num = 0; + m_first_state = 0; + m_next_touch_id = 1; } -ControllerState GameController::GetLastState() const { - if (m_states_num == 0) { - return m_last_state; - } - - auto last = (m_first_state + m_states_num - 1) % STATES_MAX; - - return m_states[last]; -} - -void GameController::AddState(const ControllerState& state) { +void GameController::AddState() { if (m_states_num >= STATES_MAX) { m_states_num = STATES_MAX - 1; m_first_state = (m_first_state + 1) % STATES_MAX; } - auto index = (m_first_state + m_states_num) % STATES_MAX; - - m_states[index] = state; - m_last_state = state; - - m_private[index].obtained = false; - + const auto index = (m_first_state + m_states_num) % STATES_MAX; + m_states[index] = m_state; + m_obtained[index] = false; m_states_num++; } @@ -218,17 +206,11 @@ void GameController::Button(int id, uint32_t button, bool down) { // The keyboard shares the player-1 pad with the active gamepad. if (m_active_id == id || id == HOST_INPUT_CONTROLLER_ID) { - auto state = GetLastState(); + m_state.time = LibKernel::KernelGetProcessTime(); - state.time = LibKernel::KernelGetProcessTime(); + m_state.buttons = down ? m_state.buttons | button : m_state.buttons & ~button; - if (down) { - state.buttons |= button; - } else { - state.buttons &= ~button; - } - - AddState(state); + AddState(); } } @@ -236,33 +218,25 @@ void GameController::Axis(int id, Controller::Axis axis, int value) { Common::LockGuard lock(m_mutex); if (m_active_id == id || id == HOST_INPUT_CONTROLLER_ID) { - auto state = GetLastState(); - - state.time = LibKernel::KernelGetProcessTime(); + m_state.time = LibKernel::KernelGetProcessTime(); int axis_id = static_cast(axis); EXIT_IF(axis_id < 0 || axis_id >= static_cast(Controller::Axis::AxisMax)); - state.axes[axis_id] = value; + m_state.axes[axis_id] = value; + uint32_t trigger = 0; if (axis == Controller::Axis::TriggerLeft) { - if (value > 0) { - state.buttons |= PAD_BUTTON_L2; - } else { - state.buttons &= ~PAD_BUTTON_L2; - } + trigger = PAD_BUTTON_L2; + } else if (axis == Controller::Axis::TriggerRight) { + trigger = PAD_BUTTON_R2; + } + if (trigger != 0) { + m_state.buttons = value > 0 ? m_state.buttons | trigger : m_state.buttons & ~trigger; } - if (axis == Controller::Axis::TriggerRight) { - if (value > 0) { - state.buttons |= PAD_BUTTON_R2; - } else { - state.buttons &= ~PAD_BUTTON_R2; - } - } - - AddState(state); + AddState(); } } @@ -270,21 +244,45 @@ void GameController::RightStick(int id, int x, int y) { Common::LockGuard lock(m_mutex); if (m_active_id == id || id == HOST_INPUT_CONTROLLER_ID) { - auto state = GetLastState(); - state.time = LibKernel::KernelGetProcessTime(); - state.axes[static_cast(Axis::RightX)] = x; - state.axes[static_cast(Axis::RightY)] = y; - AddState(state); + m_state.time = LibKernel::KernelGetProcessTime(); + m_state.axes[static_cast(Axis::RightX)] = x; + m_state.axes[static_cast(Axis::RightY)] = y; + AddState(); + } +} + +void GameController::TouchPad(int id, int finger, bool down, float x, float y) { + if (finger < 0 || finger >= 2) { + return; + } + + Common::LockGuard lock(m_mutex); + if (m_active_id == id || id == HOST_INPUT_CONTROLLER_ID) { + auto& touch = m_state.touch[finger]; + m_state.time = LibKernel::KernelGetProcessTime(); + if (down && !touch.down) { + touch.id = m_next_touch_id; + m_next_touch_id = m_next_touch_id == 127 ? 1 : m_next_touch_id + 1; + } + touch.down = down; + touch.x = static_cast(std::clamp(x, 0.0f, 1.0f) * 1920.0f); + touch.y = static_cast(std::clamp(y, 0.0f, 1.0f) * 943.0f); + if (id == HOST_INPUT_CONTROLLER_ID) { + m_state.buttons = down ? m_state.buttons | PAD_BUTTON_TOUCH_PAD + : m_state.buttons & ~PAD_BUTTON_TOUCH_PAD; + } + AddState(); } } void GameController::ResetInputState() { Common::LockGuard lock(m_mutex); - ControllerState state {}; - state.time = LibKernel::KernelGetProcessTime(); - m_states_num = 0; - m_first_state = 0; - AddState(state); + m_state = {}; + m_state.time = LibKernel::KernelGetProcessTime(); + m_states_num = 0; + m_first_state = 0; + m_next_touch_id = 1; + AddState(); } void GameController::SetVibration(uint8_t large_motor, uint8_t small_motor) { @@ -325,7 +323,7 @@ void GameController::ReadState(ControllerState* state, bool* flag, int* count) { *flag = m_connected; *count = m_connected_count; - *state = GetLastState(); + *state = m_state; } int GameController::ReadStates(ControllerState* states, int states_num, bool* flag, int* count) { @@ -348,8 +346,8 @@ int GameController::ReadStates(ControllerState* states, int states_num, bool* fl break; } auto index = (m_first_state + i) % STATES_MAX; - if (!m_private[index].obtained) { - m_private[index].obtained = true; + if (!m_obtained[index]) { + m_obtained[index] = true; states[ret_num++] = m_states[index]; } @@ -390,6 +388,12 @@ void ControllerRightStick(int id, int x, int y) { g_controller->RightStick(id, x, y); } +void ControllerTouchPad(int id, int finger, bool down, float x, float y) { + EXIT_IF(g_controller == nullptr); + + g_controller->TouchPad(id, finger, down, x, y); +} + void ControllerResetInputState() { EXIT_IF(g_controller == nullptr); g_controller->ResetInputState(); @@ -508,7 +512,7 @@ int KYTY_SYSV_ABI PadGetControllerInformation(int handle, PadControllerInformati info->stick_dead_zone_left = controller_get_axis(-32768, 32767, 8000) - 128; info->stick_dead_zone_right = controller_get_axis(-32768, 32767, 8000) - 128; info->connection_type = 0; - info->connected_count = pad_connected_count_to_u8(connected_count); + info->connected_count = static_cast(std::min(connected_count, 255)); info->connected = connected; info->device_class = 0; diff --git a/src/libs/controller.h b/src/libs/controller.h index bdc938433..9c01a880d 100644 --- a/src/libs/controller.h +++ b/src/libs/controller.h @@ -51,7 +51,13 @@ struct PadLightBarParam; inline int controller_get_axis(int min, int max, int value) { int v = (255 * (value - min)) / (max - min); - return (v < 0 ? 0 : (v > 255 ? 255 : v)); + if (v < 0) { + return 0; + } + if (v > 255) { + return 255; + } + return v; } void ControllerConnect(int id); @@ -59,6 +65,7 @@ void ControllerDisconnect(int id); void ControllerButton(int id, uint32_t button, bool down); void ControllerAxis(int id, Axis axis, int value); void ControllerRightStick(int id, int x, int y); +void ControllerTouchPad(int id, int finger, bool down, float x, float y); void ControllerResetInputState(); int KYTY_SYSV_ABI PadInit(); diff --git a/src/libs/padData.h b/src/libs/padData.h index 2924dfac1..ad36899d3 100644 --- a/src/libs/padData.h +++ b/src/libs/padData.h @@ -5,46 +5,50 @@ namespace Libs::Controller { +struct PadTouch { + uint16_t x; + uint16_t y; + uint8_t id; + uint8_t reserve[3]; +}; + +struct PadTouchData { + uint8_t touch_num; + uint8_t reserve[3]; + uint32_t reserve1; + PadTouch touch[2]; +}; + struct PadData { - uint32_t buttons; - uint8_t left_stick_x; - uint8_t left_stick_y; - uint8_t right_stick_x; - uint8_t right_stick_y; - uint8_t analog_buttons_l2; - uint8_t analog_buttons_r2; - uint8_t padding[2]; - float orientation_x; - float orientation_y; - float orientation_z; - float orientation_w; - float acceleration_x; - float acceleration_y; - float acceleration_z; - float angular_velocity_x; - float angular_velocity_y; - float angular_velocity_z; - uint8_t touch_data_touch_num; - uint8_t touch_data_reserve[3]; - uint32_t touch_data_reserve1; - uint16_t touch_data_touch0_x; - uint16_t touch_data_touch0_y; - uint8_t touch_data_touch0_id; - uint8_t touch_data_touch0_reserve[3]; - uint16_t touch_data_touch1_x; - uint16_t touch_data_touch1_y; - uint8_t touch_data_touch1_id; - uint8_t touch_data_touch1_reserve[3]; - bool connected; - uint64_t timestamp; - uint32_t extension_unit_data_extension_unit_id; - uint8_t extension_unit_data_reserve[1]; - uint8_t extension_unit_data_data_length; - uint8_t extension_unit_data_data[10]; - uint8_t connected_count; - uint8_t reserve[2]; - uint8_t device_unique_data_len; - uint8_t device_unique_data[12]; + uint32_t buttons; + uint8_t left_stick_x; + uint8_t left_stick_y; + uint8_t right_stick_x; + uint8_t right_stick_y; + uint8_t analog_buttons_l2; + uint8_t analog_buttons_r2; + uint8_t padding[2]; + float orientation_x; + float orientation_y; + float orientation_z; + float orientation_w; + float acceleration_x; + float acceleration_y; + float acceleration_z; + float angular_velocity_x; + float angular_velocity_y; + float angular_velocity_z; + PadTouchData touch_data; + bool connected; + uint64_t timestamp; + uint32_t extension_unit_data_extension_unit_id; + uint8_t extension_unit_data_reserve[1]; + uint8_t extension_unit_data_data_length; + uint8_t extension_unit_data_data[10]; + uint8_t connected_count; + uint8_t reserve[2]; + uint8_t device_unique_data_len; + uint8_t device_unique_data[12]; }; static_assert(sizeof(PadData) == 120);