USBHost_t36 library: keyboard modifier keys

Status
Not open for further replies.

distributed

New member
I have a Teensy 3.6 with a USB host header installed and a keyboard plugged into it, and have been playing around with the USBHost_t36 library examples and can receive key presses from the keyboard.
What I am having trouble with is to figure out which of the modifier keys was set on key press and release.

Some help with figuring out which of the ctrl,shift,alt,gui keys was pressed would be really appreciated!

Below I have listed the output I receive over the serial and the key combination I pressed on the keyboard attached:
I am assuming that something in the 4 byte code received will have the information I want.

Code:
// I pressed and released: p
onPress>> sz(4) 112 0x70 'p' 1110000
onRelease>> sz(4) 112 0x70 p
// I pressed and released: shift+p
onPress>> sz(4) 80 0x50 'P' 1010000
onRelease>> sz(4) 80 0x50 P
// I pressed and released: ctrl+p
onPress>> sz(4) 16 0x10 '' 10000
onRelease>> sz(4) 16 0x10 
// I pressed and released: alt+p
onPress>> sz(4) 112 0x70 'p' 1110000
onRelease>> sz(4) 112 0x70 p

// and now the same sequence with "s"

onPress>> sz(4) 115 0x73 's' 1110011
onRelease>> sz(4) 115 0x73 s

onPress>> sz(4) 83 0x53 'S' 1010011
onRelease>> sz(4) 83 0x53 S

onPress>> sz(4) 19 0x13 '' 10011
onRelease>> sz(4) 19 0x13 

onPress>> sz(4) 115 0x73 's' 1110011
onRelease>> sz(4) 115 0x73 s

Relevant excerpt from my code is listed below:

Code:
USBHost myusb;
KeyboardController keyboard1(myusb);

void setup()
{
  while (!Serial) ; // wait for Arduino Serial Monitor
  myusb.begin();
  keyboard1.attachPress(OnPress);
  keyboard1.attachRelease(OnRelease);
}

void OnPress(auto key)
{
  char buff[128] = {0};
  char poof[64] = {0};
  long lk = key;
  ltoa( lk, poof, 2);
  snprintf(buff, 127, "onPress>> sz(%u) %u 0x%x '%c' %s\n", sizeof(key), key, key, key, poof);
  Serial.print(buff);
}

void OnRelease(int key)
{
  char buff[128] = {0};
  snprintf(buff, 127, "onRelease>> sz(%u) %u 0x%x %c\n", sizeof(key), key, key, key);
  Serial.print(buff);
}

Once I figure this out I would like to help update the USBHost_t36 library examples to include this case.
I have been able to get most of the other stuff on T3.6 that I wanted working (RTC, uSD card, etc.) and this is the only thing I am stuck with now :-(
Thanks!
 
After googling around for a bit I located the github repository for the library header file:
https://github.com/PaulStoffregen/USBHost_t36/blob/master/USBHost_t36.h

And it seems that the attach functions are expected to receive a unicode value, and there is a private function to convert from key+modifier combo to unicode.

Code:
	void     attachPress(void (*f)(int unicode)) { keyPressedFunction = f; }
	void     attachRelease(void (*f)(int unicode)) { keyReleasedFunction = f; }
...
private:
	void update();
	uint16_t convert_to_unicode(uint32_t mod, uint32_t key);
	void key_press(uint32_t mod, uint32_t key);
	void key_release(uint32_t mod, uint32_t key);

I am still not sure of how to make sense of the unicode values though.

Here is the full set of public methods, so maybe I should be using getModifiers() in my press and release callback methods?

Code:
public:
	KeyboardController(USBHost &host) { init(); }
	KeyboardController(USBHost *host) { init(); }

	// Some methods are in both public classes so we need to figure out which one to use
	operator bool() { return (device != nullptr); }
	// Main boot keyboard functions. 
	uint16_t getKey() { return keyCode; }
	uint8_t  getModifiers() { return modifiers; }
	uint8_t  getOemKey() { return keyOEM; }
	void     attachPress(void (*f)(int unicode)) { keyPressedFunction = f; }
	void     attachRelease(void (*f)(int unicode)) { keyReleasedFunction = f; }
	void     LEDS(uint8_t leds);
	uint8_t  LEDS() {return leds_.byte;}
	void     updateLEDS(void);
	bool     numLock() {return leds_.numLock;}
	bool     capsLock() {return leds_.capsLock;}
	bool     scrollLock() {return leds_.scrollLock;}
	void	 numLock(bool f);
	void     capsLock(bool f);
	void	 scrollLock(bool f);

	// Added for extras information.
	void     attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; }
	void     attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; }
	enum {MAX_KEYS_DOWN=4};
 
Yes if I remember correctly, it has been awhile since I worked on it.

Yes getModifiers returns the set of modifier keys that were pressed during the key... Probably should be a set of defines for which bit is which. But should not be hard to figure out. Just run the Mouse example program, when a key is pressed I believe it will print out which modifiers are pressed.

For US like keyboards the Unicode is the same as ASCII... That is only one byte is used. I don't have any other keyboards, so not sure how well that part works, but does use the standard Teensy tables to try to convert from the Keycodes to the actual value.

Note: The code tries to handle the SHIFT (also with combination of CAPS lock), The definition of the SHIFT stuff is in the main COres in the keylayouts.h file
Likewise I think it is handling the Ctrl keys get the values < than a space.

Looks like the Shift key is either 0x2 or 0x20 (left vs right shift)
Likewise CTRL key is either 0x1 or ox10 again left vs right
...
 
