Added Keyboard.pressRaw(), releaseRaw() and writeRaw() to make it possible to send other keys than just ASCII

pull/18/head
Michael Dreher 12 years ago committed by Jesse Vincent
parent 3778bdaf66
commit d2d1d1b4a6

@ -90,6 +90,7 @@ const u8 _hidReportDescriptor[] = {
0x85, HID_REPORTID_KEYBOARD, // REPORT_ID (2)
0x05, 0x07, // USAGE_PAGE (Keyboard)
// Keyboard Modifiers (shift, alt, ...)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
@ -102,14 +103,14 @@ const u8 _hidReportDescriptor[] = {
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
// Keyboard keys
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x26, 0xDF, 0x00, // LOGICAL_MAXIMUM (239)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x29, 0xDF, // USAGE_MAXIMUM (Left Control - 1)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0, // END_COLLECTION
@ -571,9 +572,33 @@ uint8_t USBPutChar(uint8_t c);
// to the persistent key report and sends the report. Because of the way
// USB HID works, the host acts like the key remains pressed until we
// call release(), releaseAll(), or otherwise clear the report and resend.
size_t Keyboard_::press(uint8_t k)
size_t Keyboard_::pressRaw(uint8_t k)
{
uint8_t i;
// Add k to the key report only if it's not already present
// and if there is an empty slot.
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
for (i=0; i<6; i++) {
if (_keyReport.keys[i] == 0x00) {
_keyReport.keys[i] = k;
break;
}
}
if (i == 6 || (k >= 0xE0)) {
setWriteError();
return 0;
}
}
sendReport(&_keyReport);
return 1;
}
// translates ASCII characters to usage
size_t Keyboard_::press(uint8_t k)
{
if (k >= 136) { // it's a non-printing key (not a modifier)
k = k - 136;
} else if (k >= 128) { // it's a modifier key
@ -590,28 +615,48 @@ size_t Keyboard_::press(uint8_t k)
k &= 0x7F;
}
}
// Add k to the key report only if it's not already present
// and if there is an empty slot.
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
for (i=0; i<6; i++) {
if (_keyReport.keys[i] == 0x00) {
_keyReport.keys[i] = k;
break;
}
return pressRaw(k);
}
// release() takes the specified key out of the persistent key report and
// sends the report. This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t Keyboard_::releaseRaw(uint8_t k)
{
uint8_t i;
// Test the key report to see if k is present. Clear it if it exists.
// Check all positions in case the key is present more than once (which it shouldn't be)
for (i=0; i<6; i++) {
if (0 != k && _keyReport.keys[i] == k) {
_keyReport.keys[i] = 0x00;
}
if (i == 6) {
setWriteError();
return 0;
}
}
sendReport(&_keyReport);
return 1;
}
// translates ASCII characters to usage
size_t Keyboard_::release(uint8_t k)
{
if (k >= 136) { // it's a non-printing key (not a modifier)
k = k - 136;
} else if (k >= 128) { // it's a modifier key
_keyReport.modifiers &= ~(1<<(k-128));
k = 0;
} else { // it's a printing key
k = pgm_read_byte(_asciimap + k);
if (!k) {
return 0;
}
if (k & 0x80) { // it's a capital letter or other character reached with shift
_keyReport.modifiers &= ~(0x02); // the left shift modifier
k &= 0x7F;
}
}
return releaseRaw(k);
}
// System Control
// k is one of the SYSTEM_CONTROL defines which come from the HID usage table "Generic Desktop Page (0x01)"
// in "HID Usage Tables" (HUT1_12v2.pdf)
@ -644,40 +689,6 @@ size_t Keyboard_::systemControl(uint8_t k)
}
}
// release() takes the specified key out of the persistent key report and
// sends the report. This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t Keyboard_::release(uint8_t k)
{
uint8_t i;
if (k >= 136) { // it's a non-printing key (not a modifier)
k = k - 136;
} else if (k >= 128) { // it's a modifier key
_keyReport.modifiers &= ~(1<<(k-128));
k = 0;
} else { // it's a printing key
k = pgm_read_byte(_asciimap + k);
if (!k) {
return 0;
}
if (k & 0x80) { // it's a capital letter or other character reached with shift
_keyReport.modifiers &= ~(0x02); // the left shift modifier
k &= 0x7F;
}
}
// Test the key report to see if k is present. Clear it if it exists.
// Check all positions in case the key is present more than once (which it shouldn't be)
for (i=0; i<6; i++) {
if (0 != k && _keyReport.keys[i] == k) {
_keyReport.keys[i] = 0x00;
}
}
sendReport(&_keyReport);
return 1;
}
void Keyboard_::releaseAll(void)
{
_keyReport.keys[0] = 0;
@ -690,10 +701,17 @@ void Keyboard_::releaseAll(void)
sendReport(&_keyReport);
}
size_t Keyboard_::writeRaw(uint8_t c)
{
uint8_t p = pressRaw(c); // Keydown
releaseRaw(c); // Keyup
return (p); // just return the result of press() since release() almost always returns 1
}
size_t Keyboard_::write(uint8_t c)
{
uint8_t p = press(c); // Keydown
uint8_t r = release(c); // Keyup
release(c); // Keyup
return (p); // just return the result of press() since release() almost always returns 1
}

