Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: Observations on Teensy USB keyboard support

  1. #1
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112

    Observations on Teensy USB keyboard support

    I made these notes while investigating Teensy keyboard support, then thought they would be useful to share. There are specific bug reports and suggestions for enhancement, in bold.

    The key constants are derived from labelling of the US ANSI no-altgr keyboard layout
    http://en.wikipedia.org/wiki/File:KB...es-NoAltGr.svg

    The modifiers (four on Teensyduino, eight in C) are combined with the base keys.

    So to send ctrl-C you do
    Code:
    usb_keyboard_press(KEY_C, MODIFIER_KEY_CTRL);
    if you are using C and makefiles. Apparently though Teensyduino users don't have things so simple. They need instead to do
    Code:
    Keyboard.set_modifier(MODIFIERKEY_CTRL);
    Keyboard.set_key1(KEY_C);
    Keyboard.set_key2(0);
    Keyboard.set_key3(0);
    Keyboard.set_key4(0);
    Keyboard.set_key5(0);
    Keyboard.set_key6(0);
    Keyboard.send_now();
    Keyboard.set_key1(0); 
    Keyboard.send_now();
    Keyboard.set_key1(0); 
    Keyboard.send_now();
    Three comments, firstly why do Teensyduino users need to use so many more lines of code? It would be better to add the same function as in the C binding, for the cases where only a single key plus a modifier is pressed, then released.
    Secondly, why is there only access to left-hand modifiers? It would be better to support the right-hand modifier keys in Teensyduino as well as the left hand ones.
    And thirdly (minor), why the MOFIFIER_KEY_foo vs MODIFIERKEY_foo difference? It would be better to be consistent (although a reason to not be consistent would be that a change might break existing code).

    As required by the USB HID Keyboard spec, the key names however refer to layout, not labelling. So for example, to produce ctrl-A on a French AZERTY keyboard
    http://en.wikipedia.org/wiki/File:KB_France.svg
    requires
    Code:
    usb_keyboard_press(KEY_Q, MODIFIER_KEY_CTRL);
    because KEY_Q means the leftmost top row key, which is labelled A. This is confusing, and is probably the reason for the A-grave becoming Q-grave bug I reported earlier. But this layout-based naming comes from the USB keyboard spec.

    Or, on Teensyduino,
    Code:
    Keyboard.set_modifier(MODIFIERKEY_CTRL);
    Keyboard.set_key1(KEY_Q);
    Keyboard.set_key2(0);
    Keyboard.set_key3(0);
    Keyboard.set_key4(0);
    Keyboard.set_key5(0);
    Keyboard.set_key6(0);
    Keyboard.send_now();
    Keyboard.set_key1(0); 
    Keyboard.send_now();
    Keyboard.set_key1(0); 
    Keyboard.send_now();
    There is no direct support for dead keys, but again by reference to the ANSI keyboard layout they can be produced. So to output which, on a French AZERTY keyboard, is typed with the diaresis dead key followed by e, one would do
    Code:
    usb_keyboard_press(KEY_LEFT_BRACE, MODIFIER_KEY_SHIFT);
    usb_keyboard_press(KEY_E, 0);
    or on Teensyduino
    Code:
    Keyboard.set_modifier(MODIFIERKEY_SHIFT);
    Keyboard.set_key1(KEY_LEFT_BRACE);
    Keyboard.set_key2(0);
    Keyboard.set_key3(0);
    Keyboard.set_key4(0);
    Keyboard.set_key5(0);
    Keyboard.set_key6(0);
    Keyboard.send_now();
    Keyboard.set_modifier(0);
    Keyboard.set_key1(KEY_E);
    Keyboard.send_now();
    Keyboard.set_key1(0); 
    Keyboard.send_now();
    alt-gr is the same as MODIFIER_KEY_RIGHT_ALT which is available in C but not in Teensyduino. So any keypress that needs alt-gr (€ on UK English; €#{[`\^@]} on French AZERTY) can only be produced with Keyboard.print();. It would be better to allow the right-hand modifier keys in Teensyduino.

    Keys not on the US ANSI layout can't be produced at all by the current Teensy implementation. The menu key, the Fn key, and (on Japanese keyboards) the three keys near the spacebar which control character input methods, and the underscore/backslash keypresses cannot be produced
    http://en.wikipedia.org/wiki/File:KB_Japanese.svg

    Keyboard Menu has HID code 118 (0x76) so could be supported
    .
    Last edited by Nantonos; 11-30-2012 at 05:56 PM.

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    The keycode constants evaluate to integers which are USB HID Usage IDs for the Keyboard/Keypad Page.
    see Chapter 10, page 53ff of
    http://www.usb.org/developers/devcla.../Hut1_12v2.pdf

    also
    http://www.usb.org/developers/devclass_docs/HID1_11.pdf


    in keylayouts.h there is support for media keys but these are not documented, and the codes conflict with Keyboard/Keypad Page codes.
    Code:
    #define KEY_MEDIA_VOLUME_INC    0x01
    #define KEY_MEDIA_VOLUME_DEC    0x02
    #define KEY_MEDIA_MUTE          0x04
    #define KEY_MEDIA_PLAY_PAUSE    0x08
    #define KEY_MEDIA_NEXT_TRACK    0x10
    #define KEY_MEDIA_PREV_TRACK    0x20
    #define KEY_MEDIA_STOP          0x40
    #define KEY_MEDIA_EJECT         0x80
    while the listed USB Keyboard/Keypad codes are
    Code:
    0x7F	Keyboard Mute
    0x80	Keyboard Volume Up
    0x81	Keyboard Volume Down

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    There are missing codes: 1-3, 100-103, 116-164, 176-221, 224-231. These should be added.

    Code:
    1	Keyboard ErrorRollOver
    2	Keyboard POSTFail
    3	Keyboard ErrorUndefined
    100	Keyboard Non-US \ and |
    101	Keyboard Application
    102	Keyboard Power
    103	Keypad =
    116	Keyboard Execute
    117	Keyboard Help
    118	Keyboard Menu
    119	Keyboard Select
    120	Keyboard Stop
    121	Keyboard Again
    122	Keyboard Undo
    123	Keyboard Cut
    124	Keyboard Copy
    125	Keyboard Paste
    126	Keyboard Find
    127	Keyboard Mute
    128	Keyboard Volume Up
    129	Keyboard Volume Down
    130	Keyboard Locking Caps Lock
    131	Keyboard Locking Num Lock
    132	Keyboard Locking Scroll Lock
    133	Keypad Comma
    134	Keypad Equals Sign
    135	Keyboard International1
    136	Keyboard International2
    137	Keyboard International3
    138	Keyboard International4
    139	Keyboard International5
    140	Keyboard International6
    141	Keyboard International7
    142	Keyboard International8
    143	Keyboard International9
    144	Keyboard LANG1
    145	Keyboard LANG2
    146	Keyboard LANG3
    147	Keyboard LANG4
    148	Keyboard LANG5
    149	Keyboard LANG6
    150	Keyboard LANG7
    151	Keyboard LANG8
    152	Keyboard LANG9
    153	Keyboard Alternate Erase
    154	Keyboard SysReq/Attention
    155	Keyboard Cancel
    156	Keyboard Clear
    157	Keyboard Prior
    158	Keyboard Return
    159	Keyboard Separator
    160	Keyboard Out
    161	Keyboard Oper
    162	Keyboard Clear/Again
    163	Keyboard CrSel/Props
    164	Keyboard ExSel
    176	Keypad 00
    177	Keypad 000
    178	Thousands Separator
    179	Decimal Separator
    180	Currency Unit
    181	Currency Sub-unit
    182	Keypad (
    183	Keypad )
    184	Keypad {
    185	Keypad }
    186	Keypad Tab
    187	Keypad Backspace
    188	Keypad A
    189	Keypad B
    190	Keypad C
    191	Keypad D
    192	Keypad E
    193	Keypad F
    194	Keypad XOR
    195	Keypad ^
    196	Keypad %
    197	Keypad <
    198	Keypad >
    199	Keypad &
    200	Kepad &&
    201	Keypad |
    202	Keypad ||
    203	Keypad :
    204	Keypad #
    205	Keypad Space
    206	Keypad @
    207	Keypad !
    208	Keypad Memory Store
    209	Keypad Memory Recall
    210	Keypad Memory Clear
    211	Keypad Memory Add
    212	Keypad Memory Subtract
    213	Keypad Memory Multiply
    214	Keypad Memory Divide
    215	Keypad +/-
    216	Keypad Clear
    217	Keypad Clear Entry
    218	Keypad Binary
    219	Keypad Octal
    220	Keypad Decimal
    221	Keypad Hexadecimal
    224	Keyboard LeftControl
    225	Keyboard LeftShift
    226	Keyboard LeftAlt
    227	Keyboard Left GUI
    228	Keyboard RightControl
    229	Keyboard RightShift
    230	Keyboard RightAlt
    231	Keyboard Right GUI

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112

    Teensy 3.0 and USB keyboard

    Teensy beta 8
    Teensy 3.0
    Win 7/64 SP1
    USB Type:K+M+J
    Examples > Teensy > USB_Keyboard > Simple

    will not compile.
    Code:
    F:\Arduino\arduino-1.0.2-teensybeta8\hardware\teensy\cores\teensy3\usb_keyboard.c: In function 'usb_keyboard_press_keycode':
    F:\Arduino\arduino-1.0.2-teensybeta8\hardware\teensy\cores\teensy3\usb_keyboard.c:237: error: 'keyboard_report_data' undeclared (first use in this function)
    F:\Arduino\arduino-1.0.2-teensybeta8\hardware\teensy\cores\teensy3\usb_keyboard.c:237: error: (Each undeclared identifier is reported only once
    F:\Arduino\arduino-1.0.2-teensybeta8\hardware\teensy\cores\teensy3\usb_keyboard.c:237: error: for each function it appears in.)
    the offending bit of usb_keyboard.c is
    Code:
    	#ifdef DEADKEYS_MASK
    	deadkeycode = deadkey_to_keycode(keycode);
    	if (deadkeycode) {
    		modrestore = keyboard_report_data[0];
    		if (modrestore) {
    			keyboard_report_data[0] = 0;
    			send_now();
    		}
    		// TODO: test if operating systems recognize
    		// deadkey sequences when other keys are held
    		mod = keycode_to_modifier(deadkeycode);
    		key = keycode_to_key(deadkeycode);
    		usb_keyboard_press_key(key, mod);
    		usb_keyboard_release_key(key, mod);
    	}
    	#endif

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    278
    [QUOTE=Nantonos;2439]alt-gr is the same as MODIFIER_KEY_RIGHT_ALT which is available in C but not in Teensyduino. So any keypress that needs alt-gr (€ on UK English; €#{[`\^@]} on French AZERTY) can only be produced with Keyboard.print();. It would be better to allow the right-hand modifier keys in Teensyduino.

    Whilst I have been working with the Teensy I have discovered that AltGr is actually just CTRL-ALT anyway so not hard to achieve in practice.

    Also both the left and right hand modifiers appear to be mapped:

    \arduino-1.0.1\hardware\teensy\cores\teensy\Keylayouts.h:

    #define MODIFIERKEY_CTRL ( 0x01 | 0x8000 )
    #define MODIFIERKEY_SHIFT ( 0x02 | 0x8000 )
    #define MODIFIERKEY_ALT ( 0x04 | 0x8000 )
    #define MODIFIERKEY_GUI ( 0x08 | 0x8000 )
    #define MODIFIERKEY_LEFT_CTRL ( 0x01 | 0x8000 )
    #define MODIFIERKEY_LEFT_SHIFT ( 0x02 | 0x8000 )
    #define MODIFIERKEY_LEFT_ALT ( 0x04 | 0x8000 )
    #define MODIFIERKEY_LEFT_GUI ( 0x08 | 0x8000 )
    #define MODIFIERKEY_RIGHT_CTRL ( 0x10 | 0x8000 )
    #define MODIFIERKEY_RIGHT_SHIFT ( 0x20 | 0x8000 )
    #define MODIFIERKEY_RIGHT_ALT ( 0x40 | 0x8000 )
    #define MODIFIERKEY_RIGHT_GUI ( 0x80 | 0x8000 )

    See \arduino-1.0.1\hardware\teensy\cores\usb_hid\usb_api.cpp

    uint8_t usb_keyboard_class::keycode_to_modifier(KEYCODE_TY PE keycode)
    {
    uint8_t modifier=0;

    #ifdef SHIFT_MASK
    if (keycode & SHIFT_MASK) modifier |= MODIFIERKEY_SHIFT;
    #endif
    #ifdef ALTGR_MASK
    if (keycode & ALTGR_MASK) modifier |= MODIFIERKEY_RIGHT_ALT;
    #endif
    #ifdef RCTRL_MASK
    if (keycode & RCTRL_MASK) modifier |= MODIFIERKEY_RIGHT_CTRL;
    #endif
    return modifier;
    }


    Not sure if I am missing something ?

  6. #6
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    Teensy beta 8
    Teensy 2.0
    Win 7/64 SP1
    USB Type:K+M+J
    Examples > Teensy > USB_Keyboard > Simple

    compiles and executes as expected.

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    Quote Originally Posted by Experimentalist View Post
    Quote Originally Posted by Nantonos View Post
    alt-gr is the same as MODIFIER_KEY_RIGHT_ALT which is available in C but not in Teensyduino. So any keypress that needs alt-gr (€ on UK English; €#{[`\^@]} on French AZERTY) can only be produced with Keyboard.print();. It would be better to allow the right-hand modifier keys in Teensyduino.
    Whilst I have been working with the Teensy I have discovered that AltGr is actually just CTRL-ALT anyway so not hard to achieve in practice.
    No, AltGr is the same as MODIFIERKEY_RIGHT_ALT.

    Quote Originally Posted by Experimentalist View Post
    Also both the left and right hand modifiers appear to be mapped:

    \arduino-1.0.1\hardware\teensy\cores\teensy\Keylayouts.h:

    #define MODIFIERKEY_CTRL ( 0x01 | 0x8000 )
    #define MODIFIERKEY_SHIFT ( 0x02 | 0x8000 )
    #define MODIFIERKEY_ALT ( 0x04 | 0x8000 )
    #define MODIFIERKEY_GUI ( 0x08 | 0x8000 )
    #define MODIFIERKEY_LEFT_CTRL ( 0x01 | 0x8000 )
    #define MODIFIERKEY_LEFT_SHIFT ( 0x02 | 0x8000 )
    #define MODIFIERKEY_LEFT_ALT ( 0x04 | 0x8000 )
    #define MODIFIERKEY_LEFT_GUI ( 0x08 | 0x8000 )
    #define MODIFIERKEY_RIGHT_CTRL ( 0x10 | 0x8000 )
    #define MODIFIERKEY_RIGHT_SHIFT ( 0x20 | 0x8000 )
    #define MODIFIERKEY_RIGHT_ALT ( 0x40 | 0x8000 )
    #define MODIFIERKEY_RIGHT_GUI ( 0x80 | 0x8000 )
    For use in C, yes. For use in Teensyduino, apparently not.

    Compare the list of modifier keys for C and for Teensyduino. The former lists 12 modifiers (but the ones without left or right in the names map to the left hand ones). The latter lists only 4 (which, again, map to the left hand ones).

    Quote Originally Posted by Experimentalist View Post
    See \arduino-1.0.1\hardware\teensy\cores\usb_hid\usb_api.cpp

    uint8_t usb_keyboard_class::keycode_to_modifier(KEYCODE_TY PE keycode)
    {
    uint8_t modifier=0;

    #ifdef SHIFT_MASK
    if (keycode & SHIFT_MASK) modifier |= MODIFIERKEY_SHIFT;
    #endif
    #ifdef ALTGR_MASK
    if (keycode & ALTGR_MASK) modifier |= MODIFIERKEY_RIGHT_ALT;
    #endif
    #ifdef RCTRL_MASK
    if (keycode & RCTRL_MASK) modifier |= MODIFIERKEY_RIGHT_CTRL;
    #endif
    return modifier;
    }

    Not sure if I am missing something ?
    Notice that in the code you quoted, altgr is right_alt not ctrl-alt

    Or maybe I am putting too much faith in the documentation rather than the code. Will try it and report back.
    Last edited by Nantonos; 11-30-2012 at 05:58 PM.

  8. #8
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    Teensy beta 8
    Teensy 2.0
    Win 7/64 SP1
    USB Type:K+M+J
    USB French keyboard test code posted here.

    compiles and runs as expected (with the same output errors I reported in that thread).

    Teensy beta 8
    Teensy 3.0
    Win 7/64 SP1
    USB Type:K+M+J
    same sketch

    compilation error
    Code:
    LayoutTest_Fr_AZERTY.ino: In function 'void setup()':
    LayoutTest_Fr_AZERTY:97: error: 'MODIFIERKEY_SHIFT' was not declared in this scope
    LayoutTest_Fr_AZERTY:98: error: 'KEY_LEFT_BRACE' was not declared in this scope
    LayoutTest_Fr_AZERTY:106: error: 'KEY_E' was not declared in this scope

  9. #9
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    Quote Originally Posted by Nantonos View Post
    It would be better to add the same function as in the C binding, for the cases where only a single key plus a modifier is pressed, then released.
    This turns out to be simple (Tested on Teensy 2.0, beta8 Teensyduino).

    Code:
    /* Implement simple keyboard sending, from the C binding.
    
     You must select Keyboard from the "Tools > USB Type" menu
     Select the the correct layout from "Tools > Keyboard Layout"
     */
    
     // Teensy 2.0 = Pin 11, Teensy++ 2.0 = Pin 6; Teensy 3.0 = Pin 13
    const int ledPin = 11;  
    
    void setup() {
      // Blink the LED for 10 seconds, to give time to open 
      // a word processor or text editor to receive the test text
      pinMode(ledPin, OUTPUT);
      for (int i=0; i < 10; i++) {
        digitalWrite(ledPin, HIGH);
        delay(500);
        digitalWrite(ledPin, LOW);
        delay(500);
      }
    }
    
    void loop () {
      //Qq repeatedly
      usb_keyboard_press(KEY_Q, MODIFIERKEY_SHIFT);
      delay(100);
      usb_keyboard_press(KEY_Q, 0);
      delay(100);
    }
    
    void usb_keyboard_press(int key, int modifier) {
      // press one key with up to one modifier, then release
      Keyboard.set_modifier(modifier);
      Keyboard.set_key1(key);
      Keyboard.set_key2(0);
      Keyboard.set_key3(0);
      Keyboard.set_key4(0);
      Keyboard.set_key5(0);
      Keyboard.set_key6(0);
      Keyboard.send_now();
      delay(1);
      Keyboard.set_key1(0); 
      Keyboard.send_now();
    }

  10. #10
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,112
    Quote Originally Posted by Nantonos View Post
    I made these notes while investigating Teensy keyboard support, then thought they would be useful to share. There are specific bug reports and suggestions for enhancement, in bold.
    I'm updating my comments based on beta9.
    Quote Originally Posted by Nantonos View Post
    Three comments, firstly why do Teensyduino users need to use so many more lines of code? It would be better to add the same function as in the C binding, for the cases where only a single key plus a modifier is pressed, then released.
    I see this is fixed in beta9. The following code compils with Teensy 3 and Keyboard+Mouse+Joystick:

    Code:
    #include "keylayouts.h"
    
    void setup (){
      delay(3000);
      usb_keyboard_press(KEY_Q, MODIFIERKEY_CTRL);
    }
    
    void loop (){
    }
    Quote Originally Posted by Nantonos View Post
    Secondly, why is there only access to left-hand modifiers? It would be better to support the right-hand modifier keys in Teensyduino as well as the left hand ones.
    And thirdly (minor), why the MOFIFIER_KEY_foo vs MODIFIERKEY_foo difference? It would be better to be consistent (although a reason to not be consistent would be that a change might break existing code).

    So any keypress that needs alt-gr (€ on UK English; €#{[`\^@]} on French AZERTY) can only be produced with Keyboard.print();. It would be better to allow the right-hand modifier keys in Teensyduino.
    I see that left and right hand modifier keys have been added in beta9:

    Code:
    #define MODIFIERKEY_CTRL        ( 0x01 | 0x8000 )
    #define MODIFIERKEY_SHIFT       ( 0x02 | 0x8000 )
    #define MODIFIERKEY_ALT         ( 0x04 | 0x8000 )
    #define MODIFIERKEY_GUI         ( 0x08 | 0x8000 )
    #define MODIFIERKEY_LEFT_CTRL   ( 0x01 | 0x8000 )
    #define MODIFIERKEY_LEFT_SHIFT  ( 0x02 | 0x8000 )
    #define MODIFIERKEY_LEFT_ALT    ( 0x04 | 0x8000 )
    #define MODIFIERKEY_LEFT_GUI    ( 0x08 | 0x8000 )
    #define MODIFIERKEY_RIGHT_CTRL  ( 0x10 | 0x8000 )
    #define MODIFIERKEY_RIGHT_SHIFT ( 0x20 | 0x8000 )
    #define MODIFIERKEY_RIGHT_ALT   ( 0x40 | 0x8000 )
    #define MODIFIERKEY_RIGHT_GUI   ( 0x80 | 0x8000 )
    Quote Originally Posted by Nantonos View Post
    Keys not on the US ANSI layout can't be produced at all by the current Teensy implementation. The menu key, the Fn key, and (on Japanese keyboards) the three keys near the spacebar which control character input methods, and the underscore/backslash keypresses cannot be produced
    http://en.wikipedia.org/wiki/File:KB_Japanese.svg

    Keyboard Menu has HID code 118 (0x76) so could be supported
    .
    The list of HID codes stops at 115; Keyboard Menu has not been added.
    Last edited by Nantonos; 12-30-2012 at 09:33 AM.

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,122
    I'm preparing beta 10. If you'd like me to test any particular thing, please post a ready-to-run sample program.

    Media keys will not be in beta 10, but I will do them soon. Windows requires an entirely separate interface and endpoint, due to some lame security implementation decisions on Microsoft's part.

    There is actually an easy API like the one you requested... I have haven't documented it yet. You can use Keyboard.press(code) and Keyboard.release(code). It allows either the keyboard codes, or ascii, and a fair amount of unicode too.

    With beta 10 so close, I'm only fixing bugs. New keycodes can be added after 10 is published. Before proposing more keycodes, please make sure they work with Windows. I'm willing to add them if they work on all 3 systems. If Windows doesn't work, it'll go on the wish-list for the media keys interface.

  12. #12
    Administrator Paul's Avatar
    Join Date
    Oct 2012
    Posts
    392
    If anyone's still watching this old thread, new & improved media key support is available.

    https://forum.pjrc.com/threads/34074...ows-compatible

    I'm closing this old thread. Please comment on the new thread.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •