| #ifdef M | #ifdef M | ||||
| #undef M | #undef M | ||||
| #endif | #endif | ||||
| #define M(n) ((n) & 0x3FFF) | |||||
| #define M(n) ((n) & KEYCODE_MASK) | |||||
| const KEYCODE_TYPE PROGMEM keycodes_ascii[] = { | const KEYCODE_TYPE PROGMEM keycodes_ascii[] = { | ||||
| M(ASCII_20), M(ASCII_21), M(ASCII_22), M(ASCII_23), | M(ASCII_20), M(ASCII_21), M(ASCII_22), M(ASCII_23), |
| static const uint8_t PROGMEM endpoint_config_table[] = { | static const uint8_t PROGMEM endpoint_config_table[] = { | ||||
| 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, | |||||
| 1, EP_TYPE_INTERRUPT_OUT, EP_SIZE(DEBUG_RX_SIZE) | DEBUG_RX_BUFFER, | |||||
| 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, | |||||
| 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, | |||||
| #ifdef JOYSTICK_INTERFACE | |||||
| 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(JOYSTICK_SIZE) | JOYSTICK_BUFFER, | |||||
| 0 | |||||
| #endif | |||||
| EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, | |||||
| EP_TYPE_INTERRUPT_OUT, EP_SIZE(DEBUG_RX_SIZE) | DEBUG_RX_BUFFER, | |||||
| EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, | |||||
| EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, | |||||
| EP_TYPE_INTERRUPT_IN, EP_SIZE(JOYSTICK_SIZE) | JOYSTICK_BUFFER, | |||||
| EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYMEDIA_SIZE) | KEYMEDIA_BUFFER, | |||||
| }; | }; | ||||
| 0x15, 0x00, // Logical Minimum (0), | 0x15, 0x00, // Logical Minimum (0), | ||||
| 0x25, 0x01, // Logical Maximum (1), | 0x25, 0x01, // Logical Maximum (1), | ||||
| 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | ||||
| 0x95, 0x08, // Report Count (8), | |||||
| 0x75, 0x01, // Report Size (1), | |||||
| 0x15, 0x00, // Logical Minimum (0), | |||||
| 0x25, 0x01, // Logical Maximum (1), | |||||
| 0x05, 0x0C, // Usage Page (Consumer), | |||||
| 0x09, 0xE9, // Usage (Volume Increment), | |||||
| 0x09, 0xEA, // Usage (Volume Decrement), | |||||
| 0x09, 0xE2, // Usage (Mute), | |||||
| 0x09, 0xCD, // Usage (Play/Pause), | |||||
| 0x09, 0xB5, // Usage (Scan Next Track), | |||||
| 0x09, 0xB6, // Usage (Scan Previous Track), | |||||
| 0x09, 0xB7, // Usage (Stop), | |||||
| 0x09, 0xB8, // Usage (Eject), | |||||
| 0x81, 0x02, // Input (Data, Variable, Absolute), ;Media keys | |||||
| 0x95, 0x01, // Report Count (1), | |||||
| 0x75, 0x08, // Report Size (8), | |||||
| 0x81, 0x03, // Input (Constant), ;Reserved byte | |||||
| 0x95, 0x05, // Report Count (5), | 0x95, 0x05, // Report Count (5), | ||||
| 0x75, 0x01, // Report Size (1), | 0x75, 0x01, // Report Size (1), | ||||
| 0x05, 0x08, // Usage Page (LEDs), | 0x05, 0x08, // Usage Page (LEDs), | ||||
| 0xc0 // End Collection | 0xc0 // End Collection | ||||
| }; | }; | ||||
| static const uint8_t PROGMEM keymedia_hid_report_desc[] = { | |||||
| 0x05, 0x0C, // Usage Page (Consumer) | |||||
| 0x09, 0x01, // Usage (Consumer Controls) | |||||
| 0xA1, 0x01, // Collection (Application) | |||||
| 0x75, 0x0A, // Report Size (10) | |||||
| 0x95, 0x04, // Report Count (4) | |||||
| 0x19, 0x00, // Usage Minimum (0) | |||||
| 0x2A, 0x9C, 0x02, // Usage Maximum (0x29C) | |||||
| 0x15, 0x00, // Logical Minimum (0) | |||||
| 0x26, 0x9C, 0x02, // Logical Maximum (0x29C) | |||||
| 0x81, 0x00, // Input (Data, Array) | |||||
| 0x05, 0x01, // Usage Page (Generic Desktop) | |||||
| 0x75, 0x08, // Report Size (8) | |||||
| 0x95, 0x03, // Report Count (3) | |||||
| 0x19, 0x00, // Usage Minimum (0) | |||||
| 0x29, 0xB7, // Usage Maximum (0xB7) | |||||
| 0x15, 0x00, // Logical Minimum (0) | |||||
| 0x26, 0xB7, 0x00, // Logical Maximum (0xB7) | |||||
| 0x81, 0x00, // Input (Data, Array) | |||||
| 0xC0 // End Collection | |||||
| }; | |||||
| // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | ||||
| static const uint8_t PROGMEM mouse_hid_report_desc[] = { | static const uint8_t PROGMEM mouse_hid_report_desc[] = { | ||||
| 0x05, 0x01, // Usage Page (Generic Desktop) | 0x05, 0x01, // Usage Page (Generic Desktop) | ||||
| #define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 ) | #define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 ) | ||||
| #define MOUSE_HID_DESC_OFFSET ( 9 + 9+9+7 + 9 ) | #define MOUSE_HID_DESC_OFFSET ( 9 + 9+9+7 + 9 ) | ||||
| #define DEBUG_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9 ) | #define DEBUG_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9 ) | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| #define JOYSTICK_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9 ) | #define JOYSTICK_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9 ) | ||||
| #define CONFIG1_DESC_SIZE ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9+9+7) | |||||
| #else | |||||
| #define CONFIG1_DESC_SIZE ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 ) | |||||
| #endif | |||||
| #define KEYMEDIA_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9+9+7 + 9 ) | |||||
| #define CONFIG1_DESC_SIZE ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9+9+7 + 9+9+7 ) | |||||
| static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | ||||
| // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | ||||
| DEBUG_RX_SIZE, 0, // wMaxPacketSize | DEBUG_RX_SIZE, 0, // wMaxPacketSize | ||||
| DEBUG_RX_INTERVAL, // bInterval | DEBUG_RX_INTERVAL, // bInterval | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||||
| 9, // bLength | 9, // bLength | ||||
| 4, // bDescriptorType | 4, // bDescriptorType | ||||
| 0x03, // bmAttributes (0x03=intr) | 0x03, // bmAttributes (0x03=intr) | ||||
| 12, 0, // wMaxPacketSize | 12, 0, // wMaxPacketSize | ||||
| JOYSTICK_INTERVAL, // bInterval | JOYSTICK_INTERVAL, // bInterval | ||||
| #endif | |||||
| // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||||
| 9, // bLength | |||||
| 4, // bDescriptorType | |||||
| KEYMEDIA_INTERFACE, // bInterfaceNumber | |||||
| 0, // bAlternateSetting | |||||
| 1, // bNumEndpoints | |||||
| 0x03, // bInterfaceClass (0x03 = HID) | |||||
| 0x00, // bInterfaceSubClass | |||||
| 0x00, // bInterfaceProtocol | |||||
| 0, // iInterface | |||||
| // HID interface descriptor, HID 1.11 spec, section 6.2.1 | |||||
| 9, // bLength | |||||
| 0x21, // bDescriptorType | |||||
| 0x11, 0x01, // bcdHID | |||||
| 0, // bCountryCode | |||||
| 1, // bNumDescriptors | |||||
| 0x22, // bDescriptorType | |||||
| LSB(sizeof(keymedia_hid_report_desc)), // wDescriptorLength | |||||
| MSB(sizeof(keymedia_hid_report_desc)), | |||||
| // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |||||
| 7, // bLength | |||||
| 5, // bDescriptorType | |||||
| KEYMEDIA_ENDPOINT | 0x80, // bEndpointAddress | |||||
| 0x03, // bmAttributes (0x03=intr) | |||||
| KEYMEDIA_SIZE, 0, // wMaxPacketSize | |||||
| KEYMEDIA_INTERVAL, // bInterval | |||||
| }; | }; | ||||
| // If you're desperate for a little extra code memory, these strings | // If you're desperate for a little extra code memory, these strings | ||||
| {0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | {0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | ||||
| {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | ||||
| {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| {0x2200, JOYSTICK_INTERFACE, joystick_hid_report_desc, sizeof(joystick_hid_report_desc)}, | {0x2200, JOYSTICK_INTERFACE, joystick_hid_report_desc, sizeof(joystick_hid_report_desc)}, | ||||
| {0x2100, JOYSTICK_INTERFACE, config1_descriptor+JOYSTICK_HID_DESC_OFFSET, 9}, | {0x2100, JOYSTICK_INTERFACE, config1_descriptor+JOYSTICK_HID_DESC_OFFSET, 9}, | ||||
| #endif | |||||
| {0x2200, KEYMEDIA_INTERFACE, keymedia_hid_report_desc, sizeof(keymedia_hid_report_desc)}, | |||||
| {0x2100, KEYMEDIA_INTERFACE, config1_descriptor+KEYMEDIA_HID_DESC_OFFSET, 9}, | |||||
| {0x0300, 0x0000, (const uint8_t *)&string0, 4}, | {0x0300, 0x0000, (const uint8_t *)&string0, 4}, | ||||
| {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)}, | {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)}, | ||||
| }; | }; | ||||
| static uint8_t mouse_protocol USBSTATE; | static uint8_t mouse_protocol USBSTATE; | ||||
| // joystick data | // joystick data | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| uint8_t joystick_report_data[12] USBSTATE; | uint8_t joystick_report_data[12] USBSTATE; | ||||
| #endif | |||||
| // keyboard media keys data | |||||
| uint8_t keymedia_report_data[8] USBSTATE; | |||||
| uint16_t keymedia_consumer_keys[4] USBSTATE; | |||||
| uint8_t keymedia_system_keys[3] USBSTATE; | |||||
| /************************************************************************** | /************************************************************************** | ||||
| keyboard_leds = 0; | keyboard_leds = 0; | ||||
| mouse_buttons = 0; | mouse_buttons = 0; | ||||
| mouse_protocol = 1; | mouse_protocol = 1; | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| joystick_report_data[0] = 0; | joystick_report_data[0] = 0; | ||||
| joystick_report_data[1] = 0; | joystick_report_data[1] = 0; | ||||
| joystick_report_data[2] = 0; | joystick_report_data[2] = 0; | ||||
| joystick_report_data[9] = 0x08; | joystick_report_data[9] = 0x08; | ||||
| joystick_report_data[10] = 0x20; | joystick_report_data[10] = 0x20; | ||||
| joystick_report_data[11] = 0x80; | joystick_report_data[11] = 0x80; | ||||
| #endif | |||||
| keymedia_report_data[0] = 0; | |||||
| keymedia_report_data[1] = 0; | |||||
| keymedia_report_data[2] = 0; | |||||
| keymedia_report_data[3] = 0; | |||||
| keymedia_report_data[4] = 0; | |||||
| keymedia_report_data[5] = 0; | |||||
| keymedia_report_data[6] = 0; | |||||
| keymedia_report_data[7] = 0; | |||||
| keymedia_consumer_keys[0] = 0; | |||||
| keymedia_consumer_keys[1] = 0; | |||||
| keymedia_consumer_keys[2] = 0; | |||||
| keymedia_consumer_keys[3] = 0; | |||||
| keymedia_system_keys[0] = 0; | |||||
| keymedia_system_keys[1] = 0; | |||||
| keymedia_system_keys[2] = 0; | |||||
| UDINT = 0; | UDINT = 0; | ||||
| UDIEN = (1<<EORSTE)|(1<<SOFE); | UDIEN = (1<<EORSTE)|(1<<SOFE); | ||||
| //sei(); // init() in wiring.c does this | //sei(); // init() in wiring.c does this | ||||
| uint8_t intbits; | uint8_t intbits; | ||||
| const uint8_t *list; | const uint8_t *list; | ||||
| const uint8_t *cfg; | const uint8_t *cfg; | ||||
| uint8_t i, n, len, en; | |||||
| uint8_t i, n, len; | |||||
| uint8_t bmRequestType; | uint8_t bmRequestType; | ||||
| uint8_t bRequest; | uint8_t bRequest; | ||||
| uint16_t wValue; | uint16_t wValue; | ||||
| debug_flush_timer = 0; | debug_flush_timer = 0; | ||||
| usb_send_in(); | usb_send_in(); | ||||
| cfg = endpoint_config_table; | cfg = endpoint_config_table; | ||||
| for (i=1; i<NUM_ENDPOINTS; i++) { | |||||
| for (i=1; i<7; i++) { | |||||
| UENUM = i; | UENUM = i; | ||||
| pgm_read_byte_postinc(en, cfg); | |||||
| UECONX = en; | |||||
| if (en) { | |||||
| pgm_read_byte_postinc(UECFG0X, cfg); | |||||
| pgm_read_byte_postinc(UECFG1X, cfg); | |||||
| } | |||||
| UECONX = 1; | |||||
| pgm_read_byte_postinc(UECFG0X, cfg); | |||||
| pgm_read_byte_postinc(UECFG1X, cfg); | |||||
| } | } | ||||
| UERST = 0x1E; | UERST = 0x1E; | ||||
| UERST = 0; | UERST = 0; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| if (wIndex == JOYSTICK_INTERFACE) { | if (wIndex == JOYSTICK_INTERFACE) { | ||||
| if (bmRequestType == 0xA1) { | if (bmRequestType == 0xA1) { | ||||
| if (bRequest == HID_GET_REPORT) { | if (bRequest == HID_GET_REPORT) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| if (wIndex == KEYMEDIA_INTERFACE) { | |||||
| if (bmRequestType == 0xA1) { | |||||
| if (bRequest == HID_GET_REPORT) { | |||||
| usb_wait_in_ready(); | |||||
| for (i=0; i<8; i++) { | |||||
| UEDATX = keymedia_report_data[i]; | |||||
| } | |||||
| usb_send_in(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (wIndex == DEBUG_INTERFACE) { | if (wIndex == DEBUG_INTERFACE) { | ||||
| if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { | if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { | ||||
| len = wLength; | len = wLength; |
| // Step #1, decode UTF8 to Unicode code points | // Step #1, decode UTF8 to Unicode code points | ||||
| // | // | ||||
| #if ARDUINO >= 100 | |||||
| size_t usb_keyboard_class::write(uint8_t c) | size_t usb_keyboard_class::write(uint8_t c) | ||||
| #else | |||||
| void usb_keyboard_class::write(uint8_t c) | |||||
| #endif | |||||
| { | { | ||||
| if (c < 0x80) { | if (c < 0x80) { | ||||
| // single byte encoded, 0x00 to 0x7F | // single byte encoded, 0x00 to 0x7F | ||||
| // or illegal, 0xF5 to 0xFF | // or illegal, 0xF5 to 0xFF | ||||
| utf8_state = 255; | utf8_state = 255; | ||||
| } | } | ||||
| #if ARDUINO >= 100 | |||||
| return 1; | return 1; | ||||
| #endif | |||||
| } | } | ||||
| // Unicode code points beyond U+FFFF are not supported | // Unicode code points beyond U+FFFF are not supported | ||||
| // technically this input should probably be called UCS-2 | // technically this input should probably be called UCS-2 | ||||
| if (cpoint < 32) { | if (cpoint < 32) { | ||||
| if (cpoint == 10) return KEY_ENTER & 0x3FFF; | |||||
| if (cpoint == 10) return KEY_ENTER & KEYCODE_MASK; | |||||
| if (cpoint == 11) return KEY_TAB & KEYCODE_MASK; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (cpoint < 128) { | if (cpoint < 128) { | ||||
| { | { | ||||
| keyboard_report_data[7] = c; | keyboard_report_data[7] = c; | ||||
| } | } | ||||
| void usb_keyboard_class::set_media(uint8_t c) | |||||
| { | |||||
| keyboard_report_data[1] = c; | |||||
| } | |||||
| void usb_keyboard_class::send_now(void) | void usb_keyboard_class::send_now(void) | ||||
| uint8_t key, mod, msb, modrestore=0; | uint8_t key, mod, msb, modrestore=0; | ||||
| msb = n >> 8; | msb = n >> 8; | ||||
| if (msb >= 0xC2 && msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else | |||||
| if (msb == 0x80) { | |||||
| presskey(0, n); | |||||
| return; | |||||
| } else | |||||
| if (msb == 0x40) { | |||||
| presskey(n, 0); | |||||
| return; | |||||
| if (msb >= 0xC2) { | |||||
| if (msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else if (msb == 0xF0) { | |||||
| presskey(n, 0); | |||||
| return; | |||||
| } else if (msb == 0xE0) { | |||||
| presskey(0, n); | |||||
| return; | |||||
| } else if (msb == 0xE2) { | |||||
| press_system_key(n); | |||||
| return; | |||||
| } else if (msb >= 0xE4 && msb <= 0xE7) { | |||||
| press_consumer_key(n & 0x3FF); | |||||
| return; | |||||
| } else { | |||||
| return; | |||||
| } | |||||
| } | } | ||||
| KEYCODE_TYPE keycode = unicode_to_keycode(n); | KEYCODE_TYPE keycode = unicode_to_keycode(n); | ||||
| if (!keycode) return; | if (!keycode) return; | ||||
| #ifdef DEADKEYS_MASK | |||||
| #ifdef DEADKEYS_MASK | |||||
| KEYCODE_TYPE deadkeycode = deadkey_to_keycode(keycode); | KEYCODE_TYPE deadkeycode = deadkey_to_keycode(keycode); | ||||
| if (deadkeycode) { | if (deadkeycode) { | ||||
| modrestore = keyboard_report_data[0]; | modrestore = keyboard_report_data[0]; | ||||
| presskey(key, mod); | presskey(key, mod); | ||||
| releasekey(key, mod); | releasekey(key, mod); | ||||
| } | } | ||||
| #endif | |||||
| #endif | |||||
| mod = keycode_to_modifier(keycode); | mod = keycode_to_modifier(keycode); | ||||
| key = keycode_to_key(keycode); | key = keycode_to_key(keycode); | ||||
| presskey(key, mod | modrestore); | presskey(key, mod | modrestore); | ||||
| uint8_t key, mod, msb; | uint8_t key, mod, msb; | ||||
| msb = n >> 8; | msb = n >> 8; | ||||
| if (msb >= 0xC2 && msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else | |||||
| if (msb == 0x80) { | |||||
| releasekey(0, n); | |||||
| return; | |||||
| } else | |||||
| if (msb == 0x40) { | |||||
| releasekey(n, 0); | |||||
| return; | |||||
| if (msb >= 0xC2) { | |||||
| if (msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else if (msb == 0xF0) { | |||||
| releasekey(n, 0); | |||||
| return; | |||||
| } else if (msb == 0xE0) { | |||||
| releasekey(0, n); | |||||
| return; | |||||
| } else if (msb == 0xE2) { | |||||
| release_system_key(n); | |||||
| return; | |||||
| } else if (msb >= 0xE4 && msb <= 0xE7) { | |||||
| release_consumer_key(n & 0x3FF); | |||||
| return; | |||||
| } else { | |||||
| return; | |||||
| } | |||||
| } | } | ||||
| KEYCODE_TYPE keycode = unicode_to_keycode(n); | KEYCODE_TYPE keycode = unicode_to_keycode(n); | ||||
| if (!keycode) return; | if (!keycode) return; | ||||
| send_now(); | send_now(); | ||||
| } | } | ||||
| void usb_keyboard_class::press_consumer_key(uint16_t key) | |||||
| { | |||||
| if (key == 0) return; | |||||
| for (uint8_t i=0; i < 4; i++) { | |||||
| if (keymedia_consumer_keys[i] == key) return; | |||||
| } | |||||
| for (uint8_t i=0; i < 4; i++) { | |||||
| if (keymedia_consumer_keys[i] == 0) { | |||||
| keymedia_consumer_keys[i] = key; | |||||
| keymedia_send(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| void usb_keyboard_class::release_consumer_key(uint16_t key) | |||||
| { | |||||
| if (key == 0) return; | |||||
| for (uint8_t i=0; i < 4; i++) { | |||||
| if (keymedia_consumer_keys[i] == key) { | |||||
| keymedia_consumer_keys[i] = 0; | |||||
| keymedia_send(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| void usb_keyboard_class::press_system_key(uint8_t key) | |||||
| { | |||||
| if (key == 0) return; | |||||
| for (uint8_t i=0; i < 3; i++) { | |||||
| if (keymedia_system_keys[i] == key) return; | |||||
| } | |||||
| for (uint8_t i=0; i < 3; i++) { | |||||
| if (keymedia_system_keys[i] == 0) { | |||||
| keymedia_system_keys[i] = key; | |||||
| keymedia_send(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| void usb_keyboard_class::release_system_key(uint8_t key) | |||||
| { | |||||
| if (key == 0) return; | |||||
| for (uint8_t i=0; i < 3; i++) { | |||||
| if (keymedia_system_keys[i] == key) { | |||||
| keymedia_system_keys[i] = 0; | |||||
| keymedia_send(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| void usb_keyboard_class::keymedia_release_all(void) | |||||
| { | |||||
| uint8_t anybits = 0; | |||||
| for (uint8_t i=0; i < 4; i++) { | |||||
| if (keymedia_consumer_keys[i] != 0) anybits = 1; | |||||
| keymedia_consumer_keys[i] = 0; | |||||
| } | |||||
| for (uint8_t i=0; i < 3; i++) { | |||||
| if (keymedia_system_keys[i] != 0) anybits = 1; | |||||
| keymedia_system_keys[i] = 0; | |||||
| } | |||||
| if (anybits) keymedia_send(); | |||||
| } | |||||
| // send the contents of keyboard_keys and keyboard_modifier_keys | |||||
| void usb_keyboard_class::keymedia_send(void) | |||||
| { | |||||
| uint8_t intr_state, timeout; | |||||
| if (!usb_configuration) return; | |||||
| intr_state = SREG; | |||||
| cli(); | |||||
| UENUM = KEYMEDIA_ENDPOINT; | |||||
| timeout = UDFNUML + 50; | |||||
| while (1) { | |||||
| // are we ready to transmit? | |||||
| if (UEINTX & (1<<RWAL)) break; | |||||
| SREG = intr_state; | |||||
| // has the USB gone offline? | |||||
| if (!usb_configuration) return; | |||||
| // have we waited too long? | |||||
| if (UDFNUML == timeout) return; | |||||
| // get ready to try checking again | |||||
| intr_state = SREG; | |||||
| cli(); | |||||
| UENUM = KEYMEDIA_ENDPOINT; | |||||
| } | |||||
| // 44444444 44333333 33332222 22222211 11111111 | |||||
| // 98765432 10987654 32109876 54321098 76543210 | |||||
| UEDATX = keymedia_consumer_keys[0]; | |||||
| UEDATX = (keymedia_consumer_keys[1] << 2) | ((keymedia_consumer_keys[0] >> 8) & 0x03); | |||||
| UEDATX = (keymedia_consumer_keys[2] << 4) | ((keymedia_consumer_keys[1] >> 6) & 0x0F); | |||||
| UEDATX = (keymedia_consumer_keys[3] << 6) | ((keymedia_consumer_keys[2] >> 4) & 0x3F); | |||||
| UEDATX = keymedia_consumer_keys[3] >> 2; | |||||
| UEDATX = keymedia_system_keys[0]; | |||||
| UEDATX = keymedia_system_keys[1]; | |||||
| UEDATX = keymedia_system_keys[2]; | |||||
| UEINTX = 0x3A; | |||||
| SREG = intr_state; | |||||
| } | |||||
| void usb_mouse_class::move(int8_t x, int8_t y, int8_t wheel) | void usb_mouse_class::move(int8_t x, int8_t y, int8_t wheel) | ||||
| } | } | ||||
| #if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||||
| void usb_joystick_class::send_now(void) | void usb_joystick_class::send_now(void) | ||||
| { | { | ||||
| uint8_t intr_state, timeout; | uint8_t intr_state, timeout; | ||||
| SREG = intr_state; | SREG = intr_state; | ||||
| } | } | ||||
| #endif | |||||
| } | } | ||||
| // transmit a character. | // transmit a character. | ||||
| #if ARDUINO >= 100 | |||||
| size_t usb_serial_class::write(uint8_t c) | size_t usb_serial_class::write(uint8_t c) | ||||
| #else | |||||
| void usb_serial_class::write(uint8_t c) | |||||
| #endif | |||||
| { | { | ||||
| //static uint8_t previous_timeout=0; | //static uint8_t previous_timeout=0; | ||||
| uint8_t timeout, intr_state; | uint8_t timeout, intr_state; | ||||
| debug_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | debug_flush_timer = TRANSMIT_FLUSH_TIMEOUT; | ||||
| } | } | ||||
| SREG = intr_state; | SREG = intr_state; | ||||
| #if ARDUINO >= 100 | |||||
| return 1; | return 1; | ||||
| #endif | |||||
| error: | error: | ||||
| #if ARDUINO >= 100 | |||||
| setWriteError(); | setWriteError(); | ||||
| return 0; | return 0; | ||||
| #else | |||||
| return; | |||||
| #endif | |||||
| } | } | ||||
| usb_serial_class Serial = usb_serial_class(); | usb_serial_class Serial = usb_serial_class(); | ||||
| usb_keyboard_class Keyboard = usb_keyboard_class(); | usb_keyboard_class Keyboard = usb_keyboard_class(); | ||||
| usb_mouse_class Mouse = usb_mouse_class(); | usb_mouse_class Mouse = usb_mouse_class(); | ||||
| #if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||||
| usb_joystick_class Joystick = usb_joystick_class(); | usb_joystick_class Joystick = usb_joystick_class(); | ||||
| #endif | |||||
| public: | public: | ||||
| void begin(void) { } | void begin(void) { } | ||||
| void end(void) { } | void end(void) { } | ||||
| #if ARDUINO >= 100 | |||||
| virtual size_t write(uint8_t); | virtual size_t write(uint8_t); | ||||
| #else | |||||
| virtual void write(uint8_t); | |||||
| #endif | |||||
| using Print::write; | using Print::write; | ||||
| void write_unicode(uint16_t unicode) { write_keycode(unicode_to_keycode(unicode)); } | void write_unicode(uint16_t unicode) { write_keycode(unicode_to_keycode(unicode)); } | ||||
| void set_modifier(uint8_t); | void set_modifier(uint8_t); | ||||
| void set_key4(uint8_t); | void set_key4(uint8_t); | ||||
| void set_key5(uint8_t); | void set_key5(uint8_t); | ||||
| void set_key6(uint8_t); | void set_key6(uint8_t); | ||||
| void set_media(uint8_t); | |||||
| void set_media(uint16_t c) { | |||||
| if (c == 0) { | |||||
| keymedia_release_all(); | |||||
| } else if (c >= 0xE400 && c <= 0xE7FF) { | |||||
| press(c); | |||||
| } | |||||
| } | |||||
| void send_now(void); | void send_now(void); | ||||
| void press(uint16_t n); | void press(uint16_t n); | ||||
| void release(uint16_t n); | void release(uint16_t n); | ||||
| void releasekey(uint8_t key, uint8_t modifier); | void releasekey(uint8_t key, uint8_t modifier); | ||||
| void write_keycode(KEYCODE_TYPE key); | void write_keycode(KEYCODE_TYPE key); | ||||
| void write_key(KEYCODE_TYPE code); | void write_key(KEYCODE_TYPE code); | ||||
| void press_consumer_key(uint16_t key); | |||||
| void release_consumer_key(uint16_t key); | |||||
| void press_system_key(uint8_t key); | |||||
| void release_system_key(uint8_t key); | |||||
| void keymedia_release_all(void); | |||||
| void keymedia_send(void); | |||||
| uint8_t utf8_state; | uint8_t utf8_state; | ||||
| uint16_t unicode_wchar; | uint16_t unicode_wchar; | ||||
| }; | }; | ||||
| #if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||||
| extern uint8_t joystick_report_data[12]; | extern uint8_t joystick_report_data[12]; | ||||
| class usb_joystick_class | class usb_joystick_class | ||||
| extern usb_joystick_class Joystick; | extern usb_joystick_class Joystick; | ||||
| #endif | |||||
| virtual int read(); | virtual int read(); | ||||
| virtual int peek(); | virtual int peek(); | ||||
| virtual void flush(); | virtual void flush(); | ||||
| #if ARDUINO >= 100 | |||||
| virtual size_t write(uint8_t); | virtual size_t write(uint8_t); | ||||
| #else | |||||
| virtual void write(uint8_t); | |||||
| #endif | |||||
| using Print::write; | using Print::write; | ||||
| operator bool(); | operator bool(); | ||||
| // Teensy extensions | // Teensy extensions |
| * | * | ||||
| **************************************************************************/ | **************************************************************************/ | ||||
| // These buffer sizes are best for most applications, but perhaps if you | |||||
| // want more buffering on some endpoint at the expense of others, this | |||||
| // is where you can make such changes. The AT90USB162 has only 176 bytes | |||||
| // of DPRAM (USB buffers) and only endpoints 3 & 4 can double buffer. | |||||
| // 0: control 32 64 | |||||
| // 1: debug IN 64 64x2 | |||||
| // 2: debug OUT 32 32x2 | |||||
| // 3: keyboard IN 8x2 8x2 | |||||
| // 4: mouse + joystick IN (IDs) 16x2 16x2 | |||||
| // 5: joystick 16x2 | |||||
| // 6: | |||||
| #if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||||
| // 0: control 64 | |||||
| // 1: debug IN 64x2 | |||||
| // 2: debug OUT 32x2 | |||||
| // 3: keyboard IN 8x2 | |||||
| // 4: mouse IN 16x2 | |||||
| // 5: joystick IN 16x2 | |||||
| // 6: keyboard media IN 8x2 | |||||
| // Some operating systems, especially Windows, may cache USB device | // Some operating systems, especially Windows, may cache USB device | ||||
| // info. Changes to the device name may not update on the same | // info. Changes to the device name may not update on the same | ||||
| #define JOYSTICK_BUFFER EP_DOUBLE_BUFFER | #define JOYSTICK_BUFFER EP_DOUBLE_BUFFER | ||||
| #define JOYSTICK_INTERVAL 2 | #define JOYSTICK_INTERVAL 2 | ||||
| #define NUM_ENDPOINTS 7 | |||||
| #define NUM_INTERFACE 4 | |||||
| #elif defined(__AVR_AT90USB162__) | |||||
| #define STR_PRODUCT L"Teensy Keyboard/Mouse" | |||||
| #define ENDPOINT0_SIZE 32 | |||||
| #define DEBUG_INTERFACE 2 | |||||
| #define DEBUG_TX_ENDPOINT 1 | |||||
| #define DEBUG_TX_SIZE 64 | |||||
| #define DEBUG_TX_BUFFER EP_SINGLE_BUFFER | |||||
| #define DEBUG_TX_INTERVAL 2 | |||||
| #define DEBUG_RX_ENDPOINT 2 | |||||
| #define DEBUG_RX_SIZE 32 | |||||
| #define DEBUG_RX_BUFFER EP_SINGLE_BUFFER | |||||
| #define DEBUG_RX_INTERVAL 8 | |||||
| #define KEYBOARD_INTERFACE 0 | |||||
| #define KEYBOARD_ENDPOINT 3 | |||||
| #define KEYBOARD_SIZE 8 | |||||
| #define KEYBOARD_BUFFER EP_DOUBLE_BUFFER | |||||
| #define KEYBOARD_INTERVAL 1 | |||||
| #define MOUSE_INTERFACE 1 | |||||
| #define MOUSE_ENDPOINT 4 | |||||
| #define MOUSE_SIZE 8 | |||||
| #define MOUSE_BUFFER EP_DOUBLE_BUFFER | |||||
| #define MOUSE_INTERVAL 8 | |||||
| #define NUM_ENDPOINTS 5 | |||||
| #define NUM_INTERFACE 3 | |||||
| #endif | |||||
| #define KEYMEDIA_INTERFACE 4 | |||||
| #define KEYMEDIA_ENDPOINT 6 | |||||
| #define KEYMEDIA_SIZE 8 | |||||
| #define KEYMEDIA_BUFFER EP_DOUBLE_BUFFER | |||||
| #define KEYMEDIA_INTERVAL 4 | |||||
| #define NUM_ENDPOINTS 7 | |||||
| #define NUM_INTERFACE 5 | |||||
| // setup | // setup | ||||
| extern uint8_t keyboard_idle_count; | extern uint8_t keyboard_idle_count; | ||||
| extern volatile uint8_t keyboard_leds; | extern volatile uint8_t keyboard_leds; | ||||
| extern uint8_t mouse_buttons; | extern uint8_t mouse_buttons; | ||||
| #ifdef JOYSTICK_INTERFACE | |||||
| extern uint8_t joystick_report_data[12]; | extern uint8_t joystick_report_data[12]; | ||||
| #endif | |||||
| extern uint8_t keymedia_report_data[8]; | |||||
| extern uint16_t keymedia_consumer_keys[4]; | |||||
| extern uint8_t keymedia_system_keys[3]; | |||||
| // transmit a block of data | // transmit a block of data | ||||
| #if ARDUINO >= 100 | |||||
| size_t usb_serial_class::write(const uint8_t *buffer, uint16_t size) | size_t usb_serial_class::write(const uint8_t *buffer, uint16_t size) | ||||
| #else | |||||
| #define setWriteError() | |||||
| void usb_serial_class::write(const uint8_t *buffer, uint16_t size) | |||||
| #endif | |||||
| { | { | ||||
| uint8_t timeout, intr_state, write_size; | uint8_t timeout, intr_state, write_size; | ||||
| #if ARDUINO >= 100 | |||||
| size_t count=0; | size_t count=0; | ||||
| #endif | |||||
| // if we're not online (enumerated and configured), error | // if we're not online (enumerated and configured), error | ||||
| if (!usb_configuration) { | if (!usb_configuration) { | ||||
| write_size = CDC_TX_SIZE - UEBCLX; | write_size = CDC_TX_SIZE - UEBCLX; | ||||
| if (write_size > size) write_size = size; | if (write_size > size) write_size = size; | ||||
| size -= write_size; | size -= write_size; | ||||
| #if ARDUINO >= 100 | |||||
| count += write_size; | count += write_size; | ||||
| #endif | |||||
| #define ASM_COPY1(src, dest, tmp) "ld " tmp ", " src "\n\t" "st " dest ", " tmp "\n\t" | #define ASM_COPY1(src, dest, tmp) "ld " tmp ", " src "\n\t" "st " dest ", " tmp "\n\t" | ||||
| #define ASM_COPY2(src, dest, tmp) ASM_COPY1(src, dest, tmp) ASM_COPY1(src, dest, tmp) | #define ASM_COPY2(src, dest, tmp) ASM_COPY1(src, dest, tmp) ASM_COPY1(src, dest, tmp) | ||||
| } | } | ||||
| SREG = intr_state; | SREG = intr_state; | ||||
| end: | end: | ||||
| #if ARDUINO >= 100 | |||||
| return count; | return count; | ||||
| #else | |||||
| return; | |||||
| #endif | |||||
| } | } | ||||
| // transmit a string | // transmit a string | ||||
| // Step #1, decode UTF8 to Unicode code points | // Step #1, decode UTF8 to Unicode code points | ||||
| // | // | ||||
| #if ARDUINO >= 100 | |||||
| size_t usb_keyboard_class::write(uint8_t c) | size_t usb_keyboard_class::write(uint8_t c) | ||||
| #else | |||||
| void usb_keyboard_class::write(uint8_t c) | |||||
| #endif | |||||
| { | { | ||||
| if (c < 0x80) { | if (c < 0x80) { | ||||
| // single byte encoded, 0x00 to 0x7F | // single byte encoded, 0x00 to 0x7F | ||||
| // or illegal, 0xF5 to 0xFF | // or illegal, 0xF5 to 0xFF | ||||
| utf8_state = 255; | utf8_state = 255; | ||||
| } | } | ||||
| #if ARDUINO >= 100 | |||||
| return 1; | return 1; | ||||
| #endif | |||||
| } | } | ||||
| // Unicode code points beyond U+FFFF are not supported | // Unicode code points beyond U+FFFF are not supported | ||||
| // technically this input should probably be called UCS-2 | // technically this input should probably be called UCS-2 | ||||
| if (cpoint < 32) { | if (cpoint < 32) { | ||||
| if (cpoint == 10) return KEY_ENTER & 0x3FFF; | |||||
| if (cpoint == 10) return KEY_ENTER & KEYCODE_MASK; | |||||
| if (cpoint == 11) return KEY_TAB & KEYCODE_MASK; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (cpoint < 128) { | if (cpoint < 128) { | ||||
| { | { | ||||
| keyboard_report_data[7] = c; | keyboard_report_data[7] = c; | ||||
| } | } | ||||
| void usb_keyboard_class::set_media(uint8_t c) | |||||
| { | |||||
| keyboard_report_data[1] = c; | |||||
| } | |||||
| void usb_keyboard_class::send_now(void) | void usb_keyboard_class::send_now(void) | ||||
| uint8_t key, mod, msb, modrestore=0; | uint8_t key, mod, msb, modrestore=0; | ||||
| msb = n >> 8; | msb = n >> 8; | ||||
| if (msb >= 0xC2 && msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else | |||||
| if (msb == 0x80) { | |||||
| presskey(0, n); | |||||
| return; | |||||
| } else | |||||
| if (msb == 0x40) { | |||||
| presskey(n, 0); | |||||
| return; | |||||
| } | |||||
| if (msb >= 0xC2) { | |||||
| if (msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else if (msb == 0xF0) { | |||||
| presskey(n, 0); | |||||
| return; | |||||
| } else if (msb == 0xE0) { | |||||
| presskey(0, n); | |||||
| return; | |||||
| } else if (msb == 0xE2) { | |||||
| //press_system_key(n); | |||||
| return; | |||||
| } else if (msb >= 0xE4 && msb <= 0xE7) { | |||||
| //press_consumer_key(n & 0x3FF); | |||||
| return; | |||||
| } else { | |||||
| return; | |||||
| } | |||||
| } | |||||
| KEYCODE_TYPE keycode = unicode_to_keycode(n); | KEYCODE_TYPE keycode = unicode_to_keycode(n); | ||||
| if (!keycode) return; | if (!keycode) return; | ||||
| #ifdef DEADKEYS_MASK | #ifdef DEADKEYS_MASK | ||||
| uint8_t key, mod, msb; | uint8_t key, mod, msb; | ||||
| msb = n >> 8; | msb = n >> 8; | ||||
| if (msb >= 0xC2 && msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else | |||||
| if (msb == 0x80) { | |||||
| releasekey(0, n); | |||||
| return; | |||||
| } else | |||||
| if (msb == 0x40) { | |||||
| releasekey(n, 0); | |||||
| return; | |||||
| } | |||||
| if (msb >= 0xC2) { | |||||
| if (msb <= 0xDF) { | |||||
| n = (n & 0x3F) | ((uint16_t)(msb & 0x1F) << 6); | |||||
| } else if (msb == 0xF0) { | |||||
| releasekey(n, 0); | |||||
| return; | |||||
| } else if (msb == 0xE0) { | |||||
| releasekey(0, n); | |||||
| return; | |||||
| } else if (msb == 0xE2) { | |||||
| //release_system_key(n); | |||||
| return; | |||||
| } else if (msb >= 0xE4 && msb <= 0xE7) { | |||||
| //release_consumer_key(n & 0x3FF); | |||||
| return; | |||||
| } else { | |||||
| return; | |||||
| } | |||||
| } | |||||
| KEYCODE_TYPE keycode = unicode_to_keycode(n); | KEYCODE_TYPE keycode = unicode_to_keycode(n); | ||||
| if (!keycode) return; | if (!keycode) return; | ||||
| mod = keycode_to_modifier(keycode); | mod = keycode_to_modifier(keycode); |
| void set_key4(uint8_t); | void set_key4(uint8_t); | ||||
| void set_key5(uint8_t); | void set_key5(uint8_t); | ||||
| void set_key6(uint8_t); | void set_key6(uint8_t); | ||||
| void set_media(uint8_t); | |||||
| void set_media(uint8_t) { | |||||
| } | |||||
| void send_now(void); | void send_now(void); | ||||
| void press(uint16_t n); | void press(uint16_t n); | ||||
| void release(uint16_t n); | void release(uint16_t n); |