@ -155,8 +155,11 @@ public:
void begin(void);
void end(void);
virtual size_t write(uint8_t k);
virtual size_t writeRaw(uint8_t c);
virtual size_t press(uint8_t k);
virtual size_t pressRaw(uint8_t k);
virtual size_t release(uint8_t k);
virtual size_t releaseRaw(uint8_t k);
virtual void releaseAll(void);
virtual size_t systemControl(uint8_t k);
};

@ -24,13 +24,13 @@
#if defined(USBCON)
#define EP_TYPE_CONTROL 0x00
#define EP_TYPE_BULK_IN 0x81
#define EP_TYPE_BULK_OUT 0x80
#define EP_TYPE_INTERRUPT_IN 0xC1
#define EP_TYPE_INTERRUPT_OUT 0xC0
#define EP_TYPE_ISOCHRONOUS_IN 0x41
#define EP_TYPE_ISOCHRONOUS_OUT 0x40
#define EP_TYPE_CONTROL (0x00)
#define EP_TYPE_BULK_IN ((1<<EPTYPE1) | (1<<EPDIR))
#define EP_TYPE_BULK_OUT (1<<EPTYPE1)
#define EP_TYPE_INTERRUPT_IN ((1<<EPTYPE1) | (1<<EPTYPE0) | (1<<EPDIR))
#define EP_TYPE_INTERRUPT_OUT ((1<<EPTYPE1) | (1<<EPTYPE0))
#define EP_TYPE_ISOCHRONOUS_IN ((1<<EPTYPE0) | (1<<EPDIR))
#define EP_TYPE_ISOCHRONOUS_OUT (1<<EPTYPE0)
/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
#define TX_RX_LED_PULSE_MS 100
@ -344,7 +344,7 @@ static
void InitEP(u8 index, u8 type, u8 size)
{
UENUM = index;
UECONX = 1;
UECONX = (1<<EPEN);
UECFG0X = type;
UECFG1X = size;
}
@ -355,7 +355,7 @@ void InitEndpoints()
for (u8 i = 1; i < sizeof(_initEndpoints); i++)
{
UENUM = i;
UECONX = 1;
UECONX = (1<<EPEN);
UECFG0X = pgm_read_byte(_initEndpoints+i);
UECFG1X = EP_DOUBLE_64;
}
@ -627,11 +627,33 @@ static inline void USB_ClockEnable()
{
UHWCON |= (1<<UVREGE); // power internal reg
USBCON = (1<<USBE) | (1<<FRZCLK); // clock frozen, usb enabled
// ATmega32U4
#if defined(PINDIV)
#if F_CPU == 16000000UL
PLLCSR |= (1<<PINDIV); // Need 16 MHz xtal
#elif F_CPU == 8000000UL
PLLCSR &= ~(1<<PINDIV); // Need 8 MHz xtal
#endif
// AT90USB646, AT90USB647, AT90USB1286, AT90USB1287
#elif defined(PLLP2)
#if F_CPU == 16000000UL
PLLCSR = (1<<PINDIV); // Need 16 MHz xtal
#if defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
// For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x.
PLLCSR = (PLLCSR & ~(1<<PLLP1)) | ((1<<PLLP2) | (1<<PLLP0)); // Need 16 MHz xtal
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
// For AT90USB64x only. Do not use with AT90USB128x.
PLLCSR = (PLLCSR & ~(1<<PLLP0)) | ((1<<PLLP2) | (1<<PLLP1)); // Need 16 MHz xtal
#else
#error "USB Chip not supported, please defined method of PLL initialization yourself"
#endif
#elif F_CPU == 8000000UL
PLLCSR = 0x00; // Need 8 MHz xtal
// for Atmel AT90USB128x and AT90USB64x
PLLCSR = (PLLCSR & ~(1<<PLLP2)) | ((1<<PLLP1) | (1<<PLLP0)); // Need 8 MHz xtal
#endif
#endif
PLLCSR |= (1<<PLLE);
while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll
{
@ -642,7 +664,13 @@ static inline void USB_ClockEnable()
// port touch at 1200 bps. This delay fixes this behaviour.
delay(1);
USBCON = (USBCON & ~(1<<FRZCLK)) | (1<<OTGPADE); // start USB clock, enable VBUS Pad
#if defined(RSTCPU)
UDCON &= ~((1<<RSTCPU) | (1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode
#else
// AT90USB64x and AT90USB128x don't have RSTCPU
UDCON &= ~((1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode
#endif
}

Loading…
Cancel
Save