@ -5,8 +5,52 @@
/** Downcast key processor to keyboard_uhid */
# define DOWNCAST(KP) container_of(KP, struct sc_keyboard_uhid, key_processor)
/** Downcast uhid_receiver to keyboard_uhid */
# define DOWNCAST_RECEIVER(UR) \
container_of ( UR , struct sc_keyboard_uhid , uhid_receiver )
# define UHID_KEYBOARD_ID 1
static void
sc_keyboard_uhid_send_input ( struct sc_keyboard_uhid * kb ,
const struct sc_hid_event * event ) {
struct sc_control_msg msg ;
msg . type = SC_CONTROL_MSG_TYPE_UHID_INPUT ;
msg . uhid_input . id = UHID_KEYBOARD_ID ;
assert ( event - > size < = SC_HID_MAX_SIZE ) ;
memcpy ( msg . uhid_input . data , event - > data , event - > size ) ;
msg . uhid_input . size = event - > size ;
if ( ! sc_controller_push_msg ( kb - > controller , & msg ) ) {
LOGE ( " Could not send UHID_INPUT message (key) " ) ;
}
}
static void
sc_keyboard_uhid_synchronize_mod ( struct sc_keyboard_uhid * kb ) {
SDL_Keymod sdl_mod = SDL_GetModState ( ) ;
uint16_t mod = sc_mods_state_from_sdl ( sdl_mod ) & ( SC_MOD_CAPS | SC_MOD_NUM ) ;
uint16_t device_mod =
atomic_load_explicit ( & kb - > device_mod , memory_order_relaxed ) ;
uint16_t diff = mod ^ device_mod ;
if ( diff ) {
// Inherently racy (the HID output reports arrive asynchronously in
// response to key presses), but will re-synchronize on next key press
// or HID output anyway
atomic_store_explicit ( & kb - > device_mod , mod , memory_order_relaxed ) ;
struct sc_hid_event hid_event ;
sc_hid_keyboard_event_from_mods ( & hid_event , diff ) ;
LOGV ( " HID keyboard state synchronized " ) ;
sc_keyboard_uhid_send_input ( kb , & hid_event ) ;
}
}
static void
sc_key_processor_process_key ( struct sc_key_processor * kp ,
const struct sc_key_event * event ,
@ -25,26 +69,56 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
// Not all keys are supported, just ignore unsupported keys
if ( sc_hid_keyboard_event_from_key ( & kb - > hid , & hid_event , event ) ) {
struct sc_control_msg msg ;
msg . type = SC_CONTROL_MSG_TYPE_UHID_INPUT ;
msg . uhid_input . id = UHID_KEYBOARD_ID ;
assert ( hid_event . size < = SC_HID_MAX_SIZE ) ;
memcpy ( msg . uhid_input . data , hid_event . data , hid_event . size ) ;
msg . uhid_input . size = hid_event . size ;
if ( ! sc_controller_push_msg ( kb - > controller , & msg ) ) {
LOGE( " Could not send UHID_INPUT message (key) " ) ;
if ( event - > scancode = = SC_SCANCODE_CAPSLOCK ) {
atomic_fetch_xor_explicit ( & kb - > device_mod , SC_MOD_CAPS ,
memory_order_relaxed ) ;
} else if ( event - > scancode = = SC_SCANCODE_NUMLOCK ) {
atomic_fetch_xor_explicit ( & kb - > device_mod , SC_MOD_NUM ,
memory_order_relaxed ) ;
} else {
// Synchronize modifiers (only if the scancode itself does not
// change the modifiers)
sc_keyboard_uhid_synchronize_mod( kb ) ;
}
sc_keyboard_uhid_send_input ( kb , & hid_event ) ;
}
}
static unsigned
sc_keyboard_uhid_to_sc_mod ( uint8_t hid_led ) {
// <https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf>
// (chapter 11: LED page)
unsigned mod = 0 ;
if ( hid_led & 0x01 ) {
mod | = SC_MOD_NUM ;
}
if ( hid_led & 0x02 ) {
mod | = SC_MOD_CAPS ;
}
return mod ;
}
static void
sc_uhid_receiver_process_output ( struct sc_uhid_receiver * receiver ,
const uint8_t * data , size_t len ) {
// Called from the thread receiving device messages
assert ( len ) ;
( void ) len ;
struct sc_keyboard_uhid * kb = DOWNCAST_RECEIVER ( receiver ) ;
uint8_t hid_led = data [ 0 ] ;
uint16_t device_mod = sc_keyboard_uhid_to_sc_mod ( hid_led ) ;
atomic_store_explicit ( & kb - > device_mod , device_mod , memory_order_relaxed ) ;
}
bool
sc_keyboard_uhid_init ( struct sc_keyboard_uhid * kb ,
struct sc_controller * controller ) {
struct sc_controller * controller ,
struct sc_uhid_devices * uhid_devices ) {
sc_hid_keyboard_init ( & kb - > hid ) ;
kb - > controller = controller ;
atomic_init ( & kb - > device_mod , 0 ) ;
static const struct sc_key_processor_ops ops = {
. process_key = sc_key_processor_process_key ,
@ -58,6 +132,14 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
kb - > key_processor . async_paste = false ;
kb - > key_processor . ops = & ops ;
static const struct sc_uhid_receiver_ops uhid_receiver_ops = {
. process_output = sc_uhid_receiver_process_output ,
} ;
kb - > uhid_receiver . id = UHID_KEYBOARD_ID ;
kb - > uhid_receiver . ops = & uhid_receiver_ops ;
sc_uhid_devices_add_receiver ( uhid_devices , & kb - > uhid_receiver ) ;
struct sc_control_msg msg ;
msg . type = SC_CONTROL_MSG_TYPE_UHID_CREATE ;
msg . uhid_create . id = UHID_KEYBOARD_ID ;