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

Thread: Keyboard Media Keys, now (hopefully) Windows compatible

  1. #1
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808

    Keyboard Media Keys, now (hopefully) Windows compatible

    I've been working on improved media keys support which can work with Windows. It's ready for initial testing. Hopefully there's still interest in this feature?

    Code for Teensy LC & 3.x is on github now.

    https://github.com/PaulStoffregen/cores

    If you'd like to try this, download the cores repository and replace your hardware/teensy/avr/cores folder with its contents. On a Mac, control-click Arduino, then "Show Package Contents", and replace Contents/Java/hardware/teensy/avr/cores with the files from github.

    I'm planning to back-port this to Teensy 2.0, after some testing. As you can see on the github commit log, this changed quite a lot of the USB keyboard code. I could really use some help with testing, especially on various Windows systems, and *especially* with the many non-US layouts. So far, I've done only initial testing on Windows 10, and only with "US English" keyboard layout.

    The new media key support is intended to be used with Keyboard.press() and Keyboard.release(). Here's an example:

    Code:
    /* Buttons to USB Keyboard Example - Special Media Player Keys
    
       You must select Keyboard from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    */
    
    #include <Bounce.h>
    
    // Create Bounce objects for each button.  The Bounce object
    // automatically deals with contact chatter or "bounce", and
    // it makes detecting changes very simple.
    Bounce button0 = Bounce(0, 10);
    Bounce button1 = Bounce(1, 10);  // 10 ms debounce time is appropriate
    Bounce button2 = Bounce(2, 10);  // for most mechanical pushbuttons
    // TODO: fix pin 3 button on my testing board....
    Bounce button3 = Bounce(4, 10);
    Bounce button4 = Bounce(5, 10);  // if a button is too "sensitive" 
    Bounce button5 = Bounce(6, 10);  // you can increase this time.
    
    void setup() {
      // Configure the pins for input mode with pullup resistors.
      // The pushbuttons connect from each pin to ground.  When
      // the button is pressed, the pin reads LOW because the button
      // shorts it to ground.  When released, the pin reads HIGH
      // because the pullup resistor connects to +5 volts inside
      // the chip.
      pinMode(0, INPUT_PULLUP);
      pinMode(1, INPUT_PULLUP);
      pinMode(2, INPUT_PULLUP);
      pinMode(4, INPUT_PULLUP);
      pinMode(5, INPUT_PULLUP);
      pinMode(6, INPUT_PULLUP);
    }
    
    void loop() {
      // Update all the buttons.  There should not be any long
      // delays in loop(), so this runs repetitively at a rate
      // faster than the buttons could be pressed and released.
      button0.update();
      button1.update();
      button2.update();
      button3.update();
      button4.update();
      button5.update();
    
      // Check each button for "falling" edge.
      // falling = high (not pressed - voltage from pullup resistor)
      //           to low (pressed - button connects pin to ground)
      if (button0.fallingEdge()) {
        Keyboard.press(KEY_MEDIA_PREV_TRACK);
        Keyboard.release(KEY_MEDIA_PREV_TRACK);
      }
      if (button1.fallingEdge()) {
        Keyboard.press(KEY_MEDIA_PLAY_PAUSE);
        Keyboard.release(KEY_MEDIA_PLAY_PAUSE);
      }
      if (button2.fallingEdge()) {
        Keyboard.press(KEY_MEDIA_NEXT_TRACK);
        Keyboard.release(KEY_MEDIA_NEXT_TRACK);
      }
      if (button3.fallingEdge()) {
        Keyboard.press(KEY_MEDIA_VOLUME_DEC);
        Keyboard.release(KEY_MEDIA_VOLUME_DEC);
      }
      if (button4.fallingEdge()) {
        Keyboard.press(KEY_MEDIA_VOLUME_INC);
        Keyboard.release(KEY_MEDIA_VOLUME_INC);
      }
      if (button5.fallingEdge()) {
        Keyboard.press(KEY_SYSTEM_POWER_DOWN);
        Keyboard.release(KEY_SYSTEM_POWER_DOWN);
        //Keyboard.press(KEY_MEDIA_EJECT);
        //delay(300);  // Mac OS-X will not recognize a very short eject press
        //Keyboard.release(KEY_MEDIA_EJECT);
      }
    }
    So far, these are the keys defined in keylayouts.h:

    Code:
    KEY_MEDIA_PLAY          
    KEY_MEDIA_PAUSE         
    KEY_MEDIA_RECORD        
    KEY_MEDIA_FAST_FORWARD  
    KEY_MEDIA_REWIND        
    KEY_MEDIA_NEXT_TRACK    
    KEY_MEDIA_PREV_TRACK    
    KEY_MEDIA_STOP          
    KEY_MEDIA_EJECT         
    KEY_MEDIA_RANDOM_PLAY   
    KEY_MEDIA_PLAY_PAUSE    
    KEY_MEDIA_PLAY_SKIP     
    KEY_MEDIA_MUTE          
    KEY_MEDIA_VOLUME_INC    
    KEY_MEDIA_VOLUME_DEC    
    KEY_SYSTEM_POWER_DOWN
    KEY_SYSTEM_SLEEP
    KEY_SYSTEM_WAKE_UP
    Unlike the old code, which was limited to only 8 keys (which only worked on Mac & Linux), this new way is intended to be able to support all the media (aka HID Consumer Usage Page) key definitions, and all the system control keys too.

    The Keyboard.press() and Keyboard.release() functions are meant to accept ASCII, and Unicode up to 0xC1FF (of course, each layout implements only a small fraction of the huge Unicode space), and non-ascii characters, and the many KEY_XYZ constants which map directly to HID usage numbers. Much of this code got reworked... and it seems to be functioning, but I haven't yet tested on non-US layouts. I could really use help testing from anyone using Teensy as a non-US keyboard.

    If you find anything not working, please be sure to post a complete program and specify which layout and OS you're using, so I can try to reproduce and fix the problem.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808
    If anyone wants to experiment with defining other keys, this is the spec where they're found:

    http://www.usb.org/developers/hidpage/Hut1_12v2.pdf

    The media/consumer keys are in table 17 starting on page 75. To use these, add an offset of 0xE400 to the Usage ID number in the spec, for the number you give to Keyboard.press() and Keyboard.release().

    The system control keys are on page 27. To use these, add of offset of 0xE200. So to experiment with whatever "System Menu Exit" actually does (if anything), you'd use Keyboard.press(0xE288); to send that keystroke to your PC.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808
    Has anyone giving this a try yet? Maybe I ought to make an early 1.29 beta once the other new usb stuff is stable?

  4. #4
    Senior Member Pensive's Avatar
    Join Date
    Aug 2014
    Location
    Basingstoke, UK
    Posts
    562
    I'm interested in it, but finding time for everything is my challenge.

    I think there would be great benefit in implementing many of the other ones like flight sim commands etc, so you could create a flight sim joystick that didn't need setting up, for example.

    But i havent had a chance to test the media keys yet and won't for a bit.

    I'd like to make a "Massive Sleep Bash Button" to sleep my PC - i've got the button ready and everything.

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808
    When I tested on Windows 10, this code instantly put it into sleep mode.

    Code:
        Keyboard.press(KEY_SYSTEM_POWER_DOWN);
        Keyboard.release(KEY_SYSTEM_POWER_DOWN);
    Ubuntu 14.04 and Mac OS-X 10.7.5 both display a dialog box asking to confirm, but Windows just instantly went to sleep mode!

  6. #6
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    win 7
    same as when I press the Sleep key on my keyboard... with an icon of the moon affixed.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808
    I've back-ported the new Windows-compatible media keys to Teensy 2.0 & Teensy++ 2.0.

    https://github.com/PaulStoffregen/co...4a104f6888db15

    They can only be used in Keyboard+Mouse+Joystick mode. It works great with Windows 10. I believe all other versions of Windows should work too.

    When Serial is added, the AVR chips don't have enough USB endpoints to add the media keys.

  8. #8

    Need More Keys...

    [QUOTE=PaulStoffregen;102516]I've back-ported the new Windows-compatible media keys to Teensy 2.0 & Teensy++ 2.0.

    Hi Paul,

    Just joining the discussion, been a Teensy fan/user for years. Thanks for all your work and contributions that help make this such a cool tool!

    I'm working on a keyboard project and need FULL replacement for 104 keyboard (not so worried about media keys, but that'd be nice).
    -- My background is in Assistive Technology - tech for folks with disabilities --

    Forced by customers, I'm primarily a Windows person...

    I have run into several concerns, firstly: we have the GUI key(s) only as a modifier. Using the Windows key alone, for example, works as a single key-send not as a modifier.
    Is there some 'dead' key that I can send with your MODIFIERKEY_GUI key that gives me the same result as just pressing and releasing the Windows key (scan code-VKC 91/5B).
    I see in your new updates the right-hand versions of Modifier keys, but I can't find a GUI Menu (scan code-VKC 93/5D) I'd love to have that.

    As a thought, if it saves space dropping the Left-Hand Constants seems like it wouldn't matter since they are redundant.
    also, you probably are doing so, but in case not, as an idea to save space in my code I store the constants as bytes and add the 15th bit when I use them (A = 4 + 16384)

    I assume the naming conventions are why the constants for several characters are off - using the shifted names not the un-shifted names:
    (KEY_TILDE, KEY_QUOTE, KEY_NUMBER, KEY_RIGHT_BRACE, KEY_LEFT_BRACE) it might help folks to add a note to that effect in the support pages...

    By the way I have a Windows-based Key Watching tool I made that reports Scan Codes and Names for keys as pressed (using Windows API's so if you set the system to a Norwegian keyboard you get the names in Norwegian!)
    I'd be happy to send you a copy if you like, or to use it to help test new changes to Teensy code...

    Cheers, thanks and let me know if there is anything I can do to help grow the Teensy World!

    Kirk

  9. #9

    P.S.

    Forgot one...

    Is there some way to catch the Caps Lock / NumLock status when the Computer sends the status update?
    i.e. I want my keyboard to have LED's for those two but need to know if the regular keyboard sent a keypress for either... so mine can match.

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808
    If you have 2 (or more) keyboards connected to a PC, each communicates with the PC, but they never communicate with each other. When you press a key on one of the keyboards, the PC doesn't send anything to the other keyboard to inform them of the activity on the unrelated keyboard.

    When you press cap locks, the PC might or might not consider all the keyboards to be in cap lock mode. When you think about it for a moment, it's rather silly to have the caps lock key one any of your keyboards put all the others into caps lock mode. But some versions of Windows do this. I know Macintosh does not.

    Before you get too far down the path, I recommend plugging 2 real keyboards into your PC and watching what effect each has on the other's LEDs. Whatever your PC does, understand it's how your operating system is handling things. Other PCs might be different. Not all operating systems are created equal.

  11. #11
    Never mind, I hacked your code and used the HID value directly it works!

    void sendKeyboard( int sendKey){
    unsigned int KeyCodeVal;


    // Set the final PJRC Key Value:
    // KEYBASE is defined as bit15: 16384 or 0x4000
    KeyCodeVal = sendKey| KEYBASE;

    Keyboard.set_modifier(0);
    Keyboard.set_key1(KeyCodeVal);
    //Keyboard.set_key2(KEY_B);
    //Keyboard.set_key3(KEY_C);
    //Keyboard.set_key4(KEY_D);
    //Keyboard.set_key5(KEY_E);
    //Keyboard.set_key6(KEY_F);
    Keyboard.send_now();

    // release all the keys at the same instant
    Keyboard.set_modifier(0);
    Keyboard.set_key1(0);
    Keyboard.send_now();
    }

    Then call like this:

    sendKeyboard(101);

    -- 101 is the offset value for the Application Key as defined in the HID spec.

    Again, thanks for building such a cool platform that makes things like this so easy!
    Last edited by Kirk Siqveland; 07-23-2016 at 05:34 AM.

  12. #12
    Dang, I thought I could use the other HID codes the same way, but other than the Application-Menu key none of the ones I'm looking for are working.

    Any thoughts?
    I'm wondering if its a signed/unsigned integer issue since the numbers I need are above 127...

    I'm still hoping to have full replacement for all the keys on a 104 keyboard.

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,808
    Starting with Teensyduino 1.29, use Keyboard.press() and Keyboard.release() for the media keys.

    Look at File > Examples > Teensy > USB_Keyboard > MediaButtons.

  14. #14
    I've got a teensy 3.1 running as a usb keyboard+mouse. KEY_SYSTEM_SLEEP and KEY_SYSTEM_POWER_DOWN both put the computer to sleep though KEY_SYSTEM_WAKE_UP doesn't bring the computer out of sleep nor does sending a regular key (such as KEY_SPACE). What's odd is that both wired and wireless usb keyboards seem to bring it out of sleep just fine, both by pressing the 'moon' icon and by just hitting any random (non-modifier or F) key. I'm not that familiar with the inner workings of usb but I'd be grateful for any direction someone cold point me towards. I've been at this for a while now and just can't seem to get my head around it.

  15. #15
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by euchrideucrow View Post
    I've got a teensy 3.1 running as a usb keyboard+mouse. KEY_SYSTEM_SLEEP and KEY_SYSTEM_POWER_DOWN both put the computer to sleep though KEY_SYSTEM_WAKE_UP doesn't bring the computer out of sleep nor does sending a regular key (such as KEY_SPACE).
    You probably didn't set up USB remote wakeup:
    https://forum.pjrc.com/threads/36144...-OS-X-computer

  16. #16
    Thanks for the link; unfortunately that's the first discussion I came across and making the change in usb_desc.c and then using his button code in my loop didn't work in my case. I could very well be implementing it wrong but all I have to do is change that one line in usb-desc.c and I should then be able to use his code or KEY_SYSTEM_WAKE_UP on button press, correct?

  17. #17
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by euchrideucrow View Post
    Thanks for the link; unfortunately that's the first discussion I came across and making the change in usb_desc.c and then using his button code in my loop didn't work in my case. I could very well be implementing it wrong but all I have to do is change that one line in usb-desc.c and I should then be able to use his code or KEY_SYSTEM_WAKE_UP on button press, correct?
    You can't just send a key, it won't be received. You have to use 'USB_CTL_RESUME'. You also need to make sure the USB descriptor is reloaded, e.g. on Windows it will be cached and you have to force a refresh.

  18. #18
    Gave this a shot a second time. It does work if I immediately press my wake up button after the computer has gone to sleep. If I wait longer than about 5 seconds it stops bringing it out of sleep. Uninstalled the device in windows and switched it to a different hub just to be sure that the cache had cleared.

Posting Permissions

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