diff --git a/.gitignore b/.gitignore index 79d9e76d335..7853b6484fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_STORE app/bin/ app/pde.jar build/macosx/work/ diff --git a/hardware/arduino/cores/arduino/HID.cpp b/hardware/arduino/cores/arduino/HID.cpp index ac636084493..a2fafa164d1 100644 --- a/hardware/arduino/cores/arduino/HID.cpp +++ b/hardware/arduino/cores/arduino/HID.cpp @@ -1,20 +1,20 @@ /* Copyright (c) 2011, Peter Barrett -** -** Permission to use, copy, modify, and/or distribute this software for -** any purpose with or without fee is hereby granted, provided that the -** above copyright notice and this permission notice appear in all copies. -** -** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR -** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES -** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -** SOFTWARE. -*/ + ** + ** Permission to use, copy, modify, and/or distribute this software for + ** any purpose with or without fee is hereby granted, provided that the + ** above copyright notice and this permission notice appear in all copies. + ** + ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + ** SOFTWARE. + */ #include "Platform.h" #include "USBAPI.h" @@ -75,14 +75,14 @@ const u8 _hidReportDescriptor[] = { 0x81, 0x06, // INPUT (Data,Var,Rel) 0xc0, // END_COLLECTION 0xc0, // END_COLLECTION - + // 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) @@ -105,22 +105,22 @@ const u8 _hidReportDescriptor[] = { 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0, // END_COLLECTION - + #if RAWHID_ENABLED // RAW HID 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), - + 0xA1, 0x01, // Collection 0x01 0x85, 0x03, // REPORT_ID (3) 0x75, 0x08, // report size = 8 bits 0x15, 0x00, // logical minimum = 0 0x26, 0xFF, 0x00, // logical maximum = 255 - + 0x95, 64, // report count TX 0x09, 0x01, // usage 0x81, 0x02, // Input (array) - + 0x95, 64, // report count RX 0x09, 0x02, // usage 0x91, 0x02, // Output (array) @@ -187,7 +187,7 @@ bool WEAK HID_Setup(Setup& setup) _hid_protocol = setup.wValueL; return true; } - + if (HID_SET_IDLE == r) { _hid_idle = setup.wValueL; @@ -316,7 +316,7 @@ const uint8_t _asciimap[128] = 0x00, // GS 0x00, // RS 0x00, // US - + 0x2c, // ' ' 0x1e|SHIFT, // ! 0x34|SHIFT, // " @@ -417,94 +417,173 @@ const uint8_t _asciimap[128] = uint8_t USBPutChar(uint8_t c); -// press() adds the specified key (printing, non-printing, or modifier) +// pressKeycode() adds the specified key (printing, non-printing, or modifier) // 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) +// call releaseKeycode(), releaseAll(), or otherwise clear the report and resend. +// When send is set to FALSE (= 0x00) no sendReport() is executed. This comes in +// handy when combining key presses (e.g. SHIFT+A). +size_t Keyboard_::pressKeycode(uint8_t k, uint8_t send) { - 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) { - setWriteError(); - return 0; + uint8_t index = 0x00; + uint8_t done = 0x00; + + if ((k >= KEYCODE_LEFT_CTRL) && (k <= KEYCODE_RIGHT_GUI)) { + // it's a modifier key + _keyReport.modifiers |= (0x01 << (k - KEYCODE_LEFT_CTRL)); + } else { + // it's some other key: + // Add k to the key report only if it's not already present + // and if there is an empty slot. + for (index = 0x00; index < KEYREPORT_KEYCOUNT; index++) { + if (_keyReport.keys[index] != k) { // is k already in list? + if (0x00 == _keyReport.keys[index]) { // have we found an empty slot? + _keyReport.keys[index] = k; + done = 0x01; + break; + } + } else { + done = 0x01; + break; + } + } - if (k & 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers |= 0x02; // the left shift modifier - k &= 0x7F; + + // use separate variable to check if slot was found + // for style reasons - we do not know how the compiler + // handles the for() index when it leaves the loop + if (0x00 == done) { + setWriteError(); + return 0x00; } } - // 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 (0x00 != send) { + sendReport(&_keyReport); + } + return 0x01; +} + +// press() transforms the given key to the actual keycode and calls +// pressKeycode() to actually press this key. +size_t Keyboard_::press(uint8_t k) +{ + if (k >= KEY_RIGHT_GUI + 0x01) { + // it's a non-printing key (not a modifier) + k = k - (KEY_RIGHT_GUI + 0x01); + } else { + if (k >= KEY_LEFT_CTRL) { + // it's a modifier key + k = k - KEY_LEFT_CTRL + KEYCODE_LEFT_CTRL; + } else { + k = pgm_read_byte(_asciimap + k); + if (0x00 != k) { + if (0x00 != (k & SHIFT)) { + // it's a capital letter or other character reached with shift + // the left shift modifier + pressKeycode(KEYCODE_LEFT_SHIFT, 0x00); + k = k ^ SHIFT; + } + } else { + return 0x00; } } - if (i == 6) { - setWriteError(); - return 0; - } } - sendReport(&_keyReport); - return 1; + + pressKeycode(k, 0x01); + return 0x1; } -// release() takes the specified key out of the persistent key report and +// releaseKeycode() 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) +// When send is set to FALSE (= 0x00) no sendReport() is executed. This comes in +// handy when combining key releases (e.g. SHIFT+A). +size_t Keyboard_::releaseKeycode(uint8_t k, uint8_t send) { - 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; + uint8_t indexA; + uint8_t indexB; + uint8_t count; + + if ((k >= KEYCODE_LEFT_CTRL) && (k <= KEYCODE_RIGHT_GUI)) { + // it's a modifier key + _keyReport.modifiers = _keyReport.modifiers & (~(0x01 << (k - KEYCODE_LEFT_CTRL))); + } else { + // it's some other key: + // 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 (indexA = 0x00; indexA < KEYREPORT_KEYCOUNT; indexA++) { + if (_keyReport.keys[indexA] == k) { + _keyReport.keys[indexA] = 0x00; + } } - if (k & 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers &= ~(0x02); // the left shift modifier - k &= 0x7F; + + // finally rearrange the keys list so that the free (= 0x00) are at the + // end of the keys list - some implementations stop for keys at the + // first occurence of an 0x00 in the keys list + // so (0x00)(0x01)(0x00)(0x03)(0x02)(0x00) becomes (0x01)(0x03)(0x02)(0x00)(0x00)(0x00) + count = 0x00; // holds the number of zeros we've found + indexA = 0x00; + while ((indexA + count) < KEYREPORT_KEYCOUNT) { + if (0x00 == _keyReport.keys[indexA]) { + count++; // one more zero + for (indexB = indexA; indexB < KEYREPORT_KEYCOUNT-count; indexB++) { + _keyReport.keys[indexB] = _keyReport.keys[indexB+0x01]; + } + _keyReport.keys[KEYREPORT_KEYCOUNT-count] = 0x00; + } else { + indexA++; // one more non-zero + } } + } + + if (0x00 != send) { + sendReport(&_keyReport); } + return 0x01; +} + +// release() transforms the given key to the actual keycode and calls +// releaseKeycode() to actually release this key. +size_t Keyboard_::release(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 (k >= KEY_RIGHT_GUI + 0x01) { + // it's a non-printing key (not a modifier) + k = k - (KEY_RIGHT_GUI + 0x01); + } else { + if (k >= KEY_LEFT_CTRL) { + // it's a modifier key + k = k - KEY_LEFT_CTRL + KEYCODE_LEFT_CTRL; + } else { + k = pgm_read_byte(_asciimap + k); + if (0x00 != k) { + if (0x00 != (k & SHIFT)) { + // it's a capital letter or other character reached with shift + // the left shift modifier + releaseKeycode(KEYCODE_LEFT_SHIFT, 0x00); + k = k ^ SHIFT; + } + } else { + return 0x00; + } } } - - sendReport(&_keyReport); - return 1; + + releaseKeycode(k, 0x01); + return 0x01; } void Keyboard_::releaseAll(void) { - _keyReport.keys[0] = 0; - _keyReport.keys[1] = 0; - _keyReport.keys[2] = 0; - _keyReport.keys[3] = 0; - _keyReport.keys[4] = 0; - _keyReport.keys[5] = 0; - _keyReport.modifiers = 0; + _keyReport.keys[0x00] = 0x00; + _keyReport.keys[0x01] = 0x00; + _keyReport.keys[0x02] = 0x00; + _keyReport.keys[0x03] = 0x00; + _keyReport.keys[0x04] = 0x00; + _keyReport.keys[0x05] = 0x00; + _keyReport.modifiers = 0x00; sendReport(&_keyReport); } diff --git a/hardware/arduino/cores/arduino/USBAPI.h b/hardware/arduino/cores/arduino/USBAPI.h index eb2e5937db0..cb3e27de880 100644 --- a/hardware/arduino/cores/arduino/USBAPI.h +++ b/hardware/arduino/cores/arduino/USBAPI.h @@ -14,7 +14,7 @@ class USBDevice_ public: USBDevice_(); bool configured(); - + void attach(); void detach(); // Serial port goes down too... void poll(); @@ -32,7 +32,7 @@ class Serial_ : public Stream public: void begin(uint16_t baud_count); void end(void); - + virtual int available(void); virtual void accept(void); virtual int peek(void); @@ -74,6 +74,98 @@ extern Mouse_ Mouse; //================================================================================ // Keyboard +// USB HID based keycodes +// as taken from: http://www.usb.org/developers/devclass_docs/Hut1_11.pdf +#define KEYCODE_LEFT_CTRL 0xE0 +#define KEYCODE_LEFT_SHIFT 0xE1 +#define KEYCODE_LEFT_ALT 0xE2 +#define KEYCODE_LEFT_GUI 0xE3 +#define KEYCODE_RIGHT_CTRL 0xE4 +#define KEYCODE_RIGHT_SHIFT 0xE5 +#define KEYCODE_RIGHT_ALT 0xE6 +#define KEYCODE_RIGHT_GUI 0xE7 + +#define KEYCODE_UP_ARROW 0x52 +#define KEYCODE_DOWN_ARROW 0x51 +#define KEYCODE_LEFT_ARROW 0x50 +#define KEYCODE_RIGHT_ARROW 0x4F +#define KEYCODE_BACKSPACE 0x2A +#define KEYCODE_TAB 0x2B +#define KEYCODE_RETURN 0x28 +#define KEYCODE_ESC 0x29 +#define KEYCODE_INSERT 0x49 +#define KEYCODE_DELETE 0xD4 +#define KEYCODE_PAGE_UP 0x4B +#define KEYCODE_PAGE_DOWN 0x4E +#define KEYCODE_HOME 0x4A +#define KEYCODE_END 0x4D +#define KEYCODE_CAPS_LOCK 0x39 +#define KEYCODE_F1 0x3A +#define KEYCODE_F2 0x3B +#define KEYCODE_F3 0x3C +#define KEYCODE_F4 0x3D +#define KEYCODE_F5 0x3E +#define KEYCODE_F6 0x3F +#define KEYCODE_F7 0x40 +#define KEYCODE_F8 0x41 +#define KEYCODE_F9 0x42 +#define KEYCODE_F10 0x43 +#define KEYCODE_F11 0x44 +#define KEYCODE_F12 0x45 + +#define KEYCODE_ENTER KEYCODE_RETURN +#define KEYCODE_SPACEBAR 0x2C +#define KEYCODE_PRINT_SCREEN 0x46 +#define KEYCODE_SCROLL_LOCK 0x47 +#define KEYCODE_PAUSE 0x48 +#define KEYCODE_KEYPAD_NUM_LOCK 0x53 +#define KEYCODE_KEYPAD_RETURN 0x58 +#define KEYCODE_KEYPAD_ENTER KEYCODE_KEYPAD_RETURN +#define KEYCODE_KEYPAD_END 0x59 +#define KEYCODE_KEYPAD_DOWN_ARROW 0x5A +#define KEYCODE_KEYPAD_PAGE_DOWN 0x5B +#define KEYCODE_KEYPAD_LEFT_ARROW 0x5C +#define KEYCODE_KEYPAD_RIGHT_ARROW 0x5E +#define KEYCODE_KEYPAD_HOME 0x5F +#define KEYCODE_KEYPAD_UP_ARROW 0x60 +#define KEYCODE_KEYPAD_PAGE_UP 0x61 +#define KEYCODE_KEYPAD_INSERT 0x62 +#define KEYCODE_KEYPAD_DELETE 0x63 +#define KEYCODE_APPLICATION 0x65 +#define KEYCODE_POWER 0x66 +#define KEYCODE_F13 0x68 +#define KEYCODE_F14 0x69 +#define KEYCODE_F15 0x6A +#define KEYCODE_F16 0x6B +#define KEYCODE_F17 0x6C +#define KEYCODE_F18 0x6D +#define KEYCODE_F19 0x6E +#define KEYCODE_F20 0x6F +#define KEYCODE_F21 0x70 +#define KEYCODE_F22 0x71 +#define KEYCODE_F23 0x72 +#define KEYCODE_F24 0x73 +#define KEYCODE_EXECUTE 0x74 +#define KEYCODE_HELP 0x75 +#define KEYCODE_MENU 0x76 +#define KEYCODE_SELECT 0x77 +#define KEYCODE_STOP 0x78 +#define KEYCODE_AGAIN 0x79 +#define KEYCODE_UNDO 0x7A +#define KEYCODE_CUT 0x7B +#define KEYCODE_COPY 0x7C +#define KEYCODE_PASTE 0x7D +#define KEYCODE_FIND 0x7E +#define KEYCODE_MUTE 0x7F +#define KEYCODE_VOLUME_UP 0x80 +#define KEYCODE_VOLUME_DOWN 0x81 +#define KEYCODE_CANCEL 0x9B +#define KEYCODE_CLEAR 0x9C +#define KEYCODE_PRIOR 0x9D +#define KEYCODE_KEYPAD_TAB 0xBA +#define KEYCODE_KEYPAD_BACKSPACE 0xBB + +// ASCII based keys #define KEY_LEFT_CTRL 0x80 #define KEY_LEFT_SHIFT 0x81 #define KEY_LEFT_ALT 0x82 @@ -111,12 +203,15 @@ extern Mouse_ Mouse; #define KEY_F11 0xCC #define KEY_F12 0xCD +#define KEY_ENTER KEY_RETURN + // Low level key report: up to 6 keys and shift, ctrl etc at once +#define KEYREPORT_KEYCOUNT 0x06 typedef struct { uint8_t modifiers; uint8_t reserved; - uint8_t keys[6]; + uint8_t keys[KEYREPORT_KEYCOUNT]; } KeyReport; class Keyboard_ : public Print @@ -131,6 +226,8 @@ class Keyboard_ : public Print virtual size_t write(uint8_t k); virtual size_t press(uint8_t k); virtual size_t release(uint8_t k); + virtual size_t pressKeycode(uint8_t k, uint8_t send); + virtual size_t releaseKeycode(uint8_t k, uint8_t send); virtual void releaseAll(void); }; extern Keyboard_ Keyboard;