USB keyboard hardware proxy

Hooman

Member
What I want to build: a device into which I can plug in my keyboard and that will look like a USB keyboard if I plug it into a USB host of any kind that accepts a keyboard. The idea is for it to be all in hardware, such that no driver software is needed on the host. By default it'd proxy all key presses/releases, but of course I want to do some interesting things, like record, replay, maybe swap keyboard maps, etc. I'll want a few buttons on this gizmo. And optionally maybe have a small LCD display to echo key sequences (with an assumed keyboard layout).

So obviously, I need to implement a USB host and a USB HID device. Even if this were feasible in an Arduino, the ATMega328's 2k of RAM seem a bit tight for the recording ability I'm interested in.

Is the Teensy (3.2) an adequate Microcontroller for this?

And what else will I need? I came across a page explaining how it can be paired with the Arduino USB host shield. Is the shield necessary, or can the Teensy (with whatever other needed hardware, e.g. USB-A jack and pulldown resistors) be programmed to handle this directly? As for the USB device interface, should I use the micro-USB port on the Teensy card for it, or add a new one?

Reading up on it, I realized that the trickiest thing for a USB device will be power management, and properly reporting needs to the USB host. Also, the page explaining the USB host shield points out that the power demand when plugging in the keyboard will cause the Teensy to reboot if I don't put a capacitor there. But if the device is plugged in to the computer before to the keyboard is plugged in to the device, it won't be able to properly estimate maximum power demand to the host, so I'm thinking maybe that reboot is a good thing, and then presumably the computer will see us as a new device and request power needs anew, which we should be able to report? Incidentally, what are the power needs of the Teensy card itself?

Note: I have no direct experience with Microcontroller programing, this would be my first such project. But I have some digital design experience (PALs, CPLDs, with VHDL) from back in the day, know the basics of how keyboards and keyboard drivers work (scan codes, clear codes, etc.), and I'm fluent in C.

Thanks in advance for your insights!
 
The Teensy 3.6 has two USB Ports, one is a HOST and you can connect a keyboard. The other can be programmed to act as a keyboard easyly. So, in short: Yes, possible. Of course, you have to write your software to program the Teensy 3.6
 
The Teensy 3.6 has two USB Ports, one is a HOST and you can connect a keyboard. The other can be programmed to act as a keyboard easyly. So, in short: Yes, possible. Of course, you have to write your software to program the Teensy 3.6

Thanks for the info. Fair enough, but at that price, a Raspberry Pi would also do the trick, wouldn't it?...
Perhaps a bit more power-hungry, though.
 
I think he wants to make a logger, where teensy takes a physically keyboard plugged into it, and teensy plugged to PC. Teensy would then pass-through all keystrokes while logging them to.. uSD?
 
