Skip to content

Commit 5456707

Browse files
committed
Added Keyboard.pressRaw(), releaseRaw() and writeRaw() to make it possible to send other keys than just ASCII
1 parent 781181e commit 5456707

File tree

3 files changed

+115
-66
lines changed

3 files changed

+115
-66
lines changed

hardware/arduino/cores/arduino/HID.cpp

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const u8 _hidReportDescriptor[] = {
8989
0x85, HID_REPORTID_KEYBOARD, // REPORT_ID (2)
9090
0x05, 0x07, // USAGE_PAGE (Keyboard)
9191

92+
// Keyboard Modifiers (shift, alt, ...)
9293
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
9394
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
9495
0x15, 0x00, // LOGICAL_MINIMUM (0)
@@ -101,14 +102,14 @@ const u8 _hidReportDescriptor[] = {
101102
0x75, 0x08, // REPORT_SIZE (8)
102103
0x81, 0x03, // INPUT (Cnst,Var,Abs)
103104

105+
// Keyboard keys
104106
0x95, 0x06, // REPORT_COUNT (6)
105107
0x75, 0x08, // REPORT_SIZE (8)
106108
0x15, 0x00, // LOGICAL_MINIMUM (0)
107-
0x25, 0x65, // LOGICAL_MAXIMUM (101)
109+
0x26, 0xDF, 0x00, // LOGICAL_MAXIMUM (239)
108110
0x05, 0x07, // USAGE_PAGE (Keyboard)
109-
110111
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
111-
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
112+
0x29, 0xDF, // USAGE_MAXIMUM (Left Control - 1)
112113
0x81, 0x00, // INPUT (Data,Ary,Abs)
113114
0xc0, // END_COLLECTION
114115

@@ -457,9 +458,33 @@ uint8_t USBPutChar(uint8_t c);
457458
// to the persistent key report and sends the report. Because of the way
458459
// USB HID works, the host acts like the key remains pressed until we
459460
// call release(), releaseAll(), or otherwise clear the report and resend.
460-
size_t Keyboard_::press(uint8_t k)
461+
size_t Keyboard_::pressRaw(uint8_t k)
461462
{
462463
uint8_t i;
464+
// Add k to the key report only if it's not already present
465+
// and if there is an empty slot.
466+
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
467+
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
468+
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
469+
470+
for (i=0; i<6; i++) {
471+
if (_keyReport.keys[i] == 0x00) {
472+
_keyReport.keys[i] = k;
473+
break;
474+
}
475+
}
476+
if (i == 6 || (k >= 0xE0)) {
477+
setWriteError();
478+
return 0;
479+
}
480+
}
481+
sendReport(&_keyReport);
482+
return 1;
483+
}
484+
485+
// translates ASCII characters to usage
486+
size_t Keyboard_::press(uint8_t k)
487+
{
463488
if (k >= 136) { // it's a non-printing key (not a modifier)
464489
k = k - 136;
465490
} else if (k >= 128) { // it's a modifier key
@@ -476,28 +501,48 @@ size_t Keyboard_::press(uint8_t k)
476501
k &= 0x7F;
477502
}
478503
}
479-
480-
// Add k to the key report only if it's not already present
481-
// and if there is an empty slot.
482-
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
483-
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
484-
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
485-
486-
for (i=0; i<6; i++) {
487-
if (_keyReport.keys[i] == 0x00) {
488-
_keyReport.keys[i] = k;
489-
break;
490-
}
504+
return pressRaw(k);
505+
}
506+
507+
// release() takes the specified key out of the persistent key report and
508+
// sends the report. This tells the OS the key is no longer pressed and that
509+
// it shouldn't be repeated any more.
510+
size_t Keyboard_::releaseRaw(uint8_t k)
511+
{
512+
uint8_t i;
513+
// Test the key report to see if k is present. Clear it if it exists.
514+
// Check all positions in case the key is present more than once (which it shouldn't be)
515+
for (i=0; i<6; i++) {
516+
if (0 != k && _keyReport.keys[i] == k) {
517+
_keyReport.keys[i] = 0x00;
491518
}
492-
if (i == 6) {
493-
setWriteError();
494-
return 0;
495-
}
496519
}
520+
497521
sendReport(&_keyReport);
498522
return 1;
499523
}
500524

525+
// translates ASCII characters to usage
526+
size_t Keyboard_::release(uint8_t k)
527+
{
528+
if (k >= 136) { // it's a non-printing key (not a modifier)
529+
k = k - 136;
530+
} else if (k >= 128) { // it's a modifier key
531+
_keyReport.modifiers &= ~(1<<(k-128));
532+
k = 0;
533+
} else { // it's a printing key
534+
k = pgm_read_byte(_asciimap + k);
535+
if (!k) {
536+
return 0;
537+
}
538+
if (k & 0x80) { // it's a capital letter or other character reached with shift
539+
_keyReport.modifiers &= ~(0x02); // the left shift modifier
540+
k &= 0x7F;
541+
}
542+
}
543+
return releaseRaw(k);
544+
}
545+
501546
// System Control
502547
// k is one of the SYSTEM_CONTROL defines which come from the HID usage table "Generic Desktop Page (0x01)"
503548
// in "HID Usage Tables" (HUT1_12v2.pdf)
@@ -530,40 +575,6 @@ size_t Keyboard_::systemControl(uint8_t k)
530575
}
531576
}
532577

