Ver código fonte

Now only optionally force keyboard into boot protocol mode

The first gigabyte fix, was to always force the keyboard into boot protocol mode, which appeared to work well for all of the keyboards I tried.

Unforationally it caused issues with some wireless keyboard/mouse combo packages, including some logitech and some microsoft keyboards.

This version instead, I created a list (currently only one vendor id), of vendor id:product id, that need to be forced into boot mode.  Knowing that if there is one keyboard vendor with this N key rollover feature, there are probably others.  So while this list can be expanded, this requires users to update library.  So added a method forceBootProtocol method to keyboard class that allows the user to try it out without needing to update the library sources.

The mouse test program has example of either setting it before the keyboard is initiated, as well as another way that when a connection is found it asks for the vendor id, and if it is the one of my gigabyte keyboard, it calls the function then.

While doing this I found some of the query functions like idVendor on the keyboard class would not compile as the keyboard object has multiple inheritence and both base classes have this.  So like the joystick objects I added these to the top level function and these functions will direct the calls to the approrpriate places.
main
Kurt Eckhardt 6 anos atrás
pai
commit
4c909ab188
4 arquivos alterados com 146 adições e 32 exclusões
  1. +11
    -2
      USBHost_t36.h
  2. +44
    -26
      examples/Mouse/Mouse.ino
  3. +90
    -4
      keyboard.cpp
  4. +1
    -0
      keywords.txt

+ 11
- 2
USBHost_t36.h Ver arquivo

KeyboardController(USBHost &host) { init(); } KeyboardController(USBHost &host) { init(); }
KeyboardController(USBHost *host) { init(); } KeyboardController(USBHost *host) { init(); }


// need their own versions as both USBDriver and USBHIDInput provide
uint16_t idVendor();
uint16_t idProduct();
const uint8_t *manufacturer();
const uint8_t *product();
const uint8_t *serialNumber();

// Some methods are in both public classes so we need to figure out which one to use // Some methods are in both public classes so we need to figure out which one to use
operator bool() { return (device != nullptr); } operator bool() { return (device != nullptr); }
// Main boot keyboard functions. // Main boot keyboard functions.
// Added for extras information. // Added for extras information.
void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; } void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; }
void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; } void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; }
void forceBootProtocol();
enum {MAX_KEYS_DOWN=4}; enum {MAX_KEYS_DOWN=4};




volatile bool hid_input_data_ = false; // did we receive any valid data with report? volatile bool hid_input_data_ = false; // did we receive any valid data with report?
uint8_t count_keys_down_ = 0; uint8_t count_keys_down_ = 0;
uint16_t keys_down[MAX_KEYS_DOWN]; uint16_t keys_down[MAX_KEYS_DOWN];

bool force_boot_protocol; // User or VID/PID said force boot protocol?
bool control_queued;
}; };




uint8_t pl2303_v1; // Which version do we have uint8_t pl2303_v1; // Which version do we have
uint8_t pl2303_v2; uint8_t pl2303_v2;
uint8_t interface; uint8_t interface;
bool control_queued;
bool control_queued; // Is there already a queued control messaged
typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341, CP210X } sertype_t; typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341, CP210X } sertype_t;
sertype_t sertype; sertype_t sertype;



+ 44
- 26
examples/Mouse/Mouse.ino Ver arquivo

RawHIDController rawhid1(myusb); RawHIDController rawhid1(myusb);
RawHIDController rawhid2(myusb, 0xffc90004); RawHIDController rawhid2(myusb, 0xffc90004);


USBDriver *drivers[] = {&hub1, &hub2,&keyboard1, &keyboard2, &joystick1, &hid1, &hid2, &hid3, &hid4, &hid5};
USBDriver *drivers[] = {&hub1, &hub2, &keyboard1, &keyboard2, &joystick1, &hid1, &hid2, &hid3, &hid4, &hid5};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "KB1", "KB2", "JOY1D", "HID1", "HID2", "HID3", "HID4", "HID5"};
const char * driver_names[CNT_DEVICES] = {"Hub1", "Hub2", "KB1", "KB2", "JOY1D", "HID1", "HID2", "HID3", "HID4", "HID5"};
bool driver_active[CNT_DEVICES] = {false, false, false, false}; bool driver_active[CNT_DEVICES] = {false, false, false, false};


// Lets also look at HID Input devices // Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2}; USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) #define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"};
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1", "Joystick1", "RawHid1", "RawHid2"};
bool hid_driver_active[CNT_DEVICES] = {false, false}; bool hid_driver_active[CNT_DEVICES] = {false, false};
bool show_changed_only = false;
bool show_changed_only = false;


uint8_t joystick_left_trigger_value = 0; uint8_t joystick_left_trigger_value = 0;
uint8_t joystick_right_trigger_value = 0; uint8_t joystick_right_trigger_value = 0;
uint64_t joystick_full_notify_mask = (uint64_t)-1;
uint64_t joystick_full_notify_mask = (uint64_t) - 1;