Maybe wants a hardware keyboard macro device for games that monitor for software macros. (I've heard they do this but could be rubbish).
 
@gibbedy - many moons ago tried to use a Leonardo variant to play a game that required complex 4-8 button combos and got detected - looks like it recorded the timings and started dropping the tail of combos if the timing was too close to perfect.

Dithering the timing might have helped but didn't care enough at the time to try that just to finish a game I was terrible at.
 
Heh, yeah, I've heard of macro-detection, but rest assured: my macros are for comms only. I want this mainly for an Xbox, and it only allows keyboard use for messages. I want macros to quickly send message for mic-less comms. E.g. "Hi Cmdr, this is a hold-up. Kindly kill your speed and leave hardpoints closed for a quick scan. I will merely ask for a modest amount of your cargo, and if you comply, you will be on your way unharmed." If I have to manually type something like that, the victim will be long since gone.

Now, if you wanted to make game macros on an xbox, I wonder if one could intercept a wired controller? And I suspect some randomness for the interval between keystrokes would be enough to evade detection - is that what you mean by dithering? But, not relevant to me.
 
Taking a look at the Teensy 3.6, it does seem to be the right controller for the job.

But what about the power management issues? How would you approach the various initialization scenarios I outlined above? (device plugged in first, then keyboard into device, or the other way around) How about suspend mode? Keepalive? Turning the LCD on/off? How would the controller measure its own power usage? (Does it need to?) Some trick with a pull-up resistor or pull-down resistor to an analog input? I haven't really thought it through...
 
teensy doesnt need a keyboard, it can act as one standalone, you can use a button on gpio to fire your message to the console
 
teensy doesnt need a keyboard, it can act as one standalone, you can use a button on gpio to fire your message to the console

Right, but that's rather limited, I have something more elaborate in mind. That message was just one example usage. I want to record several strings, be able to edit them, etc. For one, I don't want to limit myself to 2kB of RAM. I want a polished-looking product in the end, several buttons to select functions. The keyboard will still be needed, this is still only a proxy. If I wanted to have a standalone macro keypad, that exists already commercially, and is easier to DIY.

What I want to make is similar to this: https://making.arantius.com/remapcro, but not quite; in some ways more, in other ways, simpler. Don't really want to go into details as I haven't nailed them down and would prefer to share when I have a finished product or something close to it.

As for the voice recognition idea... I know you probably meant that tongue-in-cheek, but... hmm.
 
yeah thats a good idea, you can use macro keys to add phrases without reprogramming teensy, theyd be stored on uSD. would be nice to have a little lcd to touch the ones you dont want, to delete them, or a touch to add a new one :)
 
So, working through the USBHost_t36 library, I'm trying to figure out the simplest way to implement my proxy. I will record keys using attachPress() and attachRelease(), easy enough. But I would also like to forward all keyboard reports messages seamlessly from the host to the device. I'm looking at changing the library directly, at least just to make KeyboardController::new_data() virtual, so I can override it. Can't really think of an easier way... can anyone else?
 
Last edited:
A simple example of a USB keyboard pass through. I verified it works on a Xbox One.

Code:
// derived from "mouse" example of USBHost_t36 library
// simple relaying of keystrokes between a keyboard connected to the
// usb host port of a teensy 3.6 and the output of the teensy
// acting as a usb keyboard

/*
  The Teensy 3.6 has a USB host port as well as the usual USB device port
  so it can act as a USB pass through or proxy device.

  The pull request below (not mine) allows a sketch to receive the
  USB keyboard HID report when it arrives from the USB host port.
  This version does not require changes to Keyboard.

  Latest usbhost_t36 from git
  https://github.com/PaulStoffregen/USBHost_t36

  with this pull request applied
  https://github.com/PaulStoffregen/USBHost_t36/pull/18

  Hardware
    Teensy 3.6 board
    https://www.pjrc.com/store/teensy36.html
    Teensy 3.6 USB host cable
    https://www.pjrc.com/store/cable_usb_host_t36.html
*/

#include "USBHost_t36.h"  // to host a usb keyboard
#include "Keyboard.h"     // to act as a usb keyboard device

USBHost myusb;
KeyboardController keyboard_in(myusb);

/*
  Key remap possiblities
    Swap LeftCtrl and CapsLock. Put CapsLock in the corner where it belongs!
    Switchable QWERTY, Dvorak, and colemak keyboard layouts
    Hardware key macros
    Remappings and macros that work even in BIOS and recovery mode.
    Remappings and macros that work with KVMs and game consoles.
*/
void reportReader(const uint8_t report[8])
{
  Keyboard.set_modifier(report[0]);
  Keyboard.set_key1(report[2]);
  Keyboard.set_key2(report[3]);
  Keyboard.set_key3(report[4]);
  Keyboard.set_key4(report[5]);
  Keyboard.set_key5(report[6]);
  Keyboard.set_key6(report[7]);
  Keyboard.send_now();
}

void setup()
{
  myusb.begin();
  keyboard_in.attachReportReader(reportReader);
}

void loop() {
  myusb.Task();
}
 
