ControllerInterface.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2010 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <atomic>
  5. #include <functional>
  6. #include <list>
  7. #include <memory>
  8. #include <mutex>
  9. #include "Common/Matrix.h"
  10. #include "Common/WindowSystemInfo.h"
  11. #include "InputCommon/ControllerInterface/CoreDevice.h"
  12. #include "InputCommon/ControllerInterface/InputBackend.h"
  13. // enable disable sources
  14. #ifdef _WIN32
  15. #define CIFACE_USE_WIN32
  16. #endif
  17. #ifdef HAVE_X11
  18. #define CIFACE_USE_XLIB
  19. #endif
  20. #if defined(__APPLE__)
  21. #define CIFACE_USE_OSX
  22. #endif
  23. #if defined(HAVE_LIBEVDEV) && defined(HAVE_LIBUDEV)
  24. #define CIFACE_USE_EVDEV
  25. #endif
  26. #if defined(USE_PIPES)
  27. #define CIFACE_USE_PIPES
  28. #endif
  29. #define CIFACE_USE_DUALSHOCKUDPCLIENT
  30. #if defined(HAVE_SDL2)
  31. #define CIFACE_USE_SDL
  32. #endif
  33. #if defined(HAVE_HIDAPI)
  34. #define CIFACE_USE_STEAMDECK
  35. #endif
  36. namespace ciface
  37. {
  38. // A thread local "input channel" is maintained to handle the state of relative inputs.
  39. // This allows simultaneous use of relative inputs across different input contexts.
  40. // e.g. binding relative mouse movements to both GameCube controllers and FreeLook.
  41. // These operate at different rates and processing one would break the other without separate state.
  42. enum class InputChannel
  43. {
  44. Host,
  45. SerialInterface,
  46. Bluetooth,
  47. FreeLook,
  48. Count,
  49. };
  50. } // namespace ciface
  51. //
  52. // ControllerInterface
  53. //
  54. // Some crazy shit I made to control different device inputs and outputs
  55. // from lots of different sources, hopefully more easily.
  56. //
  57. class ControllerInterface : public ciface::Core::DeviceContainer
  58. {
  59. public:
  60. using HotplugCallbackHandle = std::list<std::function<void()>>::iterator;
  61. enum class WindowChangeReason
  62. {
  63. // Application is shutting down
  64. Exit,
  65. Other
  66. };
  67. enum class RefreshReason
  68. {
  69. // Only the window changed.
  70. WindowChangeOnly,
  71. // User requested, or any other internal reason (e.g. init).
  72. // The window might have changed anyway.
  73. Other
  74. };
  75. ControllerInterface() : m_is_init(false) {}
  76. void Initialize(const WindowSystemInfo& wsi);
  77. // Only call from one thread at a time.
  78. void ChangeWindow(void* hwnd, WindowChangeReason reason = WindowChangeReason::Other);
  79. // Can be called by any thread at any time (when initialized).
  80. void RefreshDevices(RefreshReason reason = RefreshReason::Other);
  81. void Shutdown();
  82. bool AddDevice(std::shared_ptr<ciface::Core::Device> device);
  83. // Removes all the devices the function returns true to.
  84. // If all the devices shared ptrs need to be destroyed immediately,
  85. // set force_devices_release to true.
  86. void RemoveDevice(std::function<bool(const ciface::Core::Device*)> callback,
  87. bool force_devices_release = false);
  88. // This is mandatory to use on device populations functions that can be called concurrently by
  89. // more than one thread, or that are called by a single other thread.
  90. // Without this, our devices list might end up in a mixed state.
  91. void PlatformPopulateDevices(std::function<void()> callback);
  92. bool IsInit() const { return m_is_init; }
  93. void UpdateInput();
  94. // Set adjustment from the full render window aspect-ratio to the drawn aspect-ratio.
  95. // Used to fit mouse cursor inputs to the relevant region of the render window.
  96. void SetAspectRatioAdjustment(float);
  97. // Calculated from the aspect-ratio adjustment.
  98. // Inputs based on window coordinates should be multiplied by this.
  99. Common::Vec2 GetWindowInputScale() const;
  100. // Request that the mouse cursor should be centered in the render window at the next opportunity.
  101. void SetMouseCenteringRequested(bool center);
  102. bool IsMouseCenteringRequested() const;
  103. HotplugCallbackHandle RegisterDevicesChangedCallback(std::function<void(void)> callback);
  104. void UnregisterDevicesChangedCallback(const HotplugCallbackHandle& handle);
  105. void InvokeDevicesChangedCallbacks() const;
  106. static void SetCurrentInputChannel(ciface::InputChannel);
  107. static ciface::InputChannel GetCurrentInputChannel();
  108. WindowSystemInfo GetWindowSystemInfo() const;
  109. private:
  110. void ClearDevices();
  111. std::list<std::function<void()>> m_devices_changed_callbacks;
  112. mutable std::recursive_mutex m_devices_population_mutex;
  113. mutable std::mutex m_callbacks_mutex;
  114. std::atomic<bool> m_is_init;
  115. // This is now always protected by m_devices_population_mutex, so
  116. // it doesn't really need to be a counter or atomic anymore (it could be a raw bool),
  117. // but we keep it so for simplicity, in case we changed the design.
  118. std::atomic<int> m_populating_devices_counter;
  119. WindowSystemInfo m_wsi;
  120. std::atomic<float> m_aspect_ratio_adjustment = 1;
  121. std::atomic<bool> m_requested_mouse_centering = false;
  122. std::vector<std::unique_ptr<ciface::InputBackend>> m_input_backends;
  123. };
  124. namespace ciface
  125. {
  126. template <typename T>
  127. class RelativeInputState
  128. {
  129. public:
  130. void Update()
  131. {
  132. const auto channel = int(ControllerInterface::GetCurrentInputChannel());
  133. m_value[channel] = m_delta[channel];
  134. m_delta[channel] = {};
  135. }
  136. T GetValue() const
  137. {
  138. const auto channel = int(ControllerInterface::GetCurrentInputChannel());
  139. return m_value[channel];
  140. }
  141. void Move(T delta)
  142. {
  143. for (auto& d : m_delta)
  144. d += delta;
  145. }
  146. private:
  147. std::array<T, int(InputChannel::Count)> m_value;
  148. std::array<T, int(InputChannel::Count)> m_delta;
  149. };
  150. } // namespace ciface
  151. extern ControllerInterface g_controller_interface;