-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathKeyboardReporter.cpp
156 lines (137 loc) · 4.63 KB
/
KeyboardReporter.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "MicroBitConfig.h"
#if CONFIG_ENABLED(DEVICE_BLE)
#include "KeyboardReporter.h"
#include "ascii2scan.h"
#include "debug.h"
const int SHIFT_MASK = 0x02;
// Copied from https://docs.silabs.com/bluetooth/2.13/code-examples/applications/ble-hid-keyboard
// Actually: https://docs.silabs.com/resources/bluetooth/code-examples/applications/ble-hid-keyboard/source/gatt.xml
// This is 45 bytes
static const uint8_t keyboardReportMap[] =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xa1, 0x01, // Collection (Application)
0x85, 0x00, // Report ID OFFSET: 7
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) Reserved byte
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) = Above codes are bit mapped to the first byte
0x81, 0x02, // Input (Data, Variable, Absolute) Modifier byte
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0x00, // Usage Minimum (Reserved (no event indicated))
0x29, 0x65, // Usage Maximum (Keyboard Application)
0x81, 0x00, // Input (Data,Array) Key arrays (6 bytes)
0xc0, // End Collection
};
KeyboardReporter *KeyboardReporter::reporter = NULL; // Singleton reference to the service
/**
*/
KeyboardReporter *KeyboardReporter::getInstance()
{
if (reporter == NULL)
{
reporter = new KeyboardReporter();
}
return reporter;
}
KeyboardReporter::KeyboardReporter() :
HIDReporter("Keyboard", 8, keyboardReportMap, sizeof(keyboardReportMap), 7, 106) // Name and report size
{
}
void KeyboardReporter::sendScanCode(uint8_t c, uint8_t modifiers) {
memset(report, 0, reportSize);
if(c) {
report[0] = modifiers;
report[1] = modifiers;
report[3] = c;
}
sendReport();
}
void KeyboardReporter::sendSimultaneousKeys(char *str, int len) {
uint8_t modifiers = 0;
memset(report, 0, reportSize);
int idx = 2; // Report index
// Process the string / build the report
for(int i=0; i<len && idx<reportSize; i++) {
char c = str[i];
// Check for modifiers
if(c>=1 && c<=8) {
modifiers |= 1<<(c-1);
// Check for direct scan code
} else if(c==0x10) {
i++; // Advance to next character if valid
if(i<len) {
report[idx++] = str[i];
}
// Regular ASCII character
} else if(c>=' ') {
uint16_t full = ascii2scan(c);
modifiers |= (full>>8) ? SHIFT_MASK : 0;
report[idx++] = full & 0xFF;
}
}
report[0] = modifiers; // iOS Hack
report[1] = modifiers; // Invalid char / ignored in iOS
sendReport();
}
void KeyboardReporter::sendString(char *str, int len) {
uint8_t lastCode = 0;
// Iterate over keys and send them
// DEBUG("Keys: ");
uint8_t shift = 0;
uint8_t code = 0;
for(int i=0; i<len; i++) {
char c = str[i];
if(c >= ' ') { // ASCII character: Get scancode details
uint16_t full = ascii2scan(c);
shift = (full>>8) ? SHIFT_MASK : 0;
code = full & 0xFF;
// Send blank when repeated keys or just a change in modifier
if(code == lastCode) {
sendScanCode(0, 0);
}
sendScanCode(code, shift);
} else {
// Handle control codes
uint8_t modifiers = 0;
while(str[i]>=1 && str[i]<=8 && i<len) {
modifiers |= 1<<(str[i]-1);
i++;
}
if(i<len) {
// Check for raw scancode
if(str[i]==0x10) {
if(i+1<len) {
i++;
code = str[i];
} else {
code = 0; // Scancode expected, but not there. Default to nothing.
}
} else {
uint16_t full = ascii2scan(str[i]);
modifiers |= (full>>8) ? SHIFT_MASK : 0;
code = full & 0xFF;
}
i++;
sendScanCode(code, modifiers);
}
}
lastCode = code;
// DEBUG("%c (%d%d)",str[i], shift, code);
}
// Send final release
sendScanCode(0, 0);
// DEBUG("\n");
}
#endif