533-
// release() takes the specified key out of the persistent key report and
534-
// sends the report. This tells the OS the key is no longer pressed and that
535-
// it shouldn't be repeated any more.
536-
size_t Keyboard_::release(uint8_t k)
537-
{
538-
uint8_t i;
539-
if (k >= 136) { // it's a non-printing key (not a modifier)
540-
k = k - 136;
541-
} else if (k >= 128) { // it's a modifier key
542-
_keyReport.modifiers &= ~(1<<(k-128));
543-
k = 0;
544-
} else { // it's a printing key
545-
k = pgm_read_byte(_asciimap + k);
546-
if (!k) {
547-
return 0;
548-
}
549-
if (k & 0x80) { // it's a capital letter or other character reached with shift
550-
_keyReport.modifiers &= ~(0x02); // the left shift modifier
551-
k &= 0x7F;
552-
}
553-
}
554-
555-
// Test the key report to see if k is present. Clear it if it exists.
556-
// Check all positions in case the key is present more than once (which it shouldn't be)
557-
for (i=0; i<6; i++) {
558-
if (0 != k && _keyReport.keys[i] == k) {
559-
_keyReport.keys[i] = 0x00;
560-
}
561-
}
562-
563-
sendReport(&_keyReport);
564-
return 1;
565-
}
566-
567578
void Keyboard_::releaseAll(void)
568579
{
569580
_keyReport.keys[0] = 0;
@@ -576,10 +587,17 @@ void Keyboard_::releaseAll(void)
576587
sendReport(&_keyReport);
577588
}
578589

590+
size_t Keyboard_::writeRaw(uint8_t c)
591+
{
592+
uint8_t p = pressRaw(c); // Keydown
593+
releaseRaw(c); // Keyup
594+
return (p); // just return the result of press() since release() almost always returns 1
595+
}
596+
579597
size_t Keyboard_::write(uint8_t c)
580598
{
581599
uint8_t p = press(c); // Keydown
582-
uint8_t r = release(c); // Keyup
600+
release(c); // Keyup
583601
return (p); // just return the result of press() since release() almost always returns 1
584602
}
585603

hardware/arduino/cores/arduino/USBAPI.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,11 @@ class Keyboard_ : public Print
154154
void begin(void);
155155
void end(void);
156156
virtual size_t write(uint8_t k);
157+
virtual size_t writeRaw(uint8_t c);
157158
virtual size_t press(uint8_t k);
159+
virtual size_t pressRaw(uint8_t k);
158160
virtual size_t release(uint8_t k);
161+
virtual size_t releaseRaw(uint8_t k);
159162
virtual void releaseAll(void);
160163
virtual size_t systemControl(uint8_t k);
161164
};

hardware/arduino/cores/arduino/USBCore.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424

2525
#if defined(USBCON)
2626