I confirmed that getModifiers() seems to return what I wanted and I was able to figure out what each bit stands for.
But I was still not sure of how to make sense of the unicode code returned to attachPress and attachRelease handlers.

After much searching, I came across the following document:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa299374(v=vs.60)

Which matches the unicode numbers I was seeing for some cases:
Code:
P : 112
shift+P : 80
ctrl+P : 16
alt+P : 25 (does not match)

Following lines are from my first comment on this thread with the output from the library:
Code:
// I pressed and released: p
onPress>> sz(4) 112 0x70 'p' 1110000
onRelease>> sz(4) 112 0x70 p
// I pressed and released: shift+p
onPress>> sz(4) 80 0x50 'P' 1010000
onRelease>> sz(4) 80 0x50 P
// I pressed and released: ctrl+p
onPress>> sz(4) 16 0x10 '' 10000
onRelease>> sz(4) 16 0x10 
// I pressed and released: alt+p
onPress>> sz(4) 112 0x70 'p' 1110000
onRelease>> sz(4) 112 0x70 p

I also came across the boot keyboard USB spec:
http://www.usb.org/developers/hidpage/HID1_11.pdf

With the following excerpt from Appendix B:

Code:
The following table represents the keyboard input report (8 bytes).
Byte Description
0 Modifier keys
1 Reserved
2 Keycode 1
3 Keycode 2
4 Keycode 3
5 Keycode 4
6 Keycode 5
7 Keycode 6
Byte 1 of this report is a constant. This byte is reserved for OEM use. The
BIOS should ignore this field if it is not used. Returning zeros in unused fields is
recommended.

Which matches the usb-keyboard emulation as described here:
https://www.pjrc.com/teensy/usb_keyboard.html

Does anyone know if it is possible to access all the fields in the usb keyboard input report using the USBHost_t36 library?
And why the library exposes a different kind of interface?

Thanks again!
 
Dear all,

I am not sure if I can ask my questions in this thread but I give it a try.

My Teensy 3.6 needs a USB keyboard for sending CW the keyboard works however there are a few pro see below.

1) No auto repeat
2) Very few control keys are mapped
3) No ALT keys are mapped
4) CTL-ALT-DEL is not mapped
5) Shift, ALT, CTL don't affect function keys
6) When caps lock the generated code = 0 instead 32

Is there a better library or is this easy to solve? now I use USBHost_t36-master

Thanks in advance.

Johan
 
I am not completely sure of your setup or the like and it has been awhile since I did much with the USBHost code and not sure what you mean by USB keyboard for sending CW...


But assuming what you wish to do is to receive Keyboard information from a keyboard that is plugged into the HOST port of a Teensy 3.6.
I assume you have tried running the example programs under this library? In particular mouse.ino? ...

With this with the default code, you will see

1) Yes - the code does not generate auto repeats. you get an event for when the key is pressed and when it is released. You can decide to put in yur own timer or the like to create if desired.
2) ? - yes mainly alpha keys by default do automatic mapping...
3) Alt keys mapped to what? If you are asking for ALT+1+3+2 will generate ä, nope not implemented.
4 ctrl+alt+delete: will give you the delete key, if you then ask for the modifiers it is 5 for the CTRL+ALT... So you can decide to do something with this if you like.
5) Function keys - again will give you the function key, but the call to getModifiers() will get you the current state of the ctrl, alt, and shift keys. Note: There are actually 2 shift modifiers (2=left shift, 0x20 is right shift), likewise for alt and ctrl. and likewise for Window keys.

6) Caps lock, num lock, scroll lock - yes give you - for key... You can look at the OEM value for these if desired.

Now if you need even more control over this, you can take over all of the translation. I believe FrankB's C64 code base does this. Don't remember if I have a copy of the code around here or not. Note: it is using the USB host code, but I believe it is seeing the raw keyboard (non translated) keys and doing it's own mappings.

Not sure if that helps you or not.
 
This will do the job

I am not completely sure of your setup or the like and it has been awhile since I did much with the USBHost code and not sure what you mean by USB keyboard for sending CW...


But assuming what you wish to do is to receive Keyboard information from a keyboard that is plugged into the HOST port of a Teensy 3.6.
I assume you have tried running the example programs under this library? In particular mouse.ino? ...

With this with the default code, you will see

1) Yes - the code does not generate auto repeats. you get an event for when the key is pressed and when it is released. You can decide to put in yur own timer or the like to create if desired.
2) ? - yes mainly alpha keys by default do automatic mapping...
3) Alt keys mapped to what? If you are asking for ALT+1+3+2 will generate ä, nope not implemented.
4 ctrl+alt+delete: will give you the delete key, if you then ask for the modifiers it is 5 for the CTRL+ALT... So you can decide to do something with this if you like.
5) Function keys - again will give you the function key, but the call to getModifiers() will get you the current state of the ctrl, alt, and shift keys. Note: There are actually 2 shift modifiers (2=left shift, 0x20 is right shift), likewise for alt and ctrl. and likewise for Window keys.

6) Caps lock, num lock, scroll lock - yes give you - for key... You can look at the OEM value for these if desired.

Now if you need even more control over this, you can take over all of the translation. I believe FrankB's C64 code base does this. Don't remember if I have a copy of the code around here or not. Note: it is using the USB host code, but I believe it is seeing the raw keyboard (non translated) keys and doing it's own mappings.

Not sure if that helps you or not.

Thanks Kurt, I think I can manage now the issues, thanks a lot!

Best regards,
Johan Holstein
 
Status
Not open for further replies.
Back
Top