void setup() void setup()
{ {
keyboard2.attachExtrasPress(OnHIDExtrasPress); keyboard2.attachExtrasPress(OnHIDExtrasPress);
keyboard2.attachExtrasRelease(OnHIDExtrasRelease); keyboard2.attachExtrasRelease(OnHIDExtrasRelease);


// The below forceBootProtocol will force which ever
// next keyboard that attaches to this device to be in boot protocol
// Only try this if you run into keyboard with issues. If this is a combined
// device like wireless mouse and keyboard this can cause mouse problems.
//keyboard1.forceBootProtocol();
rawhid1.attachReceive(OnReceiveHidData); rawhid1.attachReceive(OnReceiveHidData);
rawhid2.attachReceive(OnReceiveHidData); rawhid2.attachReceive(OnReceiveHidData);
} }
myusb.Task(); myusb.Task();


if (Serial.available()) { if (Serial.available()) {
int ch = Serial.read(); // get the first char.
while (Serial.read() != -1) ;
int ch = Serial.read(); // get the first char.
while (Serial.read() != -1) ;
if ((ch == 'b') || (ch == 'B')) { if ((ch == 'b') || (ch == 'B')) {
Serial.println("Only notify on Basic Axis changes"); Serial.println("Only notify on Basic Axis changes");
joystick1.axisChangeNotifyMask(0x3ff); joystick1.axisChangeNotifyMask(0x3ff);
Serial.println("\n*** Show only changed fields mode ***"); Serial.println("\n*** Show only changed fields mode ***");
} }
} }
}
}


for (uint8_t i = 0; i < CNT_DEVICES; i++) { for (uint8_t i = 0; i < CNT_DEVICES; i++) {
if (*drivers[i] != driver_active[i]) { if (*drivers[i] != driver_active[i]) {
if (psz && *psz) Serial.printf(" product: %s\n", psz); if (psz && *psz) Serial.printf(" product: %s\n", psz);
psz = drivers[i]->serialNumber(); psz = drivers[i]->serialNumber();
if (psz && *psz) Serial.printf(" Serial: %s\n", psz); if (psz && *psz) Serial.printf(" Serial: %s\n", psz);

// Note: with some keyboards there is an issue that they don't output in boot protocol mode
// and may not work. The above code can try to force the keyboard into boot mode, but there
// are issues with doing this blindly with combo devices like wireless keyboard/mouse, which
// may cause the mouse to not work. Note: the above id is in the builtin list of
// vendor IDs that are already forced
if (drivers[i] == &keyboard1) {
if (keyboard1.idVendor() == 0x04D9) {
Serial.println("Gigabyte vendor: force boot protocol");
// Gigabyte keyboard
keyboard1.forceBootProtocol();
}
}
} }
} }
} }






if(mouse1.available()) {
if (mouse1.available()) {
Serial.print("Mouse: buttons = "); Serial.print("Mouse: buttons = ");
Serial.print(mouse1.getButtons()); Serial.print(mouse1.getButtons());
Serial.print(", mouseX = "); Serial.print(", mouseX = ");
joystick_left_trigger_value = ltv; joystick_left_trigger_value = ltv;
joystick_right_trigger_value = rtv; joystick_right_trigger_value = rtv;
joystick1.setRumble(ltv, rtv); joystick1.setRumble(ltv, rtv);
}
}
break; break;


case JoystickController::PS3: case JoystickController::PS3:
joystick_left_trigger_value = ltv; joystick_left_trigger_value = ltv;
joystick_right_trigger_value = rtv; joystick_right_trigger_value = rtv;
joystick1.setRumble(ltv, rtv, 50); joystick1.setRumble(ltv, rtv, 50);
}
}
break; break;