27-
#define EP_TYPE_CONTROL 0x00
28-
#define EP_TYPE_BULK_IN 0x81
29-
#define EP_TYPE_BULK_OUT 0x80
30-
#define EP_TYPE_INTERRUPT_IN 0xC1
31-
#define EP_TYPE_INTERRUPT_OUT 0xC0
32-
#define EP_TYPE_ISOCHRONOUS_IN 0x41
33-
#define EP_TYPE_ISOCHRONOUS_OUT 0x40
27+
#define EP_TYPE_CONTROL (0x00)
28+
#define EP_TYPE_BULK_IN ((1<<EPTYPE1) | (1<<EPDIR))
29+
#define EP_TYPE_BULK_OUT (1<<EPTYPE1)
30+
#define EP_TYPE_INTERRUPT_IN ((1<<EPTYPE1) | (1<<EPTYPE0) | (1<<EPDIR))
31+
#define EP_TYPE_INTERRUPT_OUT ((1<<EPTYPE1) | (1<<EPTYPE0))
32+
#define EP_TYPE_ISOCHRONOUS_IN ((1<<EPTYPE0) | (1<<EPDIR))
33+
#define EP_TYPE_ISOCHRONOUS_OUT (1<<EPTYPE0)
3434

3535
/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
3636
#define TX_RX_LED_PULSE_MS 100
@@ -344,7 +344,7 @@ static
344344
void InitEP(u8 index, u8 type, u8 size)
345345
{
346346
UENUM = index;
347-
UECONX = 1;
347+
UECONX = (1<<EPEN);
348348
UECFG0X = type;
349349
UECFG1X = size;
350350
}
@@ -355,7 +355,7 @@ void InitEndpoints()
355355
for (u8 i = 1; i < sizeof(_initEndpoints); i++)
356356
{
357357
UENUM = i;
358-
UECONX = 1;
358+
UECONX = (1<<EPEN);
359359
UECFG0X = pgm_read_byte(_initEndpoints+i);
360360
UECFG1X = EP_DOUBLE_64;
361361
}
@@ -627,11 +627,33 @@ static inline void USB_ClockEnable()
627627
{
628628
UHWCON |= (1<<UVREGE); // power internal reg
629629
USBCON = (1<<USBE) | (1<<FRZCLK); // clock frozen, usb enabled
630+
631+
// ATmega32U4
632+
#if defined(PINDIV)
633+
#if F_CPU == 16000000UL
634+
PLLCSR |= (1<<PINDIV); // Need 16 MHz xtal
635+
#elif F_CPU == 8000000UL
636+
PLLCSR &= ~(1<<PINDIV); // Need 8 MHz xtal
637+
#endif
638+
639+
// AT90USB646, AT90USB647, AT90USB1286, AT90USB1287
640+
#elif defined(PLLP2)
630641
#if F_CPU == 16000000UL
631-
PLLCSR = (1<<PINDIV); // Need 16 MHz xtal
642+
#if defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
643+
// For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x.
644+
PLLCSR = (PLLCSR & ~(1<<PLLP1)) | ((1<<PLLP2) | (1<<PLLP0)); // Need 16 MHz xtal
645+
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
646+
// For AT90USB64x only. Do not use with AT90USB128x.
647+
PLLCSR = (PLLCSR & ~(1<<PLLP0)) | ((1<<PLLP2) | (1<<PLLP1)); // Need 16 MHz xtal
648+
#else
649+
#error "USB Chip not supported, please defined method of PLL initialization yourself"
650+
#endif
632651
#elif F_CPU == 8000000UL
633-
PLLCSR = 0x00; // Need 8 MHz xtal
652+
// for Atmel AT90USB128x and AT90USB64x
653+
PLLCSR = (PLLCSR & ~(1<<PLLP2)) | ((1<<PLLP1) | (1<<PLLP0)); // Need 8 MHz xtal
654+
#endif
634655
#endif
656+
635657
PLLCSR |= (1<<PLLE);
636658
while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll
637659
{
@@ -642,7 +664,13 @@ static inline void USB_ClockEnable()
642664
// port touch at 1200 bps. This delay fixes this behaviour.
643665
delay(1);
644666
USBCON = (USBCON & ~(1<<FRZCLK)) | (1<<OTGPADE); // start USB clock, enable VBUS Pad
667+
668+
#if defined(RSTCPU)
645669
UDCON &= ~((1<<RSTCPU) | (1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode
670+
#else
671+
// AT90USB64x and AT90USB128x don't have RSTCPU
672+
UDCON &= ~((1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode
673+
#endif
646674
}
647675

648676

0 commit comments

Comments
 (0)