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?