Skip to content

Commit f34df6e

Browse files
committed
Added KeyboardLeds/HID Out Report
This also enables the option for further raw HID development.
1 parent 02684ed commit f34df6e

File tree

9 files changed

+251
-70
lines changed

9 files changed

+251
-70
lines changed

examples/KeyboardLed/KeyboardLed.ino

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright (c) 2014-2015 NicoHood
3+
See the readme for credit to other people.
4+
5+
KeyboardLed example
6+
7+
Press a button to toogle caps lock.
8+
Caps lock state is represented by the onboard led.
9+
10+
See HID Project documentation for more information.
11+
https://github.com/NicoHood/HID/wiki/Keyboard-API
12+
*/
13+
14+
#include "HID-Project.h"
15+
16+
const int pinLed = LED_BUILTIN;
17+
const int pinButton = 2;
18+
19+
void setup() {
20+
pinMode(pinLed, OUTPUT);
21+
pinMode(pinButton, INPUT_PULLUP);
22+
23+
// Sends a clean report to the host. This is important on any Arduino type.
24+
Keyboard.begin();
25+
}
26+
27+
28+
void loop() {
29+
// Update Led equal to the caps lock state.
30+
// Keep in mind that on a 16u2 and Arduino Micro HIGH and LOW for TX/RX Leds are inverted.
31+
if (Keyboard.getLeds()&LED_CAPS_LOCK)
32+
digitalWrite(pinLed, HIGH);
33+
else
34+
digitalWrite(pinLed, LOW);
35+
36+
// Trigger caps lock manually via button
37+
if (!digitalRead(pinButton)) {
38+
Keyboard.write(KEY_CAPS_LOCK);
39+
40+
// Simple debounce
41+
delay(300);
42+
}
43+
}

src/HID-Project.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ extern HID_ HID;
109109
#include "HID-Tables.h"
110110

111111
// Include all HID libraries (.a linkage required to work) properly
112-
#include "AbsoluteMouse.h"
113-
#include "Consumer.h"
114-
#include "Gamepad.h"
115-
#include "System.h"
112+
//#include "AbsoluteMouse.h"
113+
//#include "Consumer.h"
114+
//#include "Gamepad.h"
115+
//#include "System.h"
116116

117117
// Include Teensy HID afterwards to overwrite key definitions if used
118118
#ifdef USE_TEENSY_KEYBOARD

src/ImprovedKeyboard.cpp

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,46 +30,58 @@ THE SOFTWARE.
3030
// Keyboard
3131

3232
static const u8 _hidReportDescriptor[] PROGMEM = {
33-
34-
// Keyboard
35-
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47
36-
0x09, 0x06, // USAGE (Keyboard)
37-
0xa1, 0x01, // COLLECTION (Application)
38-
0x85, HID_REPORTID_KEYBOARD, // REPORT_ID
39-
0x05, 0x07, // USAGE_PAGE (Keyboard)
40-
41-
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
42-
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
43-
0x15, 0x00, // LOGICAL_MINIMUM (0)
44-
0x25, 0x01, // LOGICAL_MAXIMUM (1)
45-
0x75, 0x01, // REPORT_SIZE (1)
46-
47-
0x95, 0x08, // REPORT_COUNT (8)
48-
0x81, 0x02, // INPUT (Data,Var,Abs)
49-
0x95, 0x01, // REPORT_COUNT (1)
50-
0x75, 0x08, // REPORT_SIZE (8)
51-
0x81, 0x03, // INPUT (Cnst,Var,Abs)
52-
53-
0x95, 0x06, // REPORT_COUNT (6)
54-
0x75, 0x08, // REPORT_SIZE (8)
55-
0x15, 0x00, // LOGICAL_MINIMUM (0)
56-
0x25, 0x65, // LOGICAL_MAXIMUM (101)
57-
0x05, 0x07, // USAGE_PAGE (Keyboard)
58-
59-
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
60-
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
61-
0x81, 0x00, // INPUT (Data,Ary,Abs)
62-
0xc0, // END_COLLECTION
33+
// Keyboard
34+
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) 47 */
35+
0x09, 0x06, /* USAGE (Keyboard) */
36+
0xa1, 0x01, /* COLLECTION (Application) */
37+
0x85, HID_REPORTID_KEYBOARD, /* REPORT_ID */
38+
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
39+
40+
/* Keyboard Modifiers (shift, alt, ...) */
41+
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
42+
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
43+
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
44+
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
45+
0x75, 0x01, /* REPORT_SIZE (1) */
46+
0x95, 0x08, /* REPORT_COUNT (8) */
47+
0x81, 0x02, /* INPUT (Data,Var,Abs) */
48+
49+
/* Reserved byte */
50+
0x95, 0x01, /* REPORT_COUNT (1) */
51+
0x75, 0x08, /* REPORT_SIZE (8) */
52+
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
53+
54+
/* 5 LEDs for num lock etc */
55+
0x05, 0x08, /* USAGE_PAGE (LEDs) */
56+
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
57+
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
58+
0x95, 0x05, /* REPORT_COUNT (5) */
59+
0x75, 0x01, /* REPORT_SIZE (1) */
60+
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
61+
/* Reserved 3 bits */
62+
0x95, 0x01, /* REPORT_COUNT (1) */
63+
0x75, 0x03, /* REPORT_SIZE (3) */
64+
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
65+
66+
/* 6 Keyboard keys */
67+
0x95, 0x06, /* REPORT_COUNT (6) */
68+
0x75, 0x08, /* REPORT_SIZE (8) */
69+
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
70+
0x26, 0xE7, 0x00, /* LOGICAL_MAXIMUM (231) */
71+
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
72+
0x19, 0x00, /* USAGE_MINIMUM (Reserved (no event indicated)) */
73+
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
74+
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
75+
76+
/* End */
77+
0xc0 /* END_COLLECTION */
6378
};
6479

