diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/frontend/emu_window.cpp | 43 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.h | 13 | ||||
| -rw-r--r-- | src/core/frontend/input.h | 7 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.cpp | 127 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.h | 32 |
5 files changed, 167 insertions, 55 deletions
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 8c1193894..ee7a58b1c 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -21,21 +21,18 @@ public: | |||
| 21 | 21 | ||
| 22 | std::mutex mutex; | 22 | std::mutex mutex; |
| 23 | 23 | ||
| 24 | bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false | 24 | Input::TouchStatus status; |
| 25 | |||
| 26 | float touch_x = 0.0f; ///< Touchpad X-position | ||
| 27 | float touch_y = 0.0f; ///< Touchpad Y-position | ||
| 28 | 25 | ||
| 29 | private: | 26 | private: |
| 30 | class Device : public Input::TouchDevice { | 27 | class Device : public Input::TouchDevice { |
| 31 | public: | 28 | public: |
| 32 | explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} | 29 | explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} |
| 33 | std::tuple<float, float, bool> GetStatus() const override { | 30 | Input::TouchStatus GetStatus() const override { |
| 34 | if (auto state = touch_state.lock()) { | 31 | if (auto state = touch_state.lock()) { |
| 35 | std::lock_guard guard{state->mutex}; | 32 | std::lock_guard guard{state->mutex}; |
| 36 | return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); | 33 | return state->status; |
| 37 | } | 34 | } |
| 38 | return std::make_tuple(0.0f, 0.0f, false); | 35 | return {}; |
| 39 | } | 36 | } |
| 40 | 37 | ||
| 41 | private: | 38 | private: |
| @@ -79,36 +76,44 @@ std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsi | |||
| 79 | return std::make_tuple(new_x, new_y); | 76 | return std::make_tuple(new_x, new_y); |
| 80 | } | 77 | } |
| 81 | 78 | ||
| 82 | void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | 79 | void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { |
| 83 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 80 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { |
| 84 | return; | 81 | return; |
| 82 | } | ||
| 83 | if (id >= touch_state->status.size()) { | ||
| 84 | return; | ||
| 85 | } | ||
| 85 | 86 | ||
| 86 | std::lock_guard guard{touch_state->mutex}; | 87 | std::lock_guard guard{touch_state->mutex}; |
| 87 | touch_state->touch_x = | 88 | const float x = |
| 88 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / | 89 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / |
| 89 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); | 90 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); |
| 90 | touch_state->touch_y = | 91 | const float y = |
| 91 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / | 92 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / |
| 92 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); | 93 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); |
| 93 | 94 | ||
| 94 | touch_state->touch_pressed = true; | 95 | touch_state->status[id] = std::make_tuple(x, y, true); |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | void EmuWindow::TouchReleased() { | 98 | void EmuWindow::TouchReleased(std::size_t id) { |
| 99 | if (id >= touch_state->status.size()) { | ||
| 100 | return; | ||
| 101 | } | ||
| 98 | std::lock_guard guard{touch_state->mutex}; | 102 | std::lock_guard guard{touch_state->mutex}; |
| 99 | touch_state->touch_pressed = false; | 103 | touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); |
| 100 | touch_state->touch_x = 0; | ||
| 101 | touch_state->touch_y = 0; | ||
| 102 | } | 104 | } |
| 103 | 105 | ||
| 104 | void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { | 106 | void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { |
| 105 | if (!touch_state->touch_pressed) | 107 | if (id >= touch_state->status.size()) { |
| 108 | return; | ||
| 109 | } | ||
| 110 | if (!std::get<2>(touch_state->status[id])) | ||
| 106 | return; | 111 | return; |
| 107 | 112 | ||
| 108 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 113 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) |
| 109 | std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); | 114 | std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); |
| 110 | 115 | ||
| 111 | TouchPressed(framebuffer_x, framebuffer_y); | 116 | TouchPressed(framebuffer_x, framebuffer_y, id); |
| 112 | } | 117 | } |
| 113 | 118 | ||
| 114 | void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { | 119 | void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 276d2b906..2436c6580 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -117,18 +117,23 @@ public: | |||
| 117 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) | 117 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) |
| 118 | * @param framebuffer_x Framebuffer x-coordinate that was pressed | 118 | * @param framebuffer_x Framebuffer x-coordinate that was pressed |
| 119 | * @param framebuffer_y Framebuffer y-coordinate that was pressed | 119 | * @param framebuffer_y Framebuffer y-coordinate that was pressed |
| 120 | * @param id Touch event ID | ||
| 120 | */ | 121 | */ |
| 121 | void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y); | 122 | void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); |
| 122 | 123 | ||
| 123 | /// Signal that a touch released event has occurred (e.g. mouse click released) | 124 | /** |
| 124 | void TouchReleased(); | 125 | * Signal that a touch released event has occurred (e.g. mouse click released) |
| 126 | * @param id Touch event ID | ||
| 127 | */ | ||
| 128 | void TouchReleased(std::size_t id); | ||
| 125 | 129 | ||
| 126 | /** | 130 | /** |
| 127 | * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) | 131 | * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) |
| 128 | * @param framebuffer_x Framebuffer x-coordinate | 132 | * @param framebuffer_x Framebuffer x-coordinate |
| 129 | * @param framebuffer_y Framebuffer y-coordinate | 133 | * @param framebuffer_y Framebuffer y-coordinate |
| 134 | * @param id Touch event ID | ||
| 130 | */ | 135 | */ |
| 131 | void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); | 136 | void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); |
| 132 | 137 | ||
| 133 | /** | 138 | /** |
| 134 | * Returns currently active configuration. | 139 | * Returns currently active configuration. |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index de51a754e..f014dfea3 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -163,10 +163,11 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common | |||
| 163 | using MotionDevice = InputDevice<MotionStatus>; | 163 | using MotionDevice = InputDevice<MotionStatus>; |
| 164 | 164 | ||
| 165 | /** | 165 | /** |
| 166 | * A touch status is an object that returns a tuple of two floats and a bool. The floats are | 166 | * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. |
| 167 | * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. | 167 | * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is |
| 168 | * pressed. | ||
| 168 | */ | 169 | */ |
| 169 | using TouchStatus = std::tuple<float, float, bool>; | 170 | using TouchStatus = std::array<std::tuple<float, float, bool>, 16>; |
| 170 | 171 | ||
| 171 | /** | 172 | /** |
| 172 | * A touch device is an input device that returns a touch status object | 173 | * A touch device is an input device that returns a touch status object |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 0df395e85..5219f2dad 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 5 | #include <cstring> | 6 | #include <cstring> |
| 6 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| @@ -16,7 +17,13 @@ constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | |||
| 16 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} | 17 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} |
| 17 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 18 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 18 | 19 | ||
| 19 | void Controller_Touchscreen::OnInit() {} | 20 | void Controller_Touchscreen::OnInit() { |
| 21 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||
| 22 | mouse_finger_id[id] = MAX_FINGERS; | ||
| 23 | keyboard_finger_id[id] = MAX_FINGERS; | ||
| 24 | udp_finger_id[id] = MAX_FINGERS; | ||
| 25 | } | ||
| 26 | } | ||
| 20 | 27 | ||
| 21 | void Controller_Touchscreen::OnRelease() {} | 28 | void Controller_Touchscreen::OnRelease() {} |
| 22 | 29 | ||
| @@ -40,38 +47,106 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 40 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 47 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 41 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 48 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 42 | 49 | ||
| 43 | bool pressed = false; | 50 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); |
| 44 | float x, y; | 51 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); |
| 45 | std::tie(x, y, pressed) = touch_device->GetStatus(); | 52 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { |
| 46 | auto& touch_entry = cur_entry.states[0]; | 53 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); |
| 47 | touch_entry.attribute.raw = 0; | 54 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); |
| 48 | if (!pressed && touch_btn_device) { | ||
| 49 | std::tie(x, y, pressed) = touch_btn_device->GetStatus(); | ||
| 50 | } | 55 | } |
| 51 | if (pressed && Settings::values.touchscreen.enabled) { | 56 | |
| 52 | touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); | 57 | if (Settings::values.use_touch_from_button) { |
| 53 | touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); | 58 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); |
| 54 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; | 59 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { |
| 55 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; | 60 | keyboard_finger_id[id] = |
| 56 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; | 61 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); |
| 57 | const u64 tick = core_timing.GetCPUTicks(); | 62 | } |
| 58 | touch_entry.delta_time = tick - last_touch; | ||
| 59 | last_touch = tick; | ||
| 60 | touch_entry.finger = Settings::values.touchscreen.finger; | ||
| 61 | cur_entry.entry_count = 1; | ||
| 62 | } else { | ||
| 63 | cur_entry.entry_count = 0; | ||
| 64 | } | 63 | } |
| 65 | 64 | ||
| 65 | std::array<Finger, 16> active_fingers; | ||
| 66 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), | ||
| 67 | [](const auto& finger) { return finger.pressed; }); | ||
| 68 | const auto active_fingers_count = | ||
| 69 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); | ||
| 70 | |||
| 71 | const u64 tick = core_timing.GetCPUTicks(); | ||
| 72 | cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); | ||
| 73 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||
| 74 | auto& touch_entry = cur_entry.states[id]; | ||
| 75 | if (id < active_fingers_count) { | ||
| 76 | touch_entry.x = static_cast<u16>(active_fingers[id].x * Layout::ScreenUndocked::Width); | ||
| 77 | touch_entry.y = static_cast<u16>(active_fingers[id].y * Layout::ScreenUndocked::Height); | ||
| 78 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; | ||
| 79 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; | ||
| 80 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; | ||
| 81 | touch_entry.delta_time = tick - active_fingers[id].last_touch; | ||
| 82 | fingers[active_fingers[id].id].last_touch = tick; | ||
| 83 | touch_entry.finger = active_fingers[id].id; | ||
| 84 | touch_entry.attribute.raw = active_fingers[id].attribute.raw; | ||
| 85 | } else { | ||
| 86 | // Clear touch entry | ||
| 87 | touch_entry.attribute.raw = 0; | ||
| 88 | touch_entry.x = 0; | ||
| 89 | touch_entry.y = 0; | ||
| 90 | touch_entry.diameter_x = 0; | ||
| 91 | touch_entry.diameter_y = 0; | ||
| 92 | touch_entry.rotation_angle = 0; | ||
| 93 | touch_entry.delta_time = 0; | ||
| 94 | touch_entry.finger = 0; | ||
| 95 | } | ||
| 96 | } | ||
| 66 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); | 97 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); |
| 67 | } | 98 | } |
| 68 | 99 | ||
| 69 | void Controller_Touchscreen::OnLoadInputDevices() { | 100 | void Controller_Touchscreen::OnLoadInputDevices() { |
| 70 | touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); | 101 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); |
| 71 | if (Settings::values.use_touch_from_button) { | 102 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); |
| 72 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); | 103 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); |
| 73 | } else { | 104 | } |
| 74 | touch_btn_device.reset(); | 105 | |
| 106 | std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { | ||
| 107 | std::size_t first_free_id = 0; | ||
| 108 | while (first_free_id < MAX_FINGERS) { | ||
| 109 | if (!fingers[first_free_id].pressed) { | ||
| 110 | return first_free_id; | ||
| 111 | } else { | ||
| 112 | first_free_id++; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | return std::nullopt; | ||
| 116 | } | ||
| 117 | |||
| 118 | std::size_t Controller_Touchscreen::UpdateTouchInputEvent( | ||
| 119 | const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||
| 120 | const auto& [x, y, pressed] = touch_input; | ||
| 121 | if (pressed) { | ||
| 122 | Attributes attribute{}; | ||
| 123 | if (finger_id == MAX_FINGERS) { | ||
| 124 | const auto first_free_id = GetUnusedFingerID(); | ||
| 125 | if (!first_free_id) { | ||
| 126 | // Invalid finger id do nothing | ||
| 127 | return MAX_FINGERS; | ||
| 128 | } | ||
| 129 | finger_id = first_free_id.value(); | ||
| 130 | fingers[finger_id].pressed = true; | ||
| 131 | fingers[finger_id].id = static_cast<u32_le>(finger_id); | ||
| 132 | attribute.start_touch.Assign(1); | ||
| 133 | } | ||
| 134 | fingers[finger_id].x = x; | ||
| 135 | fingers[finger_id].y = y; | ||
| 136 | fingers[finger_id].attribute = attribute; | ||
| 137 | return finger_id; | ||
| 75 | } | 138 | } |
| 139 | |||
| 140 | if (finger_id != MAX_FINGERS) { | ||
| 141 | if (!fingers[finger_id].attribute.end_touch) { | ||
| 142 | fingers[finger_id].attribute.end_touch.Assign(1); | ||
| 143 | fingers[finger_id].attribute.start_touch.Assign(0); | ||
| 144 | return finger_id; | ||
| 145 | } | ||
| 146 | fingers[finger_id].pressed = false; | ||
| 147 | } | ||
| 148 | |||
| 149 | return MAX_FINGERS; | ||
| 76 | } | 150 | } |
| 151 | |||
| 77 | } // namespace Service::HID | 152 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 4d9042adc..784124e25 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -30,6 +30,18 @@ public: | |||
| 30 | void OnLoadInputDevices() override; | 30 | void OnLoadInputDevices() override; |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | static constexpr std::size_t MAX_FINGERS = 16; | ||
| 34 | |||
| 35 | // Returns an unused finger id, if there is no fingers available std::nullopt will be returned | ||
| 36 | std::optional<std::size_t> GetUnusedFingerID() const; | ||
| 37 | |||
| 38 | // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no | ||
| 39 | // changes will be made. Updates the coordinates if the finger id it's already set. If the touch | ||
| 40 | // ends delays the output by one frame to set the end_touch flag before finally freeing the | ||
| 41 | // finger id | ||
| 42 | std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | ||
| 43 | std::size_t finger_id); | ||
| 44 | |||
| 33 | struct Attributes { | 45 | struct Attributes { |
| 34 | union { | 46 | union { |
| 35 | u32 raw{}; | 47 | u32 raw{}; |
| @@ -55,7 +67,7 @@ private: | |||
| 55 | s64_le sampling_number; | 67 | s64_le sampling_number; |
| 56 | s64_le sampling_number2; | 68 | s64_le sampling_number2; |
| 57 | s32_le entry_count; | 69 | s32_le entry_count; |
| 58 | std::array<TouchState, 16> states; | 70 | std::array<TouchState, MAX_FINGERS> states; |
| 59 | }; | 71 | }; |
| 60 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); | 72 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); |
| 61 | 73 | ||
| @@ -66,9 +78,23 @@ private: | |||
| 66 | }; | 78 | }; |
| 67 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, | 79 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, |
| 68 | "TouchScreenSharedMemory is an invalid size"); | 80 | "TouchScreenSharedMemory is an invalid size"); |
| 81 | |||
| 82 | struct Finger { | ||
| 83 | u64_le last_touch{}; | ||
| 84 | float x{}; | ||
| 85 | float y{}; | ||
| 86 | u32_le id{}; | ||
| 87 | bool pressed{}; | ||
| 88 | Attributes attribute; | ||
| 89 | }; | ||
| 90 | |||
| 69 | TouchScreenSharedMemory shared_memory{}; | 91 | TouchScreenSharedMemory shared_memory{}; |
| 70 | std::unique_ptr<Input::TouchDevice> touch_device; | 92 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; |
| 93 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | ||
| 71 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | 94 | std::unique_ptr<Input::TouchDevice> touch_btn_device; |
| 72 | s64_le last_touch{}; | 95 | std::array<std::size_t, MAX_FINGERS> mouse_finger_id; |
| 96 | std::array<std::size_t, MAX_FINGERS> keyboard_finger_id; | ||
| 97 | std::array<std::size_t, MAX_FINGERS> udp_finger_id; | ||
| 98 | std::array<Finger, MAX_FINGERS> fingers; | ||
| 73 | }; | 99 | }; |
| 74 | } // namespace Service::HID | 100 | } // namespace Service::HID |