forked from Genymobile/scrcpy
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic support to HID over AoAv2 for keyboard
This provides a better input experience via simulate physical keyboard, it converts SDL_KeyboardEvent to proper HID events and send it via HID over AoAv2. This is a rewriting and bugfix of the origin code from [@amosbird](https://github.com/amosbird).
- Loading branch information
Showing
13 changed files
with
656 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
#include "util/log.h" | ||
#include "aoa_hid.h" | ||
|
||
// See <https://source.android.com/devices/accessories/aoa2#hid-support>. | ||
#define ACCESSORY_REGISTER_HID 54 | ||
#define ACCESSORY_UNREGISTER_HID 55 | ||
#define ACCESSORY_SET_HID_REPORT_DESC 56 | ||
#define ACCESSORY_SEND_HID_EVENT 57 | ||
|
||
#define DEFAULT_TIMEOUT 1000 | ||
|
||
inline static void print_libusb_error(enum libusb_error errcode) { | ||
LOGW("libusb error: %s", libusb_strerror(errcode)); | ||
} | ||
|
||
libusb_device *aoa_find_usb_device(uint16_t vid, uint16_t pid) { | ||
libusb_device **list; | ||
libusb_device *result = NULL; | ||
ssize_t count = libusb_get_device_list(NULL, &list); | ||
if (count < 0) { | ||
print_libusb_error((enum libusb_error)count); | ||
return NULL; | ||
} | ||
for (ssize_t i = 0; i < count; ++i) { | ||
libusb_device *device = list[i]; | ||
struct libusb_device_descriptor desc; | ||
libusb_get_device_descriptor(device, &desc); | ||
if (vid == desc.idVendor && pid == desc.idProduct) { | ||
result = libusb_ref_device(device); | ||
break; | ||
} | ||
} | ||
libusb_free_device_list(list, 1); | ||
return result; | ||
} | ||
|
||
int aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle) { | ||
int result = libusb_open(device, handle); | ||
if (result < 0) { | ||
print_libusb_error((enum libusb_error)result); | ||
return result; | ||
} | ||
return 0; | ||
} | ||
|
||
int aoa_register_hid(libusb_device_handle *handle, uint16_t report_desc_size) { | ||
const uint8_t request_type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR; | ||
const uint8_t request = ACCESSORY_REGISTER_HID; | ||
// See <https://source.android.com/devices/accessories/aoa2.html#hid-support>. | ||
// value (arg0): accessory assigned ID for the HID device | ||
// index (arg1): total length of the HID report descriptor | ||
const uint16_t value = 0; | ||
const uint16_t index = report_desc_size; | ||
unsigned char *buffer = NULL; | ||
const uint16_t length = 0; | ||
int result = libusb_control_transfer(handle, request_type, request, value, | ||
index, buffer, length, DEFAULT_TIMEOUT); | ||
if (result < 0) { | ||
print_libusb_error((enum libusb_error)result); | ||
return result; | ||
} | ||
return 0; | ||
} | ||
|
||
int aoa_unregister_hid(libusb_device_handle *handle) { | ||
const uint8_t request_type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR; | ||
const uint8_t request = ACCESSORY_UNREGISTER_HID; | ||
// See <https://source.android.com/devices/accessories/aoa2.html#hid-support>. | ||
// value (arg0): accessory assigned ID for the HID device | ||
// index (arg1): 0 | ||
const uint16_t value = 0; | ||
const uint16_t index = 0; | ||
unsigned char *buffer = NULL; | ||
const uint16_t length = 0; | ||
int result = libusb_control_transfer(handle, request_type, request, value, | ||
index, buffer, length, DEFAULT_TIMEOUT); | ||
if (result < 0) { | ||
print_libusb_error((enum libusb_error)result); | ||
return result; | ||
} | ||
return 0; | ||
} | ||
|
||
int | ||
aoa_set_hid_report_desc(libusb_device_handle *handle, | ||
const unsigned char *report_desc, uint16_t report_desc_size, | ||
uint8_t max_packet_size_0) { | ||
const uint8_t request_type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR; | ||
const uint8_t request = ACCESSORY_SET_HID_REPORT_DESC; | ||
// See <https://source.android.com/devices/accessories/aoa2.html#hid-support>. | ||
// value (arg0): accessory assigned ID for the HID device | ||
const uint16_t value = 0; | ||
// libusb_control_transfer expects non-const but should not modify it. | ||
unsigned char *buffer = (unsigned char *)report_desc; | ||
const uint16_t size = report_desc_size; | ||
/** | ||
* If the HID descriptor is longer than the endpoint zero max packet size, | ||
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC | ||
* commands. The data for the descriptor must be sent sequentially | ||
* if multiple packets are needed. | ||
* | ||
* See <https://source.android.com/devices/accessories/aoa2.html#hid-support>. | ||
*/ | ||
// index (arg1): offset of data (buffer) in descriptor | ||
uint16_t offset = 0; | ||
while (offset < size) { | ||
uint16_t packet_length = size - offset; | ||
if (packet_length > max_packet_size_0) { | ||
packet_length = max_packet_size_0; | ||
} | ||
int result = libusb_control_transfer( | ||
handle, request_type, request, value, offset, buffer + offset, packet_length, DEFAULT_TIMEOUT); | ||
offset += packet_length; | ||
if (result < 0) { | ||
print_libusb_error((enum libusb_error)result); | ||
return result; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
int | ||
aoa_send_hid_event(libusb_device_handle *handle, | ||
const unsigned char *event, uint16_t size) { | ||
const uint8_t request_type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR; | ||
const uint8_t request = ACCESSORY_SEND_HID_EVENT; | ||
// See <https://source.android.com/devices/accessories/aoa2.html#hid-support>. | ||
// value (arg0): accessory assigned ID for the HID device | ||
// index (arg1): 0 (unused) | ||
const uint16_t value = 0; | ||
const uint16_t index = 0; | ||
// libusb_control_transfer expects non-const but should not modify it. | ||
unsigned char *buffer = (unsigned char *)event; | ||
const uint16_t length = size; | ||
int result = libusb_control_transfer( | ||
handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); | ||
if (result < 0) { | ||
print_libusb_error((enum libusb_error)result); | ||
return result; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#ifndef AOA_HID_H | ||
#define AOA_HID_H | ||
|
||
#include <stdint.h> | ||
|
||
#include <libusb-1.0/libusb.h> | ||
|
||
libusb_device *aoa_find_usb_device(uint16_t vid, uint16_t pid); | ||
int aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle); | ||
int aoa_register_hid(libusb_device_handle *handle, uint16_t report_desc_size); | ||
int aoa_unregister_hid(libusb_device_handle *handle); | ||
int | ||
aoa_set_hid_report_desc(libusb_device_handle *handle, | ||
const unsigned char *report_desc, uint16_t report_desc_size, | ||
uint8_t max_packet_size_0); | ||
int | ||
aoa_send_hid_event(libusb_device_handle *handle, | ||
const unsigned char *event, uint16_t size); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.