diff --git a/32blit-pico/input_usb_hid.cpp b/32blit-pico/input_usb_hid.cpp index b2b0f918d..0dd4e6852 100644 --- a/32blit-pico/input_usb_hid.cpp +++ b/32blit-pico/input_usb_hid.cpp @@ -5,14 +5,19 @@ #include "pico/binary_info.h" +#include "class/hid/hid.h" + #include "engine/api_private.hpp" #include "engine/input.hpp" // from USB code extern uint32_t hid_gamepad_id; +extern bool hid_keyboard_detected; extern uint8_t hid_joystick[2]; extern uint8_t hid_hat; extern uint32_t hid_buttons; +extern uint8_t hid_keys[6]; + struct GamepadMapping { uint32_t id; // vid:pid uint8_t a, b, x, y; @@ -44,9 +49,68 @@ void init_input() { void update_input() { using namespace blit; + // keyboard + if(hid_keyboard_detected) { + uint32_t new_buttons = 0; + + for(int i = 0; i < 6; i++) { + switch(hid_keys[i]) { + case HID_KEY_ARROW_UP: + case HID_KEY_W: + new_buttons |= uint32_t(Button::DPAD_UP); + break; + case HID_KEY_ARROW_DOWN: + case HID_KEY_S: + new_buttons |= uint32_t(Button::DPAD_DOWN); + break; + case HID_KEY_ARROW_LEFT: + case HID_KEY_A: + new_buttons |= uint32_t(Button::DPAD_LEFT); + break; + case HID_KEY_ARROW_RIGHT: + case HID_KEY_D: + new_buttons |= uint32_t(Button::DPAD_RIGHT); + break; + + case HID_KEY_Z: + case HID_KEY_U: + new_buttons |= uint32_t(Button::A); + break; + case HID_KEY_X: + case HID_KEY_I: + new_buttons |= uint32_t(Button::B); + break; + case HID_KEY_C: + case HID_KEY_O: + new_buttons |= uint32_t(Button::X); + break; + case HID_KEY_V: + case HID_KEY_P: + new_buttons |= uint32_t(Button::Y); + break; + + case HID_KEY_1: + new_buttons |= uint32_t(Button::HOME); + break; + + case HID_KEY_2: + case HID_KEY_ESCAPE: + new_buttons |= uint32_t(Button::MENU); + break; + + case HID_KEY_3: + new_buttons |= uint32_t(Button::JOYSTICK); + break; + } + } + + api.buttons = new_buttons; + } + if(!hid_gamepad_id) return; + // gamepad auto mapping = gamepad_mappings; while(mapping->id && mapping->id != hid_gamepad_id) mapping++; diff --git a/32blit-pico/usb_host.cpp b/32blit-pico/usb_host.cpp index 0a57fba21..585d6d486 100644 --- a/32blit-pico/usb_host.cpp +++ b/32blit-pico/usb_host.cpp @@ -14,9 +14,11 @@ static uint16_t buttons_offset = 0, num_buttons = 0; static uint16_t hat_offset = 0, stick_offset = 0; uint32_t hid_gamepad_id = 0; +bool hid_keyboard_detected = false; uint8_t hid_joystick[2]{0x80, 0x80}; uint8_t hid_hat = 8; uint32_t hid_buttons = 0; +uint8_t hid_keys[6]{}; void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { uint16_t vid = 0, pid = 0; @@ -24,7 +26,15 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re printf("Mount %i %i, %04x:%04x\n", dev_addr, instance, vid, pid); - hid_gamepad_id = (vid << 16) | pid; + auto protocol = tuh_hid_interface_protocol(dev_addr, instance); + + hid_keyboard_detected = protocol == HID_ITF_PROTOCOL_KEYBOARD; + + // don't attempt to use a keyboard/mouse as a gamepad + if(protocol != HID_ITF_PROTOCOL_NONE) { + tuh_hid_receive_report(dev_addr, instance); + return; + } // basic and probably wrong report descriptor parsing auto desc_end = desc_report + desc_len; @@ -35,6 +45,8 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re int usage = -1; int report_count = 0, report_size = 0; + bool found_any = false; + int bit_offset = 0; while(p != desc_end) { @@ -50,12 +62,15 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re if(usage_page == HID_USAGE_PAGE_DESKTOP && usage == HID_USAGE_DESKTOP_X) { stick_offset = bit_offset; hid_report_id = report_id; // assume everything is in the same report as the stick... and that the first x/y is the stick + found_any = true; } else if(usage_page == HID_USAGE_PAGE_DESKTOP && usage == HID_USAGE_DESKTOP_HAT_SWITCH) { hat_offset = bit_offset; + found_any = true; } else if(usage_page == HID_USAGE_PAGE_BUTTON && !(*p & HID_CONSTANT)) { // assume this is "the buttons" buttons_offset = bit_offset; num_buttons = report_count; + found_any = true; } usage = -1; @@ -83,16 +98,38 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re p += len; } + // don't bother requesting reports we can't parse + if(!found_any) + return; + + hid_gamepad_id = (vid << 16) | pid; + if(!tuh_hid_receive_report(dev_addr, instance)) { printf("Cound not request report!\n"); } } +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { + hid_keyboard_detected = false; + hid_gamepad_id = 0; +} + // should this be here or in input.cpp? void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { auto report_data = hid_report_id == -1 ? report : report + 1; + auto protocol = tuh_hid_interface_protocol(dev_addr, instance); + + if(protocol == HID_ITF_PROTOCOL_KEYBOARD) { + hid_keyboard_detected = true; + auto keyboard_report = (hid_keyboard_report_t const*) report; + memcpy(hid_keys, keyboard_report->keycode, 6); + + tuh_hid_receive_report(dev_addr, instance); + return; + } + // check report id if we have one if(hid_report_id == -1 || report[0] == hid_report_id) { // I hope these are reasonably aligned