xbox_controller_mac.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef DEVICE_GAMEPAD_XBOX_CONTROLLER_MAC_H_
  5. #define DEVICE_GAMEPAD_XBOX_CONTROLLER_MAC_H_
  6. #include <CoreFoundation/CoreFoundation.h>
  7. #include <IOKit/IOKitLib.h>
  8. #include <stddef.h>
  9. #include <stdint.h>
  10. #include <memory>
  11. #include "base/mac/scoped_cftyperef.h"
  12. #include "base/mac/scoped_ioplugininterface.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/memory/weak_ptr.h"
  15. #include "base/task/sequenced_task_runner.h"
  16. #include "device/gamepad/abstract_haptic_gamepad.h"
  17. #include "device/gamepad/gamepad_id_list.h"
  18. #include "device/gamepad/public/mojom/gamepad.mojom-forward.h"
  19. struct IOUSBDeviceStruct320;
  20. struct IOUSBInterfaceStruct300;
  21. namespace device {
  22. class XboxControllerMac final : public AbstractHapticGamepad {
  23. public:
  24. enum LEDPattern {
  25. LED_OFF = 0,
  26. // 2 quick flashes, then a series of slow flashes (about 1 per second).
  27. LED_FLASH = 1,
  28. // Flash three times then hold the LED on. This is the standard way to tell
  29. // the player which player number they are.
  30. LED_FLASH_TOP_LEFT = 2,
  31. LED_FLASH_TOP_RIGHT = 3,
  32. LED_FLASH_BOTTOM_LEFT = 4,
  33. LED_FLASH_BOTTOM_RIGHT = 5,
  34. // Simply turn on the specified LED and turn all other LEDs off.
  35. LED_HOLD_TOP_LEFT = 6,
  36. LED_HOLD_TOP_RIGHT = 7,
  37. LED_HOLD_BOTTOM_LEFT = 8,
  38. LED_HOLD_BOTTOM_RIGHT = 9,
  39. LED_ROTATE = 10,
  40. LED_FLASH_FAST = 11,
  41. LED_FLASH_SLOW = 12, // Flash about once per 3 seconds
  42. // Flash alternating LEDs for a few seconds, then flash all LEDs about once
  43. // per second
  44. LED_ALTERNATE_PATTERN = 13,
  45. // 14 is just another boring flashing speed.
  46. // Flash all LEDs once then go black.
  47. LED_FLASH_ONCE = 15,
  48. LED_NUM_PATTERNS
  49. };
  50. enum OpenDeviceResult {
  51. OPEN_SUCCEEDED = 0,
  52. OPEN_FAILED,
  53. OPEN_FAILED_EXCLUSIVE_ACCESS
  54. };
  55. struct Data {
  56. bool buttons[15];
  57. float triggers[2];
  58. float axes[4];
  59. };
  60. class Delegate {
  61. public:
  62. virtual void XboxControllerGotData(XboxControllerMac* controller,
  63. const Data& data) = 0;
  64. virtual void XboxControllerGotGuideData(XboxControllerMac* controller,
  65. bool guide) = 0;
  66. virtual void XboxControllerError(XboxControllerMac* controller) = 0;
  67. };
  68. explicit XboxControllerMac(Delegate* delegate);
  69. XboxControllerMac(const XboxControllerMac& entry) = delete;
  70. XboxControllerMac& operator=(const XboxControllerMac& entry) = delete;
  71. ~XboxControllerMac() override;
  72. // Open the Xbox controller represented by |service| and perform any necessary
  73. // initialization. Returns OPEN_SUCCEEDED if the device was opened
  74. // successfully or OPEN_FAILED on failure. Returns
  75. // OPEN_FAILED_EXCLUSIVE_ACCESS if the device is already opened by another
  76. // process.
  77. OpenDeviceResult OpenDevice(io_service_t service);
  78. // Send a command to an Xbox 360 controller to set the player indicator LED
  79. // |pattern|.
  80. void SetLEDPattern(LEDPattern pattern);
  81. // AbstractHapticGamepad implementation.
  82. void DoShutdown() override;
  83. double GetMaxEffectDurationMillis() override;
  84. void SetVibration(mojom::GamepadEffectParametersPtr params) override;
  85. base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
  86. uint32_t location_id() const { return location_id_; }
  87. GamepadId gamepad_id() const { return gamepad_id_; }
  88. XInputType xinput_type() const { return xinput_type_; }
  89. uint16_t vendor_id() const { return vendor_id_; }
  90. uint16_t product_id() const { return product_id_; }
  91. std::string product_name() const { return product_name_; }
  92. bool SupportsVibration() const;
  93. private:
  94. // Callback to be called when outgoing packets are sent to the device.
  95. // |context| is a pointer to the XboxControllerMac and |result| is the error
  96. // code for the write operation. |arg0| is unused.
  97. static void WriteComplete(void* context, IOReturn result, void* arg0);
  98. // Callback to be called when incoming packets are received from the device.
  99. // |context| is a pointer to the XboxControllerMac, |result| is the error
  100. // code for the read operation, and |*arg0| contains the number of bytes
  101. // received.
  102. //
  103. // GotData calls IOError if |result| indicates the current read operation
  104. // failed, or if scheduling the next read operation fails.
  105. static void GotData(void* context, IOReturn result, void* arg0);
  106. // Process the incoming packet in |read_buffer_| as an Xbox 360 packet.
  107. // |length| is the size of the packet in bytes.
  108. void ProcessXbox360Packet(size_t length);
  109. // Process the incoming packet in |read_buffer_| as an Xbox One packet.
  110. // |length| is the size of the packet in bytes.
  111. void ProcessXboxOnePacket(size_t length);
  112. // Queue a read from the device. Returns true if the read was queued, or false
  113. // on I/O error.
  114. bool QueueRead();
  115. // Notify the delegate that a fatal I/O error occurred.
  116. void IOError();
  117. // Send an Xbox 360 rumble packet to the device, where |strong_magnitude| and
  118. // |weak_magnitude| are values in the range [0,255] that represent the
  119. // vibration intensity for the strong and weak rumble motors.
  120. void WriteXbox360Rumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
  121. // Send an Xbox One S initialization packet to the device. Returns true if the
  122. // packet was sent successfully, or false on I/O error.
  123. bool WriteXboxOneInit();
  124. // Send an Xbox One rumble packet to the device, where |strong_magnitude| and
  125. // |weak_magnitude| are values in the range [0,255] that represent the
  126. // vibration intensity for the strong and weak rumble motors.
  127. void WriteXboxOneRumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
  128. // Send an Xbox One packet to the device acknowledging that the Xbox button
  129. // was pressed or released. |sequence_number| must match the value in the
  130. // incoming report containing the new button state.
  131. void WriteXboxOneAckGuide(uint8_t sequence_number);
  132. // Handle for the USB device. IOUSBDeviceStruct320 is the latest version of
  133. // the device API that is supported on Mac OS 10.6.
  134. base::mac::ScopedIOPluginInterface<IOUSBDeviceStruct320> device_;
  135. // Handle for the interface on the device which sends button and analog data.
  136. // The other interfaces (for the ChatPad and headset) are ignored.
  137. base::mac::ScopedIOPluginInterface<IOUSBInterfaceStruct300> interface_;
  138. bool device_is_open_ = false;
  139. bool interface_is_open_ = false;
  140. base::ScopedCFTypeRef<CFRunLoopSourceRef> source_;
  141. // This will be set to the max packet size reported by the interface, which
  142. // is 32 bytes. I would have expected USB to do message framing itself, but
  143. // somehow we still sometimes (rarely!) get packets off the interface which
  144. // aren't correctly framed. The 360 controller frames its packets with a 2
  145. // byte header (type, total length) so we can reframe the packet data
  146. // ourselves.
  147. uint16_t read_buffer_size_ = 0;
  148. std::unique_ptr<uint8_t[]> read_buffer_;
  149. // The pattern that the LEDs on the device are currently displaying, or
  150. // LED_NUM_PATTERNS if unknown.
  151. LEDPattern led_pattern_ = LED_NUM_PATTERNS;
  152. uint32_t location_id_ = 0;
  153. raw_ptr<Delegate> delegate_ = nullptr;
  154. XInputType xinput_type_ = kXInputTypeNone;
  155. GamepadId gamepad_id_ = GamepadId::kUnknownGamepad;
  156. uint16_t vendor_id_ = 0;
  157. uint16_t product_id_ = 0;
  158. std::string product_name_;
  159. int read_endpoint_ = 0;
  160. int control_endpoint_ = 0;
  161. uint8_t counter_ = 0;
  162. base::WeakPtrFactory<XboxControllerMac> weak_factory_{this};
  163. };
  164. } // namespace device
  165. #endif // DEVICE_GAMEPAD_XBOX_CONTROLLER_MAC_H_