#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); |