Puck.js to emulate Lenovo mic on/off button

Posted on
  • Hi!

    I've been trying to use my Puck.js to emulate Lenovo keyboard microphone on/off button (f4), but cannot get it to work. I suppose that I need to somehow first tell the computer that my Puck.js is a lenovo keyboard and then send a right code.

    I can see from the lenovo drivers that the code I should send is "0x00f1".

    Any ideas regarding this?

    Here's my current code:

    function p(c,cb) {
      NRF.sendHIDReport(c, function() {
        NRF.sendHIDReport(0, cb);
    setWatch(function(e) {
      // Measure length of the press
      var len = e.time - e.lastTime;
      p(0x00f1,function() {
    }, BTN, { edge:"falling",repeat:true,debounce:50})­;
  • Hi! What you're doing looks kind of right, but you'll also need the code to enable HID mode and to send the HID report in the right format (it's usually an array rather than a single byte).

    What I'd suggest is to use the existing HID keyboard example as a base: http://www.espruino.com/BLE+Keyboard - and the library is http://www.espruino.com/modules/ble_hid_­keyboard.js

    So something like this might work:

    var report = new Uint8Array([
      0x05, 0x01,       // Usage Page (Generic Desktop)
      0x09, 0x06,       // Usage (Keyboard)
      0xA1, 0x01,       // Collection (Application)
      0x05, 0x07,       // Usage Page (Key Codes)
      0x19, 0xe0,       // Usage Minimum (224)
      0x29, 0xe7,       // Usage Maximum (231)
      0x15, 0x00,       // Logical Minimum (0)
      0x25, 0x01,       // Logical Maximum (1)
      0x75, 0x01,       // Report Size (1)
      0x95, 0x08,       // Report Count (8)
      0x81, 0x02,       // Input (Data, Variable, Absolute)
      0x95, 0x01,       // Report Count (1)
      0x75, 0x08,       // Report Size (8)
      0x81, 0x01,       // Input (Constant) reserved byte(1)
      0x95, 0x05,       // Report Count (5)
      0x75, 0x01,       // Report Size (1)
      0x05, 0x08,       // Usage Page (Page# for LEDs)
      0x19, 0x01,       // Usage Minimum (1)
      0x29, 0x05,       // Usage Maximum (5)
      0x91, 0x02,       // Output (Data, Variable, Absolute), Led report
      0x95, 0x01,       // Report Count (1)
      0x75, 0x03,       // Report Size (3)
      0x91, 0x01,       // Output (Data, Variable, Absolute), Led report padding
      0x95, 0x06,       // Report Count (6)
      0x75, 0x08,       // Report Size (8)
      0x15, 0x00,       // Logical Minimum (0)
      0x25, 0xff,       // Logical Maximum (255 - for lenovo mic)
      0x05, 0x07,       // Usage Page (Key codes)
      0x19, 0x00,       // Usage Minimum (0)
      0x29, 0xff,       // Usage Maximum (255 - for lenovo mic)
      0x81, 0x00,       // Input (Data, Array) Key array(6 bytes)
      0x09, 0x05,       // Usage (Vendor Defined)
      0x15, 0x00,       // Logical Minimum (0)
      0x26, 0xFF, 0x00, // Logical Maximum (255)
      0x75, 0x08,       // Report Count (2)
      0x95, 0x02,       // Report Size (8 bit)
      0xB1, 0x02,       // Feature (Data, Variable, Absolute)
      0xC0              // End Collection (Application)
    NRF.setServices(undefined, { hid : report });
    function tap(keyCode, modifiers, callback) {
      NRF.sendHIDReport([modifiers,0,keyCode,0­,0,0,0,0], function() {
        NRF.sendHIDReport([0,0,0,0,0,0,0,0], function() {
          if (callback) callback();
    function btnPressed() {
      tap(0xF1, 0, function() {  });
    setWatch(btnPressed, BTN, {edge:"rising",repeat:true,debounce:50})­;

    What I've done is used the HID report that's normally used for keyboards - but modified it so that instead of saying 115 is the maximum keycode sent, it says 255 is, so you can then send 0xF1.

    I'm not sure if that'll do it, but it's worth a try. Failing that you could see if you can get the report descriptor your actual Lenovo keyboard uses, and then copy that

  • Interesting. I was still unable to get it work. It seems that the key is not actually a part of the keyboard. When I try to monitor my key presses with "showkey -a" it does not catch the key press at all.

    Is there any other options to mute my microphone? I'm thinking of registering Puck.js as a headset?

    ed@edhome:~$ showkey -a
    Press any keys - Ctrl-D will terminate this program
    a 	 97 0141 0x61
    b 	 98 0142 0x62
    c 	 99 0143 0x63
    d 	100 0144 0x64
  • Updating my question. When I checked the bluetooth device settings in my Windows computer I noticed that there are no Manufacturer and Model information. I guess that because of this no lenovo drivers are used.

    So my question is how do I get Puck.js to be identified as a Lenovo keyboard?

    1 Attachment

    • Puck.js-keyboard.png
  • Well, I'm stabbing in the dark here but looking at https://github.com/torvalds/linux/blob/m­aster/drivers/hid/hid-lenovo.c#L141 it might be expecting that the 'usage page' is for Lenovo.

    I had a quick check and in that code there's actually mention of the usage page:

    	0x05, 0x88,		/* Usage Page (Vendor Usage Page 0x88)	*/
    	0x09, 0x01,		/* Usage (Vendor Usage 0x01)		*/
    	0xa1, 0x01,		/* Collection (Application)		*/
    	0x85, 0x04,		/*  Report ID (4)			*/
    	0x19, 0x00,		/*  Usage Minimum (0)			*/
    	0x2a, 0xff, 0xff,	/*  Usage Maximum (65535)		*/

    I think realistically rather than poking around randomly, if you could get the full HID descriptor it'd be a huge help.

    It looks like USBTreeView might do it? https://www.uwe-sieber.de/usbtreeview_e.­html

    You could give that a try and see if you can see the full HID report?

  • Actually looks like you're able to boot into Linux? If so then this looks very promising? https://github.com/DIGImend/usbhid-dump

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

Puck.js to emulate Lenovo mic on/off button

Posted by Avatar for user121862 @user121862