Skip to content

Commit

Permalink
pico: HID keyboard
Browse files Browse the repository at this point in the history
This works most of the time.
  • Loading branch information
Daft-Freak committed Feb 25, 2023
1 parent 9e5e103 commit 3d1ed59
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
64 changes: 64 additions & 0 deletions 32blit-pico/input_usb_hid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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++;
Expand Down
39 changes: 38 additions & 1 deletion 32blit-pico/usb_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,27 @@ 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;
tuh_vid_pid_get(dev_addr, &vid, &pid);

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;
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3d1ed59

Please sign in to comment.