touchscreen.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <cstring>
  5. #include "common/common_types.h"
  6. #include "common/settings.h"
  7. #include "core/core.h"
  8. #include "core/core_timing.h"
  9. #include "core/frontend/emu_window.h"
  10. #include "core/hid/emulated_console.h"
  11. #include "core/hid/hid_core.h"
  12. #include "core/hle/service/hid/controllers/touchscreen.h"
  13. namespace Service::HID {
  14. constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
  15. Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_,
  16. u8* raw_shared_memory_)
  17. : ControllerBase{hid_core_} {
  18. static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
  19. "TouchSharedMemory is bigger than the shared memory");
  20. shared_memory = std::construct_at(
  21. reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
  22. console = hid_core.GetEmulatedConsole();
  23. }
  24. Controller_Touchscreen::~Controller_Touchscreen() = default;
  25. void Controller_Touchscreen::OnInit() {}
  26. void Controller_Touchscreen::OnRelease() {}
  27. void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
  28. shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
  29. if (!IsControllerActivated()) {
  30. shared_memory->touch_screen_lifo.buffer_count = 0;
  31. shared_memory->touch_screen_lifo.buffer_tail = 0;
  32. return;
  33. }
  34. const auto touch_status = console->GetTouch();
  35. for (std::size_t id = 0; id < MAX_FINGERS; id++) {
  36. const auto& current_touch = touch_status[id];
  37. auto& finger = fingers[id];
  38. finger.id = current_touch.id;
  39. if (finger.attribute.start_touch) {
  40. finger.attribute.raw = 0;
  41. continue;
  42. }
  43. if (finger.attribute.end_touch) {
  44. finger.attribute.raw = 0;
  45. finger.pressed = false;
  46. continue;
  47. }
  48. if (!finger.pressed && current_touch.pressed) {
  49. // Ignore all touch fingers if disabled
  50. if (!Settings::values.touchscreen.enabled) {
  51. continue;
  52. }
  53. finger.attribute.start_touch.Assign(1);
  54. finger.pressed = true;
  55. finger.position = current_touch.position;
  56. continue;
  57. }
  58. if (finger.pressed && !current_touch.pressed) {
  59. finger.attribute.raw = 0;
  60. finger.attribute.end_touch.Assign(1);
  61. continue;
  62. }
  63. // Only update position if touch is not on a special frame
  64. finger.position = current_touch.position;
  65. }
  66. std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers;
  67. const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
  68. [](const auto& finger) { return finger.pressed; });
  69. const auto active_fingers_count =
  70. static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
  71. const u64 tick = core_timing.GetCPUTicks();
  72. const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
  73. next_state.sampling_number = last_entry.sampling_number + 1;
  74. next_state.entry_count = static_cast<s32>(active_fingers_count);
  75. for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
  76. auto& touch_entry = next_state.states[id];
  77. if (id < active_fingers_count) {
  78. const auto& [active_x, active_y] = active_fingers[id].position;
  79. touch_entry.position = {
  80. .x = static_cast<u16>(active_x * Layout::ScreenUndocked::Width),
  81. .y = static_cast<u16>(active_y * Layout::ScreenUndocked::Height),
  82. };
  83. touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
  84. touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
  85. touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
  86. touch_entry.delta_time = tick - active_fingers[id].last_touch;
  87. fingers[active_fingers[id].id].last_touch = tick;
  88. touch_entry.finger = active_fingers[id].id;
  89. touch_entry.attribute.raw = active_fingers[id].attribute.raw;
  90. } else {
  91. // Clear touch entry
  92. touch_entry.attribute.raw = 0;
  93. touch_entry.position = {};
  94. touch_entry.diameter_x = 0;
  95. touch_entry.diameter_y = 0;
  96. touch_entry.rotation_angle = 0;
  97. touch_entry.delta_time = 0;
  98. touch_entry.finger = 0;
  99. }
  100. }
  101. shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
  102. }
  103. } // namespace Service::HID