65-
Keyboard_::Keyboard_(void)
80+
Keyboard_::Keyboard_(void) :
81+
HIDDevice((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor), HID_REPORTID_KEYBOARD),
82+
leds(0)
6683
{
67-
static HID_Descriptor cb = {
68-
.length = sizeof(_hidReportDescriptor),
69-
.descriptor = _hidReportDescriptor,
70-
};
71-
static HIDDescriptorListNode node(&cb);
72-
HID.AppendDescriptor(&node);
84+
// HID Descriptor is appended via the inherited HIDDevice class
7385
}
7486

7587
void Keyboard_::begin(void)
@@ -82,9 +94,22 @@ void Keyboard_::end(void)
8294

8395
void Keyboard_::sendReport(HID_KeyboardReport_Data_t* keys)
8496
{
85-
HID.SendReport(HID_REPORTID_KEYBOARD,keys,sizeof(HID_KeyboardReport_Data_t));
97+
// Call the inherited function.
98+
// This wrapper still saves us some bytes
99+
SendReport(keys,sizeof(HID_KeyboardReport_Data_t));
100+
}
101+
102+
void Keyboard_::setReportData(const void* data, int len){
103+
// Save led state
104+
if(len == 1)
105+
leds = *(uint8_t*)data;
86106
}
87107

108+
uint8_t Keyboard_::getLeds(void){
109+
return leds;
110+
}
111+
112+
88113
// press() adds the specified key (printing, non-printing, or modifier)
89114
// to the persistent key report and sends the report. Because of the way
90115
// USB HID works, the host acts like the key remains pressed until we

src/ImprovedKeyboard.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ THE SOFTWARE.
3636
// Keyboard
3737

3838
#include "HID-Project.h"
39+
#include "PluggableHID/HIDDevice.h"
3940
#include "ImprovedKeylayouts.h"
4041

4142
// Low level key report: up to 6 keys and shift, ctrl etc at once
@@ -51,11 +52,13 @@ typedef union{
5152
};
5253
} HID_KeyboardReport_Data_t;
5354

54-
class Keyboard_ : public Print
55+
class Keyboard_ : public Print, public HIDDevice
5556
{
5657
private:
5758
HID_KeyboardReport_Data_t _keyReport;
5859
void sendReport(HID_KeyboardReport_Data_t* keys);
60+
virtual void setReportData(const void* data, int len);
61+
uint8_t leds;
5962
public:
6063
Keyboard_(void);
6164
void begin(void);
@@ -70,6 +73,8 @@ class Keyboard_ : public Print
7073
size_t releaseKeycode(uint8_t k);
7174
size_t addKeycodeToReport(uint8_t k);
7275
size_t removeKeycodeFromReport(uint8_t k);
76+
77+
uint8_t getLeds(void);
7378
};
7479
extern Keyboard_ Keyboard;
7580

src/ImprovedKeylayouts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ THE SOFTWARE.
7979
#define KEY_RIGHT_WINDOWS KEY_RIGHT_GUI
8080
#define KEY_PRINTSCREEN KEY_PRINT
8181

82-
// TODO implement Leds
82+
// Keyboard Leds
8383
#define LED_NUM_LOCK 0x01
8484
#define LED_CAPS_LOCK 0x02
8585
#define LED_SCROLL_LOCK 0x04

src/PluggableHID/HID.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "PluggableUSB.h"
2020
#include "HID.h"
21+
#include "HIDDevice.h"
2122

2223
#if defined(USBCON)
2324

@@ -42,7 +43,7 @@ static u8 HID_INTERFACE;
4243

4344
HIDDescriptor _hidInterface;
4445