as the media keys are only supported on Linux/Mac anyways :(

Teensy's USB Keyboard (USB device mode) added support for media keys on Windows with Teensyduino 1.29.

Earlier versions only worked with Macintosh and Linux. Those early versions also only supported 8 media keys (and the way it was implemented was limited to exactly 8 keys), rather than the current 14 media keys plus 3 extra system control keys. The early versions also required a special API for media keys, rather than using Keyboard.press() and Keyboard.release() as modern versions do.
 
Teensy's USB Keyboard (USB device mode) added support for media keys on Windows with Teensyduino 1.29.

Earlier versions only worked with Macintosh and Linux. Those early versions also only supported 8 media keys (and the way it was implemented was limited to exactly 8 keys), rather than the current 14 media keys plus 3 extra system control keys. The early versions also required a special API for media keys, rather than using Keyboard.press() and Keyboard.release() as modern versions do.

I see, might be the docs are outdated (on pjrc website).
I don't see any option to read Media Keys in the USB Host, any idea?
 
Last edited:
Have you tried running the USB Host example sketches? Like the mouse.ino?
I know there should be one specific for keyboard...

Code:
  keyboard1.attachPress(OnPress);
  keyboard1.attachExtrasPress(OnHIDExtrasPress);
  keyboard1.attachExtrasRelease(OnHIDExtrasRelease);
You can see if it looks like the Extras catches the ones you might be interested in:
The Example app tries to print out which one:
Code:
void OnHIDExtrasPress(uint32_t top, uint16_t key)
{
  Serial.print("HID (");
  Serial.print(top, HEX);
  Serial.print(") key press:");
  Serial.print(key, HEX);
  if (top == 0xc0000) {
    switch (key) {
      case  0x20 : Serial.print(" - +10"); break;
      case  0x21 : Serial.print(" - +100"); break;
      case  0x22 : Serial.print(" - AM/PM"); break;
      case  0x30 : Serial.print(" - Power"); break;
      case  0x31 : Serial.print(" - Reset"); break;
      case  0x32 : Serial.print(" - Sleep"); break;
      case  0x33 : Serial.print(" - Sleep After"); break;
      case  0x34 : Serial.print(" - Sleep Mode"); break;
      case  0x35 : Serial.print(" - Illumination"); break;
      case  0x36 : Serial.print(" - Function Buttons"); break;
      case  0x40 : Serial.print(" - Menu"); break;
      case  0x41 : Serial.print(" - Menu  Pick"); break;
      case  0x42 : Serial.print(" - Menu Up"); break;
      case  0x43 : Serial.print(" - Menu Down"); break;
      case  0x44 : Serial.print(" - Menu Left"); break;
      case  0x45 : Serial.print(" - Menu Right"); break;
      case  0x46 : Serial.print(" - Menu Escape"); break;
      case  0x47 : Serial.print(" - Menu Value Increase"); break;
      case  0x48 : Serial.print(" - Menu Value Decrease"); break;
      case  0x60 : Serial.print(" - Data On Screen"); break;
      case  0x61 : Serial.print(" - Closed Caption"); break;
      case  0x62 : Serial.print(" - Closed Caption Select"); break;
      case  0x63 : Serial.print(" - VCR/TV"); break;
      case  0x64 : Serial.print(" - Broadcast Mode"); break;
      case  0x65 : Serial.print(" - Snapshot"); break;
      case  0x66 : Serial.print(" - Still"); break;
      case  0x80 : Serial.print(" - Selection"); break;
      case  0x81 : Serial.print(" - Assign Selection"); break;
      case  0x82 : Serial.print(" - Mode Step"); break;
      case  0x83 : Serial.print(" - Recall Last"); break;
      case  0x84 : Serial.print(" - Enter Channel"); break;
      case  0x85 : Serial.print(" - Order Movie"); break;
      case  0x86 : Serial.print(" - Channel"); break;
      case  0x87 : Serial.print(" - Media Selection"); break;
      case  0x88 : Serial.print(" - Media Select Computer"); break;
      case  0x89 : Serial.print(" - Media Select TV"); break;
      case  0x8A : Serial.print(" - Media Select WWW"); break;
      case  0x8B : Serial.print(" - Media Select DVD"); break;
      case  0x8C : Serial.print(" - Media Select Telephone"); break;
      case  0x8D : Serial.print(" - Media Select Program Guide"); break;
      case  0x8E : Serial.print(" - Media Select Video Phone"); break;
      case  0x8F : Serial.print(" - Media Select Games"); break;
      case  0x90 : Serial.print(" - Media Select Messages"); break;
      case  0x91 : Serial.print(" - Media Select CD"); break;
      case  0x92 : Serial.print(" - Media Select VCR"); break;
      case  0x93 : Serial.print(" - Media Select Tuner"); break;
      case  0x94 : Serial.print(" - Quit"); break;
      case  0x95 : Serial.print(" - Help"); break;
      case  0x96 : Serial.print(" - Media Select Tape"); break;
      case  0x97 : Serial.print(" - Media Select Cable"); break;
      case  0x98 : Serial.print(" - Media Select Satellite"); break;
      case  0x99 : Serial.print(" - Media Select Security"); break;
      case  0x9A : Serial.print(" - Media Select Home"); break;
      case  0x9B : Serial.print(" - Media Select Call"); break;
      case  0x9C : Serial.print(" - Channel Increment"); break;
      case  0x9D : Serial.print(" - Channel Decrement"); break;
      case  0x9E : Serial.print(" - Media Select SAP"); break;
      case  0xA0 : Serial.print(" - VCR Plus"); break;
      case  0xA1 : Serial.print(" - Once"); break;
      case  0xA2 : Serial.print(" - Daily"); break;
      case  0xA3 : Serial.print(" - Weekly"); break;
      case  0xA4 : Serial.print(" - Monthly"); break;
      case  0xB0 : Serial.print(" - Play"); break;
      case  0xB1 : Serial.print(" - Pause"); break;
      case  0xB2 : Serial.print(" - Record"); break;
      case  0xB3 : Serial.print(" - Fast Forward"); break;
      case  0xB4 : Serial.print(" - Rewind"); break;
      case  0xB5 : Serial.print(" - Scan Next Track"); break;
      case  0xB6 : Serial.print(" - Scan Previous Track"); break;
      case  0xB7 : Serial.print(" - Stop"); break;
      case  0xB8 : Serial.print(" - Eject"); break;
      case  0xB9 : Serial.print(" - Random Play"); break;
      case  0xBA : Serial.print(" - Select DisC"); break;
      case  0xBB : Serial.print(" - Enter Disc"); break;
      case  0xBC : Serial.print(" - Repeat"); break;
      case  0xBD : Serial.print(" - Tracking"); break;
      case  0xBE : Serial.print(" - Track Normal"); break;
      case  0xBF : Serial.print(" - Slow Tracking"); break;
      case  0xC0 : Serial.print(" - Frame Forward"); break;
      case  0xC1 : Serial.print(" - Frame Back"); break;
      case  0xC2 : Serial.print(" - Mark"); break;
      case  0xC3 : Serial.print(" - Clear Mark"); break;
      case  0xC4 : Serial.print(" - Repeat From Mark"); break;
      case  0xC5 : Serial.print(" - Return To Mark"); break;
      case  0xC6 : Serial.print(" - Search Mark Forward"); break;
      case  0xC7 : Serial.print(" - Search Mark Backwards"); break;
      case  0xC8 : Serial.print(" - Counter Reset"); break;
      case  0xC9 : Serial.print(" - Show Counter"); break;
      case  0xCA : Serial.print(" - Tracking Increment"); break;
      case  0xCB : Serial.print(" - Tracking Decrement"); break;
      case  0xCD : Serial.print(" - Pause/Continue"); break;
      case  0xE0 : Serial.print(" - Volume"); break;
      case  0xE1 : Serial.print(" - Balance"); break;
      case  0xE2 : Serial.print(" - Mute"); break;
      case  0xE3 : Serial.print(" - Bass"); break;
      case  0xE4 : Serial.print(" - Treble"); break;
      case  0xE5 : Serial.print(" - Bass Boost"); break;
      case  0xE6 : Serial.print(" - Surround Mode"); break;
      case  0xE7 : Serial.print(" - Loudness"); break;
      case  0xE8 : Serial.print(" - MPX"); break;
      case  0xE9 : Serial.print(" - Volume Up"); break;
      case  0xEA : Serial.print(" - Volume Down"); break;
      case  0xF0 : Serial.print(" - Speed Select"); break;
      case  0xF1 : Serial.print(" - Playback Speed"); break;
      case  0xF2 : Serial.print(" - Standard Play"); break;
      case  0xF3 : Serial.print(" - Long Play"); break;
      case  0xF4 : Serial.print(" - Extended Play"); break;
      case  0xF5 : Serial.print(" - Slow"); break;
      case  0x100: Serial.print(" - Fan Enable"); break;
      case  0x101: Serial.print(" - Fan Speed"); break;
      case  0x102: Serial.print(" - Light"); break;
      case  0x103: Serial.print(" - Light Illumination Level"); break;
      case  0x104: Serial.print(" - Climate Control Enable"); break;
      case  0x105: Serial.print(" - Room Temperature"); break;
      case  0x106: Serial.print(" - Security Enable"); break;
      case  0x107: Serial.print(" - Fire Alarm"); break;
      case  0x108: Serial.print(" - Police Alarm"); break;
      case  0x150: Serial.print(" - Balance Right"); break;
      case  0x151: Serial.print(" - Balance Left"); break;
      case  0x152: Serial.print(" - Bass Increment"); break;
      case  0x153: Serial.print(" - Bass Decrement"); break;
      case  0x154: Serial.print(" - Treble Increment"); break;
      case  0x155: Serial.print(" - Treble Decrement"); break;
      case  0x160: Serial.print(" - Speaker System"); break;
      case  0x161: Serial.print(" - Channel Left"); break;
      case  0x162: Serial.print(" - Channel Right"); break;
      case  0x163: Serial.print(" - Channel Center"); break;
      case  0x164: Serial.print(" - Channel Front"); break;
      case  0x165: Serial.print(" - Channel Center Front"); break;
      case  0x166: Serial.print(" - Channel Side"); break;
      case  0x167: Serial.print(" - Channel Surround"); break;
      case  0x168: Serial.print(" - Channel Low Frequency Enhancement"); break;
      case  0x169: Serial.print(" - Channel Top"); break;
      case  0x16A: Serial.print(" - Channel Unknown"); break;
      case  0x170: Serial.print(" - Sub-channel"); break;
      case  0x171: Serial.print(" - Sub-channel Increment"); break;
      case  0x172: Serial.print(" - Sub-channel Decrement"); break;
      case  0x173: Serial.print(" - Alternate Audio Increment"); break;
      case  0x174: Serial.print(" - Alternate Audio Decrement"); break;
      case  0x180: Serial.print(" - Application Launch Buttons"); break;
      case  0x181: Serial.print(" - AL Launch Button Configuration Tool"); break;
      case  0x182: Serial.print(" - AL Programmable Button Configuration"); break;
      case  0x183: Serial.print(" - AL Consumer Control Configuration"); break;
      case  0x184: Serial.print(" - AL Word Processor"); break;
      case  0x185: Serial.print(" - AL Text Editor"); break;
      case  0x186: Serial.print(" - AL Spreadsheet"); break;
      case  0x187: Serial.print(" - AL Graphics Editor"); break;
      case  0x188: Serial.print(" - AL Presentation App"); break;
      case  0x189: Serial.print(" - AL Database App"); break;
      case  0x18A: Serial.print(" - AL Email Reader"); break;
      case  0x18B: Serial.print(" - AL Newsreader"); break;
      case  0x18C: Serial.print(" - AL Voicemail"); break;
      case  0x18D: Serial.print(" - AL Contacts/Address Book"); break;
      case  0x18E: Serial.print(" - AL Calendar/Schedule"); break;
      case  0x18F: Serial.print(" - AL Task/Project Manager"); break;
      case  0x190: Serial.print(" - AL Log/Journal/Timecard"); break;
      case  0x191: Serial.print(" - AL Checkbook/Finance"); break;
      case  0x192: Serial.print(" - AL Calculator"); break;
      case  0x193: Serial.print(" - AL A/V Capture/Playback"); break;
      case  0x194: Serial.print(" - AL Local Machine Browser"); break;
      case  0x195: Serial.print(" - AL LAN/WAN Browser"); break;
      case  0x196: Serial.print(" - AL Internet Browser"); break;
      case  0x197: Serial.print(" - AL Remote Networking/ISP Connect"); break;
      case  0x198: Serial.print(" - AL Network Conference"); break;
      case  0x199: Serial.print(" - AL Network Chat"); break;
      case  0x19A: Serial.print(" - AL Telephony/Dialer"); break;
      case  0x19B: Serial.print(" - AL Logon"); break;
      case  0x19C: Serial.print(" - AL Logoff"); break;
      case  0x19D: Serial.print(" - AL Logon/Logoff"); break;
      case  0x19E: Serial.print(" - AL Terminal Lock/Screensaver"); break;
      case  0x19F: Serial.print(" - AL Control Panel"); break;
      case  0x1A0: Serial.print(" - AL Command Line Processor/Run"); break;
      case  0x1A1: Serial.print(" - AL Process/Task Manager"); break;
      case  0x1A2: Serial.print(" - AL Select Tast/Application"); break;
      case  0x1A3: Serial.print(" - AL Next Task/Application"); break;
      case  0x1A4: Serial.print(" - AL Previous Task/Application"); break;
      case  0x1A5: Serial.print(" - AL Preemptive Halt Task/Application"); break;
      case  0x200: Serial.print(" - Generic GUI Application Controls"); break;
      case  0x201: Serial.print(" - AC New"); break;
      case  0x202: Serial.print(" - AC Open"); break;
      case  0x203: Serial.print(" - AC Close"); break;
      case  0x204: Serial.print(" - AC Exit"); break;
      case  0x205: Serial.print(" - AC Maximize"); break;
      case  0x206: Serial.print(" - AC Minimize"); break;
      case  0x207: Serial.print(" - AC Save"); break;
      case  0x208: Serial.print(" - AC Print"); break;
      case  0x209: Serial.print(" - AC Properties"); break;
      case  0x21A: Serial.print(" - AC Undo"); break;
      case  0x21B: Serial.print(" - AC Copy"); break;
      case  0x21C: Serial.print(" - AC Cut"); break;
      case  0x21D: Serial.print(" - AC Paste"); break;
      case  0x21E: Serial.print(" - AC Select All"); break;
      case  0x21F: Serial.print(" - AC Find"); break;
      case  0x220: Serial.print(" - AC Find and Replace"); break;
      case  0x221: Serial.print(" - AC Search"); break;
      case  0x222: Serial.print(" - AC Go To"); break;
      case  0x223: Serial.print(" - AC Home"); break;
      case  0x224: Serial.print(" - AC Back"); break;
      case  0x225: Serial.print(" - AC Forward"); break;
      case  0x226: Serial.print(" - AC Stop"); break;
      case  0x227: Serial.print(" - AC Refresh"); break;
      case  0x228: Serial.print(" - AC Previous Link"); break;
      case  0x229: Serial.print(" - AC Next Link"); break;
      case  0x22A: Serial.print(" - AC Bookmarks"); break;
      case  0x22B: Serial.print(" - AC History"); break;
      case  0x22C: Serial.print(" - AC Subscriptions"); break;
      case  0x22D: Serial.print(" - AC Zoom In"); break;
      case  0x22E: Serial.print(" - AC Zoom Out"); break;
      case  0x22F: Serial.print(" - AC Zoom"); break;
      case  0x230: Serial.print(" - AC Full Screen View"); break;
      case  0x231: Serial.print(" - AC Normal View"); break;
      case  0x232: Serial.print(" - AC View Toggle"); break;
      case  0x233: Serial.print(" - AC Scroll Up"); break;
      case  0x234: Serial.print(" - AC Scroll Down"); break;
      case  0x235: Serial.print(" - AC Scroll"); break;
      case  0x236: Serial.print(" - AC Pan Left"); break;
      case  0x237: Serial.print(" - AC Pan Right"); break;
      case  0x238: Serial.print(" - AC Pan"); break;
      case  0x239: Serial.print(" - AC New Window"); break;
      case  0x23A: Serial.print(" - AC Tile Horizontally"); break;
      case  0x23B: Serial.print(" - AC Tile Vertically"); break;
      case  0x23C: Serial.print(" - AC Format"); break;
I know when I tested it I did see most/all of the extras on my old Dell multimedia keyboard.
 
Well, yes they appear, but I am not able to pass them through.
Using default "Serial + Keyboard + Mouse + Joystick"

Code:
keyboard_in.attachExtrasPress(OnHIDExtrasPress);
keyboard_in.attachExtrasRelease(OnHIDExtrasRelease);

void OnHIDExtrasPress(uint32_t top, uint16_t key)
{
  if (top == 0xc0000) {
    Keyboard.set_media(key);
    Keyboard.send_now();
  }
}

void OnHIDExtrasRelease(uint32_t top, uint16_t key)
{
  Keyboard.release(key);
  Keyboard.send_now();
}

Edit: Also what is report[1] for? Since its not been used in the example above.
Edit 2: Also its kinda confusing, why is 0xE9 Volume Up, but here its 0xed.
 
Last edited:
Again Sorry, I am more up on the Host side and less on the send to the pc side...

I am pretty sure you will need to do a little mapping of the addresses before you pass it along...

That is:
The function you have:
Code:
void OnHIDExtrasPress(uint32_t top, uint16_t key)
{
  if (top == 0xc0000) {
    Keyboard.set_media(key);
    Keyboard.send_now();
  }
}
Is simply passing the usage ID within page 12(Consumer page) of HID ... tot he set_media call...


But looking into the keyboard.h
Code:
#ifdef KEYMEDIA_INTERFACE
	void set_media(uint16_t c) {
		if (c == 0) {
			usb_keymedia_release_all();
		} else if (c >= 0xE400 && c <= 0xE7FF) {
			press(c);
		}
	}
#endif
	void send_now(void) { usb_keyboard_send(); }
	void press(uint16_t n) { usb_keyboard_press_keycode(n); }


And usb_keyboard.c code I see:
Code:
// Input can be:
//     32 - 127     ASCII direct (U+0020 to U+007F) <-- uses layout
//    128 - 0xC1FF  Unicode direct (U+0080 to U+C1FF) <-- uses layout
// 0xC200 - 0xDFFF  Unicode UTF8 packed (U+0080 to U+07FF) <-- uses layout
// 0xE000 - 0xE0FF  Modifier key (bitmap, 8 keys, shift/ctrl/alt/gui)
// 0xE200 - 0xE2FF  System key (HID usage code, within usage page 1)
[COLOR="#FF0000"]// 0xE400 - 0xE7FF  Media/Consumer key (HID usage code, within usage page 12)[/COLOR]
// 0xF000 - 0xFFFF  Normal key (HID usage code, within usage page 7)

void usb_keyboard_press_keycode(uint16_t n)


Sot it looks like it wants it within that range. 0xE400-0xE7ff...
So if it were me, I might try:
Code:
void OnHIDExtrasPress(uint32_t top, uint16_t key)
{
  if (top == 0xc0000) {
    Keyboard.set_media(0xE400 + key);
  }
}
And see what it does.
 
Back
Top