case JoystickController::XBOXONE:
case JoystickController::XBOX360:
case JoystickController::XBOXONE:
case JoystickController::XBOX360:
ltv = joystick1.getAxis(4); ltv = joystick1.getAxis(4);
rtv = joystick1.getAxis(5); rtv = joystick1.getAxis(5);
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) { if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) {
joystick_right_trigger_value = rtv; joystick_right_trigger_value = rtv;
joystick1.setRumble(ltv, rtv); joystick1.setRumble(ltv, rtv);
Serial.printf(" Set Rumble %d %d", ltv, rtv); Serial.printf(" Set Rumble %d %d", ltv, rtv);
}
}
break; break;
} }
if (buttons != buttons_prev) { if (buttons != buttons_prev) {
if (joystick1.joystickType == JoystickController::PS3) { if (joystick1.joystickType == JoystickController::PS3) {
joystick1.setLEDs((buttons>>12) & 0xf); // try to get to TRI/CIR/X/SQuare
joystick1.setLEDs((buttons >> 12) & 0xf); // try to get to TRI/CIR/X/SQuare
} else { } else {
uint8_t lr = (buttons & 1)? 0xff : 0;
uint8_t lg = (buttons & 2)? 0xff : 0;
uint8_t lb = (buttons & 4)? 0xff : 0;
uint8_t lr = (buttons & 1) ? 0xff : 0;
uint8_t lg = (buttons & 2) ? 0xff : 0;
uint8_t lb = (buttons & 4) ? 0xff : 0;
joystick1.setLEDs(lr, lg, lb); joystick1.setLEDs(lr, lg, lb);
} }
buttons_prev = buttons; buttons_prev = buttons;
if (rawhid1) { if (rawhid1) {
int ch; int ch;
uint8_t buffer[64]; uint8_t buffer[64];
uint8_t count_chars = 0;
uint8_t count_chars = 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
if (Serial.available()) { if (Serial.available()) {
while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) { while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) {
//Serial.print((char)keyboard2.getKey()); //Serial.print((char)keyboard2.getKey());
//Serial.println(); //Serial.println();
} }
void OnHIDExtrasPress(uint32_t top, uint16_t key)
void OnHIDExtrasPress(uint32_t top, uint16_t key)
{ {
Serial.print("HID ("); Serial.print("HID (");
Serial.print(top, HEX); Serial.print(top, HEX);
Serial.println(); Serial.println();
} }


void OnHIDExtrasRelease(uint32_t top, uint16_t key)
void OnHIDExtrasRelease(uint32_t top, uint16_t key)
{ {
Serial.print("HID ("); Serial.print("HID (");
Serial.print(top, HEX); Serial.print(top, HEX);


bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) { bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) {
// Called for maybe both HIDS for rawhid basic test. One is for the Teensy // Called for maybe both HIDS for rawhid basic test. One is for the Teensy
// to output to Serial. while still having Raw Hid...
// to output to Serial. while still having Raw Hid...
if (usage == 0xffc90004) { if (usage == 0xffc90004) {
// Lets trim off trailing null characters. // Lets trim off trailing null characters.
while ((len > 0) && (data[len-1] == 0)) {
while ((len > 0) && (data[len - 1] == 0)) {
len--; len--;
} }
if (len) { if (len) {
Serial.print("RawHID data: "); Serial.print("RawHID data: ");
Serial.println(usage, HEX); Serial.println(usage, HEX);
while (len) { while (len) {
uint8_t cb = (len > 16)? 16 : len;
uint8_t cb = (len > 16) ? 16 : len;
const uint8_t *p = data; const uint8_t *p = data;
uint8_t i; uint8_t i;
for (i = 0; i < cb; i++) { for (i = 0; i < cb; i++) {
} }
Serial.print(": "); Serial.print(": ");
for (i = 0; i < cb; i++) { for (i = 0; i < cb; i++) {
Serial.write(((*data >= ' ')&&(*data <= '~'))? *data : '.');
Serial.write(((*data >= ' ') && (*data <= '~')) ? *data : '.');
data++; data++;
} }
len -= cb; len -= cb;
} }


return true; return true;
}
}

+ 90
- 4
keyboard.cpp Ver arquivo

uint8_t charNumlockOn; // We will assume when num lock is on we have all characters... uint8_t charNumlockOn; // We will assume when num lock is on we have all characters...
} keycode_numlock_t; } keycode_numlock_t;


typedef struct {
uint16_t idVendor; // vendor id of keyboard
uint16_t idProduct; // product id - 0 implies all of the ones from vendor;
} keyboard_force_boot_protocol_t; // list of products to force into boot protocol

#ifdef M #ifdef M
#undef M #undef M
#endif #endif
#define M(n) ((n) & KEYCODE_MASK) #define M(n) ((n) & KEYCODE_MASK)


keycode_extra_t keycode_extras[] = {
static const keycode_extra_t keycode_extras[] = {
{M(KEY_ENTER), '\n'}, {M(KEY_ENTER), '\n'},
{M(KEY_ESC), 0x1b}, {M(KEY_ESC), 0x1b},
{M(KEY_TAB), 0x9 }, {M(KEY_TAB), 0x9 },
}; };


// Some of these mapped to key + shift. // Some of these mapped to key + shift.
keycode_numlock_t keycode_numlock[] = {
static const keycode_numlock_t keycode_numlock[] = {
{M(KEYPAD_SLASH), '/', '/'}, {M(KEYPAD_SLASH), '/', '/'},
{M(KEYPAD_ASTERIX), '*', '*'}, {M(KEYPAD_ASTERIX), '*', '*'},
{M(KEYPAD_MINUS), '-', '-'}, {M(KEYPAD_MINUS), '-', '-'},
{M(KEYPAD_PERIOD), 0x80 | M(KEY_DELETE), '.'} {M(KEYPAD_PERIOD), 0x80 | M(KEY_DELETE), '.'}
}; };


static const keyboard_force_boot_protocol_t keyboard_forceBootMode[] = {
{0x04D9, 0}
};


#define print USBHost::print_ #define print USBHost::print_
#define println USBHost::println_ #define println USBHost::println_


contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
driver_ready_for_device(this); driver_ready_for_device(this);
USBHIDParser::driver_ready_for_hid_collection(this); USBHIDParser::driver_ready_for_hid_collection(this);
force_boot_protocol = false; // start off assuming not
} }


bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
// only claim at interface level // only claim at interface level
if (type != 1) return false; if (type != 1) return false;
if (len < 9+9+7) return false; if (len < 9+9+7) return false;
print_hexbytes(descriptors, len);


uint32_t numendpoint = descriptors[4]; uint32_t numendpoint = descriptors[4];
if (numendpoint < 1) return false; if (numendpoint < 1) return false;
datapipe->callback_function = callback; datapipe->callback_function = callback;
queue_Data_Transfer(datapipe, report, 8, this); queue_Data_Transfer(datapipe, report, 8, this);


mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT
// see if this device in list of devices that need to be set in
// boot protocol mode
bool in_forceBoot_mode_list = false;
for (uint8_t i = 0; i < sizeof(keyboard_forceBootMode)/sizeof(keyboard_forceBootMode[0]); i++) {
if (dev->idVendor == keyboard_forceBootMode[i].idVendor) {
if ((dev->idProduct == keyboard_forceBootMode[i].idProduct) ||
(keyboard_forceBootMode[i].idProduct == 0)) {
in_forceBoot_mode_list = true;
break;
}
}
}
if (in_forceBoot_mode_list) {
println("SET_PROTOCOL Boot");
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT
} else {
mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE
}
queue_Control_Transfer(dev, &setup, NULL, this); queue_Control_Transfer(dev, &setup, NULL, this);
control_queued = true;
return true; return true;
} }


void KeyboardController::control(const Transfer_t *transfer) void KeyboardController::control(const Transfer_t *transfer)
{ {
println("control callback (keyboard)"); println("control callback (keyboard)");
control_queued = false;
print_hexbytes(transfer->buffer, transfer->length); print_hexbytes(transfer->buffer, transfer->length);
// To decode hex dump to human readable HID report summary: // To decode hex dump to human readable HID report summary:
// http://eleccelerator.com/usbdescreqparser/ // http://eleccelerator.com/usbdescreqparser/
uint32_t mesg = transfer->setup.word1; uint32_t mesg = transfer->setup.word1;
println(" mesg = ", mesg, HEX); println(" mesg = ", mesg, HEX);
if (mesg == 0x001021 && transfer->length == 0) { // SET_PROTOCOL
if (mesg == 0x00B21 && transfer->length == 0) { // SET_PROTOCOL
mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE
control_queued = true;
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
} else if (force_boot_protocol) {
forceBootProtocol(); // lets setup to do the boot protocol
force_boot_protocol = false; // turn back off
} }
} }


} }
} }