45-
static HIDDescriptorListNode* rootNode = NULL;
46+
static HIDDevice* rootDevice = NULL;
4647
static uint16_t sizeof_hidReportDescriptor = 0;
4748
static uint8_t modules_count = 0;
4849
//================================================================================
@@ -67,10 +68,10 @@ int HID_GetInterface(u8* interfaceNum)
6768
int HID_GetDescriptor(int8_t t)
6869
{
6970
if (HID_REPORT_DESCRIPTOR_TYPE == t) {
70-
HIDDescriptorListNode* current = rootNode;
71+
HIDDevice* current = rootDevice;
7172
int total = 0;
7273
while(current != NULL) {
73-
total += USB_SendControl(TRANSFER_PGM,current->cb->descriptor,current->cb->length);
74+
total += USB_SendControl(TRANSFER_PGM,current->descriptorData,current->descriptorLength);
7475
current = current->next;
7576
}
7677
return total;
@@ -79,19 +80,19 @@ int HID_GetDescriptor(int8_t t)
7980
}
8081
}
8182

82-
void HID_::AppendDescriptor(HIDDescriptorListNode *node)
83+
void HID_::AppendDescriptor(HIDDevice *device)
8384
{
8485
if (modules_count == 0) {
85-
rootNode = node;
86+
rootDevice = device;
8687
} else {
87-
HIDDescriptorListNode *current = rootNode;
88+
HIDDevice *current = rootDevice;
8889
while(current->next != NULL) {
8990
current = current->next;
9091
}
91-
current->next = node;
92+
current->next = device;
9293
}
9394
modules_count++;
94-
sizeof_hidReportDescriptor += (uint16_t)node->cb->length;
95+
sizeof_hidReportDescriptor += (uint16_t)device->descriptorLength;
9596
}
9697

9798
void HID_::SendReport(u8 id, const void* data, int len)
@@ -100,7 +101,7 @@ void HID_::SendReport(u8 id, const void* data, int len)
100101
USB_Send(HID_TX | TRANSFER_RELEASE,data,len);
101102
}
102103

103-
bool HID_Setup(USBSetup& setup, u8 i)
104+
bool HID_::HID_Setup(USBSetup& setup, u8 i)
104105
{
105106
if (HID_INTERFACE != i) {
106107
return false;
@@ -134,6 +135,35 @@ bool HID_Setup(USBSetup& setup, u8 i)
134135
_hid_idle = setup.wValueL;
135136
return true;
136137
}
138+
139+
if (HID_SET_REPORT == r)
140+
{
141+
// Get reportID and search for the suited HIDDevice
142+
uint8_t ID = setup.wIndex;
143+
HIDDevice *current = rootDevice;
144+
while(current != NULL)
145+
{
146+
// TODO implementation for non reportID HID devices
147+
// This would could make rawHID work. reportID 0 could be used as indicator
148+
if(current->reportID == ID)
149+
{
150+
// Get the data length information and the corresponding bytes
151+
uint8_t length = setup.wLength;
152+
uint8_t data[length];
153+
USB_RecvControl(data, length);
154+
155+
// Skip report ID data
156+
current->setReportData(data+1, length-1);
157+
158+
// Dont search any further
159+
break;
160+
}
161+
current = current->next;
162+
}
163+
//TODO return true??
164+
// https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/USBCore.cpp#L613-L618
165+
return true;
166+
}
137167
}
138168
return false;
139169
}
@@ -146,7 +176,7 @@ HID_::HID_(void)
146176
endpointType[0] = EP_TYPE_INTERRUPT_IN;
147177

148178
static PUSBCallbacks cb = {
149-
.setup = &HID_Setup,
179+
.setup = HID_Setup,
150180
.getInterface = &HID_GetInterface,
151181
.getDescriptor = &HID_GetDescriptor,
152182
.numEndpoints = 1,

src/PluggableHID/HID.h

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2020
*/
2121

22-
#ifndef HID_h
22+
#pragma once
23+
2324
#define HID_h
2425

2526
#include <stdint.h>
@@ -44,25 +45,17 @@
4445
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
4546
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
4647

47-
typedef struct __attribute__((packed)) {
48-
uint16_t length;
49-
const void* descriptor;
50-
} HID_Descriptor;
51-
52-
class HIDDescriptorListNode {
53-
public:
54-
HIDDescriptorListNode *next = NULL;
55-
const HID_Descriptor * cb;
56-
HIDDescriptorListNode(const HID_Descriptor *ncb) {cb = ncb;}
57-
};
48+
class HIDDevice;
5849

5950
class HID_
6051
{
6152
public:
6253
HID_(void);
6354
int begin(void);
6455
void SendReport(uint8_t id, const void* data, int len);
65-
void AppendDescriptor(HIDDescriptorListNode* node);
56+
void AppendDescriptor(HIDDevice* device);
57+
private:
58+
static bool HID_Setup(USBSetup& setup, u8 i);
6659
};
6760

6861
typedef struct
@@ -93,6 +86,3 @@ typedef struct
9386
#define WEAK __attribute__ ((weak))
9487

9588
#endif
96-
97-
#endif
98-

0 commit comments

Comments
 (0)