Disable CAPS_LOCK on USB HID keyboard

Hello, I am using http://www.arduino.cc/en/Reference/MouseKeyboard on a Due to send keystrokes though USB. Is there a way to turn off CAPS_LOCK or to figure out the state of CAPS_LOCK so I could send a KEY_CAPS_LOCK press to turn it off?

I don't see anything that for that in here C:\Program Files (x86)\Arduino\hardware\awrduino\sam\cores\USB\USBAPI.h Frank

Hi there, good question. The older versions of Arduino did seem to support this when using USB Serial. This article here refers to a byte that will be returned containing the current state:

http://coopermaa2nd.blogspot.nl/2011/11/blog-post.html

Anyone have an idea how to do this in Arduino 1.6.x? I'd like to make use of this.

I need to add some information for my application. On the PC, there is a regular USB keyboard plus the Arduino USB keyboard on separate USB ports of the PC. I like the Arduino to have the ability to guarantee that the Arduino keys sent are lower case. Frank

Good to know, I will do some more digging since I’d like to have this functionality too. In the meanwhile you could also checkout AutoHotKey. A small scripting tool that also allows you to set the current capslock, numlock and scrolllock state.

http://www.autohotkey.com/

Don’t be afraid, if you don’t know AHK this is your lucky day!

After you write your AHK script, you can run it on a machine with AHK installed. But you can also Rightclick>Compile to create a small executable which you can run independently. Hope you like, here’s an example script:

SetCapsLockState, AlwaysOff
SetNumLockState, AlwaysOff
SetScrollLockState, AlwaysOff

Save this to a file with ahk extension and doubleclick. It’s that easy!

Allright, that wasn’t too bad. In order to accomplish what you need we’ll need to make a few adjustments.

These need to be made in the Arduino\hardware\arduino\avr\cores\arduino folder. Or whichever core you are using. Hope you have done this before.

The first thing you’ll want to do is add a variable that can hold the LED status:
Open HID.cpp and add this at the top:

volatile uint8_t hid_keyboard_leds = 0;

Then change your HID report descriptor, like so:
(add the highlighted code)

// Keyboard
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x02, // REPORT_ID (2)
0x05, 0x07, // USAGE_PAGE (Keyboard)

0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)

0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)

0x05, 0x08, /* USAGE_PAGE (LEDs) /
0x19, 0x01, /
USAGE_MINIMUM (Num Lock) /
0x29, 0x05, /
USAGE_MAXIMUM (Kana) /
0x95, 0x05, /
REPORT_COUNT (5) /
0x75, 0x01, /
REPORT_SIZE (1) /
__0x91, 0x02, /
OUTPUT (Data,Var,Abs) */__

0x95, 0x01, /* REPORT_COUNT (1) /
0x75, 0x03, /
REPORT_SIZE (3) /
__0x91, 0x03, /
OUTPUT (Cnst,Var,Abs) */__

0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)

0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x73, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0, // END_COLLECTION

We’ll also need a function to return the LED variable, add this function in the Keyboard_ section of the file:

uint8_t Keyboard_::getLeds(void){
return hid_keyboard_leds;
}

Almost there, just a slight modification in the HID_setup function that stores the HID control packet result in the variable:

(add the highlighted if statement)

if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (HID_SET_PROTOCOL == r)
{
_hid_protocol = setup.wValueL;
return true;
}

if (HID_SET_IDLE == r)
{
_hid_idle = setup.wValueL;
return true;
}

if (HID_SET_REPORT == r)
** {**
** //TODO check correct report ID (not needed for now, no other device has an out report)**
** // maybe make this a general weak implementation to use it for RAW HID later?**
** if (setup.wLength == 2)**
** {**
** // write led out report data**
** uint8_t data[2];**
** if (2 == USB_RecvControl(data, 2))**
** hid_keyboard_leds = data[1];**
** }**
** // else TODO check for other devices like RAW HID, not needed for now**
** }**

}

That’s basically it. That function we added to the Keyboard_ class needs to be declared in USBAPI.h:
(add the highlighted line to the Keyboard_ class)

class Keyboard_ : public Print
{
private:
KeyReport keyReport;
void sendReport(KeyReport* keys);
public:
Keyboard
(void);
void begin(void);
void end(void);

virtual size_t rawpress(uint8_t k);
virtual size_t rawrelease(uint8_t k);
virtual size_t write(uint8_t k);
virtual size_t press(uint8_t k);
virtual size_t release(uint8_t k);
virtual void releaseAll(void);

uint8_t getLeds(void);
};
extern Keyboard_ Keyboard;

Then you can finally read the LED status in your sketch:

#define LED_NUM_LOCK 0x01
#define LED_CAPS_LOCK 0x02
#define LED_SCROLL_LOCK 0x04

loop() {
uint8_t leds = Keyboard.getLeds();
Serial.print(“CapsLock” );
Serial.print(leds & LED_CAPS_LOCK);

Serial.print("ScrollLock ");
Serial.print(leds & LED_SCROLL_LOCK);

Serial.print("NumLock ");
Serial.println(leds & LED_NUM_LOCK);
}

I found this solution scattered though the HID library I found on Github, all credits go to the author. The library looks excellent so you may also want to download and try that.

Not bad eh?