void KeyboardController::forceBootProtocol()
{
if (device && !control_queued) {
mk_setup(setup, 0x21, 11, 0, 0, 0); // 11=SET_PROTOCOL BOOT
control_queued = true;
queue_Control_Transfer(device, &setup, NULL, this);
} else {
force_boot_protocol = true; // let system know we want to force this.
}
}

void KeyboardController::disconnect() void KeyboardController::disconnect()
{ {
// TODO: free resources // TODO: free resources
hid_input_begin_ = false; hid_input_begin_ = false;
} }
} }

//*****************************************************************************
// Some simple query functions depend on which interface we are using...
//*****************************************************************************

uint16_t KeyboardController::idVendor()
{
if (device != nullptr) return device->idVendor;
if (mydevice != nullptr) return mydevice->idVendor;
return 0;
}

uint16_t KeyboardController::idProduct()
{
if (device != nullptr) return device->idProduct;
if (mydevice != nullptr) return mydevice->idProduct;
return 0;
}

const uint8_t *KeyboardController::manufacturer()
{
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
return nullptr;
}

const uint8_t *KeyboardController::product()
{
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
return nullptr;
}

const uint8_t *KeyboardController::serialNumber()
{
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
return nullptr;
}


+ 1
- 0
keywords.txt Ver arquivo

numLock KEYWORD2 numLock KEYWORD2
capsLock KEYWORD2 capsLock KEYWORD2
scrollLock KEYWORD2 scrollLock KEYWORD2
forceBootProtocol KEYWORD2


# MIDIDevice # MIDIDevice
getType KEYWORD2 getType KEYWORD2

Carregando…
Cancelar
Salvar