ifdef MOUSE_DELAY_TIME | ifdef MOUSE_DELAY_TIME | ||||
CDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME) | CDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME) | ||||
endif | endif | ||||
ifdef USB_12KRO | |||||
CDEFS += -DUSB_12KRO | |||||
ifdef NKRO_ENABLE | |||||
CDEFS += -DNKRO_ENABLE | |||||
endif | endif | ||||
======================== | ======================== | ||||
http://github.com/tmk/tmk_keyboard | http://github.com/tmk/tmk_keyboard | ||||
This is keyboard firmware for PFU HHKB style keyboard and Teensy/Teensy++ 2.0. | |||||
OS see this as composite device which has keyboard and mouse. | |||||
This is keyboard firmware for AVR USB MCUs or Teensy/Teensy++ 2.0. | |||||
The project is heavily based on PJRC USB Keyboard/Mouse Example and | The project is heavily based on PJRC USB Keyboard/Mouse Example and | ||||
owes a debt to preceding keyboard firmware projects. | owes a debt to preceding keyboard firmware projects. | ||||
http://www.pjrc.com/teensy | |||||
Version | |||||
------- | |||||
0.1 2010/08/23 | |||||
It works as normal keyboard. | |||||
It is for modified Macway keyboard(TP-999KB-E). | |||||
1.0 2010/10/02 | |||||
keyboard has mouse key now. | |||||
keyboard with layers.(see keymap.c) | |||||
FN_1(right cmd): | |||||
vi style layer | |||||
FN_2(next to right shift): | |||||
HHKB style layer | |||||
FN_3(left bottom): | |||||
h j k l: mouse move | |||||
a s d spc: mouse buttons | |||||
m ,: mouse wheel | |||||
1.1 2010/10/08 | |||||
Matrix wiring changed for casing. | |||||
(and my Teensy PD3 seems to be latchuped and unusable. :<) | |||||
1.2 2010/10/13 | |||||
HHKB support | |||||
horizontal mouse wheel support | |||||
change keymaps | |||||
2.0 2010/10/27 | |||||
HHKB/Macway support merged | |||||
Functions | |||||
--------- | |||||
Mouse key | |||||
System Control Key | |||||
Power Down, Sleep, Wake Up & USB Remote Wake up | |||||
Media Control Key | |||||
Volume Down/Up, Mute | |||||
USB NKRO | |||||
Build | Build | ||||
$ cd <target> (hhkb or macway) | $ cd <target> (hhkb or macway) | ||||
$ make | $ make | ||||
http://winavr.sourceforge.net/ | |||||
Debuging | |||||
-------- | |||||
Debug print is on if 4 keys are pressed during booting. | |||||
Use PJRC's hid_listen.exe to see debug messages. | |||||
Debuging & Rescue | |||||
----------------- | |||||
Use PJRC's hid_listen.exe to see debug messages. | |||||
Press right Control + Shift + Alt + GUI + H to debug menu. | |||||
AVR Target board | |||||
---------------- | |||||
Teensy/Teensy++ | |||||
http://www.pjrc.com/teensy | |||||
Pressing any 3 keys when connected enables debug output. | |||||
Pressing any 4 keys when connected makes bootloader comes up. | |||||
Projects related | Projects related | ||||
http://sourceforge.net/projects/ps2avr/ | http://sourceforge.net/projects/ps2avr/ | ||||
TODO & ideas | |||||
------------ | |||||
licensing notes(GPL) | |||||
I think GPL is not infringement of PJRC license. | |||||
souce code cleaning | |||||
sleep&wakeup | |||||
debouncing logic | |||||
will be coded when bouncing occurs. | |||||
bouncing doesnt occur on my ALPS switch so far. | |||||
scan rate is too slow?(to be measure) | |||||
Trackpoint(PS/2) | |||||
receive PS/2 signal from TrackPoint | |||||
send USB HID report | |||||
Thinkpad keyboard support | |||||
turn keyboard to USB keyboard/mouse composite device | |||||
setting menu(configure without changing firmware) | |||||
console for display | |||||
keymap/layer setting | |||||
mouse speed/acceleration | |||||
matrix display | |||||
PS/2 keyboard mode | |||||
with USB to PS/2 dumb adapter(possible?) | |||||
AT90USBKEY support | |||||
and other AVR USB boards | |||||
DONE: | |||||
support for HHKB pro matrix signal | |||||
exchange controller board with teensy | |||||
2010/10/11 | |||||
keymap | |||||
Matias half keyboard style | |||||
2010/10/23 | |||||
souce code cleaning | |||||
2010/10/23 | |||||
debug on/off | |||||
debug off by default | |||||
pressing keys during booting | |||||
2010/10/23 | |||||
mouse horizontal wheel | |||||
http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | |||||
http://www.keil.com/forum/15671/ | |||||
http://www.microsoft.com/whdc/device/input/wheel.mspx | |||||
2010/10/13 | |||||
debug on/off | |||||
Fn key conbination during normal operation | |||||
matrix print on/off | |||||
key print on/off | |||||
mouse print on/off | |||||
2010/10/26 | |||||
layer switching | |||||
time before switching | |||||
timeout when not used during specific time | |||||
2010/10/30 | |||||
EOF | EOF |
USB NKRO MEMO | |||||
============= | |||||
2010/12/07 | |||||
References | |||||
---------- | |||||
USB - boot mode, NKRO, compatibility, etc... | |||||
http://geekhack.org/showthread.php?t=13162 | |||||
NKey Rollover - Overview, Testing Methodology, and Results | |||||
http://geekhack.org/showwiki.php?title=NKey+Rollover+-+Overview+Testing+Methodology+and+Results | |||||
Terminogy | |||||
--------- | |||||
NKRO | |||||
ghost | |||||
matrix | |||||
mechanical with diodes | |||||
membrane | |||||
OS Support Status | |||||
----------------- | |||||
NKRO is possible at least relatively new OS. | |||||
Following OS supports both Extended and Bitmarp report. | |||||
Windows7 64bit | |||||
Windows2000 SP4 | |||||
Ubuntu 10.4(Linux 2.6) | |||||
USB NKRO methods | |||||
---------------- | |||||
1. Virtual keyboards | |||||
Keyboard can increase its KRO by using virtual keyboards with Standard or Extended report. | |||||
If the keyboard has 2 virtul keyboard with Standard report(6KRO), it gets 12KRO. | |||||
Using this method means the keyboard is a composite device. | |||||
2. Exteded report | |||||
It needs large report size for this method to achive NKRO. | |||||
If a keyboard has 101keys, it needs 103byte report. It seems to be inefficient. | |||||
3. Bitmap report | |||||
If the keyboard has less than 128keys, 16byte report will be enough for NKRO. | |||||
The 16byte report seems to be reasonable cost to get NKRO. | |||||
Report Format | |||||
------------- | |||||
Other report formats than followings are possible, though these format are typical one. | |||||
1. Standard 8bytes | |||||
modifiers(bitmap) 1byte | |||||
reserved 1byte(not used) | |||||
keys(array) 1byte*6 | |||||
Standard report can send 6keys plus 8modifiers simultaneously. | |||||
Standard report is used by most keyboards in the marketplace. | |||||
Standard report is identical to boot protocol report. | |||||
Standard report is hard to suffer from compatibility problems. | |||||
2. Extended standard 16,32,64bytes | |||||
modifiers(bitmap) 1byte | |||||
reserved 1byte(not used) | |||||
keys(array) 1byte*(14,32,62) | |||||
Extended report can send N-keys by using N+2bytes. | |||||
Extended report is expected to be compatible with boot protocol. | |||||
3. Bitmap 16,32,64bytes | |||||
keys(bitmap) (16,32)bytes | |||||
Bitmap report can send at most 128keys by 16bytes and 256keys by 32bytes. | |||||
Bitmap report can achieve USB NKRO efficiently in terms of report size. | |||||
Bitmap report needs a deliberation for boot protocol implementation. | |||||
Compatibility Problem | |||||
--------------------- | |||||
Some BIOS doesn't send SET_PROTCOL request, a keyboard can't switch to boot protocol mode. | |||||
This may cuase a problem on a keyboard which uses other report than Standard. | |||||
Windows Problem | |||||
--------------- | |||||
1. Windows accepts only 6keys in case of Standard report. | |||||
It should be able to send 6keys plus 8modifiers. | |||||
2. Windows accepts only 10keys in case of 16bytes Extended report. | |||||
It should be able to send 14keys plus 8modifiers. | |||||
3. Windows accepts only 18keys in case of 32bytes Extended report. | |||||
It should be able to send 30keys plus 8modifiers. | |||||
If keys are pressed in excess of the number, wrong keys are registered on Windows. | |||||
This problem will be reportedly fixed soon.(2010/12/05) | |||||
http://forums.anandtech.com/showpost.php?p=30873364&postcount=17 | |||||
EOF |
# To rebuild project do "make clean" then "make all". | # To rebuild project do "make clean" then "make all". | ||||
#---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||
# TODO: use config.h for build options? | |||||
VENDOR_ID = 0xFEED | VENDOR_ID = 0xFEED | ||||
PRODUCT_ID = 0xCAFE | PRODUCT_ID = 0xCAFE | ||||
MANUFACTURER = 't.m.k.' | MANUFACTURER = 't.m.k.' | ||||
PRODUCT = 't.m.k. HHKB pro' | |||||
PRODUCT = 'HHKB Mod' | |||||
DESCRIPTION = 't.m.k. firmware for HHKB pro' | DESCRIPTION = 't.m.k. firmware for HHKB pro' | ||||
MOUSE_DELAY_TIME = 127 | MOUSE_DELAY_TIME = 127 | ||||
USB_12KRO = yes | |||||
NKRO_ENABLE = true | |||||
# Target file name (without extension). | # Target file name (without extension). | ||||
TARGET = tmk_hhkb | TARGET = tmk_hhkb |
KB_NO, // FN_0 [NOT USED] | KB_NO, // FN_0 [NOT USED] | ||||
KB_NO, // FN_1 layer 1 | KB_NO, // FN_1 layer 1 | ||||
KB_SLSH, // FN_2 layer 2 | KB_SLSH, // FN_2 layer 2 | ||||
KB_SCOLON, // FN_3 layer 3 | |||||
KB_SPACE, // FN_4 layer 4 | |||||
KB_SCLN, // FN_3 layer 3 | |||||
KB_SPC, // FN_4 layer 4 | |||||
KB_NO, // FN_5 [NOT USED] | KB_NO, // FN_5 [NOT USED] | ||||
KB_NO, // FN_6 [NOT USED] | KB_NO, // FN_6 [NOT USED] | ||||
KB_NO // FN_7 layer 1 | KB_NO // FN_7 layer 1 | ||||
KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC,KB_BSPC, \ | KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC,KB_BSPC, \ | ||||
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, FN_3, KB_QUOT,KB_ENT, \ | KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, FN_3, KB_QUOT,KB_ENT, \ | ||||
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, FN_2, KB_RSFT,FN_1, \ | KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, FN_2, KB_RSFT,FN_1, \ | ||||
KB_LGUI,KB_LALT,FN_4, KB_RALT,FN_7), | |||||
KB_LGUI,KB_LALT,FN_4, KB_RALT,KB_RGUI), | |||||
/* Layer 1: HHKB mode (HHKB Fn) | /* Layer 1: HHKB mode (HHKB Fn) | ||||
* ,-----------------------------------------------------------. | * ,-----------------------------------------------------------. |
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <avr/io.h> | #include <avr/io.h> | ||||
#include <avr/interrupt.h> | |||||
#include <util/delay.h> | #include <util/delay.h> | ||||
#include "print.h" | #include "print.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
if (code == KB_NO) { | if (code == KB_NO) { | ||||
// do nothing | // do nothing | ||||
} else if (IS_MOD(code)) { | } else if (IS_MOD(code)) { | ||||
usb_keyboard_mods |= MOD_BIT(code); | |||||
usb_keyboard_add_mod(code); | |||||
} else if (IS_FN(code)) { | } else if (IS_FN(code)) { | ||||
fn_bits |= FN_BIT(code); | fn_bits |= FN_BIT(code); | ||||
} else if (IS_MOUSE(code)) { | } else if (IS_MOUSE(code)) { | ||||
// normal keys | // normal keys | ||||
else { | else { | ||||
// TODO: fix ugly code | |||||
int8_t i = 0; | |||||
int8_t empty = -1; | |||||
for (; i < KEYBOARD_REPORT_MAX; i++) { | |||||
if (usb_keyboard_keys_prev[i] == code) { | |||||
usb_keyboard_keys[i] = code; | |||||
break; | |||||
} else if (empty == -1 && usb_keyboard_keys_prev[i] == 0 && usb_keyboard_keys[i] == 0) { | |||||
empty = i; | |||||
} | |||||
} | |||||
if (i == KEYBOARD_REPORT_MAX) { | |||||
if (empty != -1) { | |||||
usb_keyboard_keys[empty] = code; | |||||
} | |||||
} | |||||
usb_keyboard_add_key(code); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
layer_switching(fn_bits); | layer_switching(fn_bits); | ||||
// TODO: clean code | // TODO: clean code | ||||
// when 4 left modifier keys down | |||||
// special mode for control, develop and debug | |||||
if (keymap_is_special_mode(fn_bits)) { | if (keymap_is_special_mode(fn_bits)) { | ||||
switch (usb_keyboard_keys[0]) { | |||||
switch (usb_keyboard_get_key()) { | |||||
case KB_H: // help | case KB_H: // help | ||||
print_enable = true; | print_enable = true; | ||||
print("b: jump to bootloader\n"); | print("b: jump to bootloader\n"); | ||||
print("d: debug print toggle\n"); | |||||
print("x: matrix debug toggle\n"); | |||||
print("k: keyboard debug toggle\n"); | |||||
print("m: mouse debug toggle\n"); | |||||
print("p: print enable toggle\n"); | |||||
print("d: toggle debug enable\n"); | |||||
print("x: toggle matrix debug\n"); | |||||
print("k: toggle keyboard debug\n"); | |||||
print("m: toggle mouse debug\n"); | |||||
print("p: toggle print enable\n"); | |||||
print("v: print version\n"); | print("v: print version\n"); | ||||
print("t: print timer count\n"); | print("t: print timer count\n"); | ||||
print("r: print registers\n"); | |||||
print("s: print status\n"); | |||||
print("`: toggle protcol(boot/report)\n"); | |||||
#ifdef NKRO_ENABLE | |||||
print("n: toggle NKRO\n"); | |||||
#endif | |||||
print("ESC: power down/wake up\n"); | print("ESC: power down/wake up\n"); | ||||
_delay_ms(500); | _delay_ms(500); | ||||
print_enable = false; | print_enable = false; | ||||
} | } | ||||
_delay_ms(1000); | _delay_ms(1000); | ||||
break; | break; | ||||
case KB_R: | |||||
case KB_S: | |||||
usb_keyboard_clear_report(); | usb_keyboard_clear_report(); | ||||
usb_keyboard_send(); | usb_keyboard_send(); | ||||
print("UDCON: "); phex(UDCON); print("\n"); | |||||
print("UDIEN: "); phex(UDIEN); print("\n"); | print("UDIEN: "); phex(UDIEN); print("\n"); | ||||
print("UDINT: "); phex(UDINT); print("\n"); | print("UDINT: "); phex(UDINT); print("\n"); | ||||
print("usb_keyboard_leds:"); phex(usb_keyboard_leds); print("\n"); | |||||
print("usb_keyboard_protocol:"); phex(usb_keyboard_protocol); print("\n"); | |||||
print("usb_keyboard_idle_config:"); phex(usb_keyboard_idle_config); print("\n"); | |||||
print("usb_keyboard_idle_count:"); phex(usb_keyboard_idle_count); print("\n"); | |||||
print("mouse_protocol:"); phex(mouse_protocol); print("\n"); | |||||
if (usb_keyboard_nkro) print("NKRO: enabled\n"); else print("NKRO: disabled\n"); | |||||
_delay_ms(500); | |||||
break; | |||||
case KB_GRV: | |||||
usb_keyboard_clear_report(); | |||||
usb_keyboard_send(); | |||||
usb_keyboard_protocol = !usb_keyboard_protocol; | |||||
mouse_protocol = !mouse_protocol; | |||||
print("keyboard protcol: "); | |||||
if (usb_keyboard_protocol) print("report"); else print("boot"); | |||||
print("\n"); | |||||
print("mouse protcol: "); | |||||
if (mouse_protocol) print("report"); else print("boot"); | |||||
print("\n"); | |||||
_delay_ms(1000); | |||||
break; | |||||
#ifdef NKRO_ENABLE | |||||
case KB_N: | |||||
usb_keyboard_clear_report(); | |||||
usb_keyboard_send(); | |||||
usb_keyboard_nkro = !usb_keyboard_nkro; | |||||
if (usb_keyboard_nkro) print("NKRO: enabled\n"); else print("NKRO: disabled\n"); | |||||
_delay_ms(1000); | _delay_ms(1000); | ||||
break; | break; | ||||
#endif | |||||
case KB_ESC: | case KB_ESC: | ||||
usb_keyboard_clear_report(); | usb_keyboard_clear_report(); | ||||
usb_keyboard_send(); | usb_keyboard_send(); |
matrix_init(); | matrix_init(); | ||||
matrix_scan(); | matrix_scan(); | ||||
// bootloader comes up when any 4 or more keys are pressed at startup | |||||
if (matrix_key_count() >= 4) { | |||||
if (matrix_key_count() >= 3) { | |||||
#ifdef DEBUG_LED | #ifdef DEBUG_LED | ||||
for (int i = 0; i < 6; i++) { | for (int i = 0; i < 6; i++) { | ||||
DEBUG_LED_CONFIG; | DEBUG_LED_CONFIG; | ||||
_delay_ms(5000); | _delay_ms(5000); | ||||
#endif | #endif | ||||
print_enable = true; | print_enable = true; | ||||
debug_enable = true; | |||||
debug_matrix = true; | |||||
debug_keyboard = true; | |||||
debug_mouse = true; | |||||
print("debug enabled.\n"); | |||||
} | |||||
if (matrix_key_count() >= 4) { | |||||
print("jump to bootloader...\n"); | print("jump to bootloader...\n"); | ||||
_delay_ms(1000); | _delay_ms(1000); | ||||
jump_bootloader(); // not return | jump_bootloader(); // not return |
// 0:control endpoint is enabled automatically by controller. | // 0:control endpoint is enabled automatically by controller. | ||||
static const uint8_t PROGMEM endpoint_config_table[] = { | static const uint8_t PROGMEM endpoint_config_table[] = { | ||||
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | // enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | ||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 1 | |||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1 | |||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2 | ||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3 | ||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4 | ||||
#ifdef USB_12KRO | |||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 5 | |||||
#ifdef NKRO_ENABLE | |||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5 | |||||
#else | #else | ||||
0, // 5 | 0, // 5 | ||||
#endif | #endif | ||||
0x95, 0x01, // Report Count (1), | 0x95, 0x01, // Report Count (1), | ||||
0x75, 0x03, // Report Size (3), | 0x75, 0x03, // Report Size (3), | ||||
0x91, 0x03, // Output (Constant), ;LED report padding | 0x91, 0x03, // Output (Constant), ;LED report padding | ||||
0x95, 0x06, // Report Count (6), | |||||
0x95, KBD_REPORT_KEYS, // Report Count (), | |||||
0x75, 0x08, // Report Size (8), | 0x75, 0x08, // Report Size (8), | ||||
0x15, 0x00, // Logical Minimum (0), | 0x15, 0x00, // Logical Minimum (0), | ||||
0x25, 0x68, // Logical Maximum(104), | |||||
0x25, 0xFF, // Logical Maximum(255), | |||||
0x05, 0x07, // Usage Page (Key Codes), | 0x05, 0x07, // Usage Page (Key Codes), | ||||
0x19, 0x00, // Usage Minimum (0), | 0x19, 0x00, // Usage Minimum (0), | ||||
0x29, 0x68, // Usage Maximum (104), | |||||
0x29, 0xFF, // Usage Maximum (255), | |||||
0x81, 0x00, // Input (Data, Array), | 0x81, 0x00, // Input (Data, Array), | ||||
0xc0 // End Collection | 0xc0 // End Collection | ||||
}; | }; | ||||
#ifdef NKRO_ENABLE | |||||
static uint8_t PROGMEM keyboard2_hid_report_desc[] = { | |||||
0x05, 0x01, // Usage Page (Generic Desktop), | |||||
0x09, 0x06, // Usage (Keyboard), | |||||
0xA1, 0x01, // Collection (Application), | |||||
0x75, 0x01, // Report Size (1), | |||||
0x95, 0x08, // Report Count (8), | |||||
0x05, 0x07, // Usage Page (Key Codes), | |||||
0x19, 0xE0, // Usage Minimum (224), | |||||
0x29, 0xE7, // Usage Maximum (231), | |||||
0x15, 0x00, // Logical Minimum (0), | |||||
0x25, 0x01, // Logical Maximum (1), | |||||
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | |||||
0x95, 0x01, // Report Count (1), | |||||
0x75, 0x08, // Report Size (8), | |||||
0x81, 0x03, // Input (Constant), ;Reserved byte | |||||
0x95, 0x05, // Report Count (5), | |||||
0x75, 0x01, // Report Size (1), | |||||
0x05, 0x08, // Usage Page (LEDs), | |||||
0x19, 0x01, // Usage Minimum (1), | |||||
0x29, 0x05, // Usage Maximum (5), | |||||
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report | |||||
0x95, 0x01, // Report Count (1), | |||||
0x75, 0x03, // Report Size (3), | |||||
0x91, 0x03, // Output (Constant), ;LED report padding | |||||
0x95, KBD2_REPORT_KEYS*8, // Report Count (), | |||||
0x75, 0x01, // Report Size (1), | |||||
0x15, 0x00, // Logical Minimum (0), | |||||
0x25, 0x01, // Logical Maximum(1), | |||||
0x05, 0x07, // Usage Page (Key Codes), | |||||
0x19, 0x00, // Usage Minimum (0), | |||||
0x29, KBD2_REPORT_KEYS*8-1, // Usage Maximum (), | |||||
0x81, 0x02, // Input (Data, Variable, Absolute), | |||||
0xc0 // End Collection | |||||
}; | |||||
#endif | |||||
// 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 | ||||
// http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | // http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | ||||
0xc0 // END_COLLECTION | 0xc0 // END_COLLECTION | ||||
}; | }; | ||||
#define KEYBOARD_HID_DESC_OFFSET (9+(9+9+7)*0+9) | |||||
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*1+9) | |||||
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*2+9) | |||||
#define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*3+9) | |||||
#ifdef USB_12KRO | |||||
# define NUM_INTERFACES 5 | |||||
# define KEYBOARD2_HID_DESC_OFFSET (9+(9+9+7)*4+9) | |||||
#define KBD_HID_DESC_OFFSET (9+(9+9+7)*0+9) | |||||
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*1+9) | |||||
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*2+9) | |||||
#define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*3+9) | |||||
#ifdef NKRO_ENABLE | |||||
# define NUM_INTERFACES 5 | |||||
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*4+9) | |||||
#else | #else | ||||
# define NUM_INTERFACES 4 | |||||
# define NUM_INTERFACES 4 | |||||
#endif | #endif | ||||
#define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES) | |||||
#define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES) | |||||
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | static 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 | ||||
9, // bLength; | 9, // bLength; | ||||
// 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 | ||||
KEYBOARD_INTERFACE, // bInterfaceNumber | |||||
KBD_INTERFACE, // bInterfaceNumber | |||||
0, // bAlternateSetting | 0, // bAlternateSetting | ||||
1, // bNumEndpoints | 1, // bNumEndpoints | ||||
0x03, // bInterfaceClass (0x03 = HID) | 0x03, // bInterfaceClass (0x03 = HID) | ||||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||||
7, // bLength | 7, // bLength | ||||
5, // bDescriptorType | 5, // bDescriptorType | ||||
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress | |||||
KBD_ENDPOINT | 0x80, // bEndpointAddress | |||||
0x03, // bmAttributes (0x03=intr) | 0x03, // bmAttributes (0x03=intr) | ||||
KEYBOARD_SIZE, 0, // wMaxPacketSize | |||||
1, // bInterval | |||||
KBD_SIZE, 0, // wMaxPacketSize | |||||
10, // bInterval | |||||
// 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 | ||||
0, // bAlternateSetting | 0, // bAlternateSetting | ||||
1, // bNumEndpoints | 1, // bNumEndpoints | ||||
0x03, // bInterfaceClass (0x03 = HID) | 0x03, // bInterfaceClass (0x03 = HID) | ||||
// ThinkPad T23 BIOS doesn't work with boot mouse. | |||||
0x00, // bInterfaceSubClass (0x01 = Boot) | |||||
0x00, // bInterfaceProtocol (0x02 = Mouse) | |||||
/* | |||||
0x01, // bInterfaceSubClass (0x01 = Boot) | 0x01, // bInterfaceSubClass (0x01 = Boot) | ||||
0x02, // bInterfaceProtocol (0x02 = Mouse) | 0x02, // bInterfaceProtocol (0x02 = Mouse) | ||||
*/ | |||||
0, // iInterface | 0, // iInterface | ||||
// HID descriptor, HID 1.11 spec, section 6.2.1 | // HID descriptor, HID 1.11 spec, section 6.2.1 | ||||
9, // bLength | 9, // bLength | ||||
EXTRA_SIZE, 0, // wMaxPacketSize | EXTRA_SIZE, 0, // wMaxPacketSize | ||||
10, // bInterval | 10, // bInterval | ||||
#ifdef USB_12KRO | |||||
#ifdef NKRO_ENABLE | |||||
// 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 | ||||
KEYBOARD_INTERFACE2, // bInterfaceNumber | |||||
KBD2_INTERFACE, // bInterfaceNumber | |||||
0, // bAlternateSetting | 0, // bAlternateSetting | ||||
1, // bNumEndpoints | 1, // bNumEndpoints | ||||
0x03, // bInterfaceClass (0x03 = HID) | 0x03, // bInterfaceClass (0x03 = HID) | ||||
0, // bCountryCode | 0, // bCountryCode | ||||
1, // bNumDescriptors | 1, // bNumDescriptors | ||||
0x22, // bDescriptorType | 0x22, // bDescriptorType | ||||
sizeof(keyboard_hid_report_desc), // wDescriptorLength | |||||
sizeof(keyboard2_hid_report_desc), // wDescriptorLength | |||||
0, | 0, | ||||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | ||||
7, // bLength | 7, // bLength | ||||
5, // bDescriptorType | 5, // bDescriptorType | ||||
KEYBOARD_ENDPOINT2 | 0x80, // bEndpointAddress | |||||
KBD2_ENDPOINT | 0x80, // bEndpointAddress | |||||
0x03, // bmAttributes (0x03=intr) | 0x03, // bmAttributes (0x03=intr) | ||||
KEYBOARD_SIZE, 0, // wMaxPacketSize | |||||
KBD2_SIZE, 0, // wMaxPacketSize | |||||
1, // bInterval | 1, // bInterval | ||||
#endif | #endif | ||||
}; | }; | ||||
// CONFIGURATION descriptor | // CONFIGURATION descriptor | ||||
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, | {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, | ||||
// HID/REPORT descriptors | // HID/REPORT descriptors | ||||
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9}, | |||||
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | |||||
{0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9}, | |||||
{0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | |||||
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | {0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | ||||
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | {0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | ||||
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_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, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9}, | {0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9}, | ||||
{0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)}, | {0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)}, | ||||
#ifdef USB_12KRO | |||||
{0x2100, KEYBOARD_INTERFACE2, config1_descriptor+KEYBOARD2_HID_DESC_OFFSET, 9}, | |||||
{0x2200, KEYBOARD_INTERFACE2, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | |||||
#ifdef NKRO_ENABLE | |||||
{0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9}, | |||||
{0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)}, | |||||
#endif | #endif | ||||
// STRING descriptors | // STRING descriptors | ||||
{0x0300, 0x0000, (const uint8_t *)&string0, 4}, | {0x0300, 0x0000, (const uint8_t *)&string0, 4}, | ||||
} | } | ||||
} | } | ||||
if (usb_keyboard_idle_config && (++div4 & 3) == 0) { | if (usb_keyboard_idle_config && (++div4 & 3) == 0) { | ||||
UENUM = KEYBOARD_ENDPOINT; | |||||
UENUM = KBD_ENDPOINT; | |||||
if (UEINTX & (1<<RWAL)) { | if (UEINTX & (1<<RWAL)) { | ||||
usb_keyboard_idle_count++; | usb_keyboard_idle_count++; | ||||
if (usb_keyboard_idle_count == usb_keyboard_idle_config) { | if (usb_keyboard_idle_count == usb_keyboard_idle_config) { | ||||
for (i=1; i<=6; i++) { | for (i=1; i<=6; i++) { | ||||
UENUM = i; | UENUM = i; | ||||
en = pgm_read_byte(cfg++); | en = pgm_read_byte(cfg++); | ||||
UECONX = en; | |||||
if (en) { | |||||
UECFG0X = pgm_read_byte(cfg++); | |||||
UECFG1X = pgm_read_byte(cfg++); | |||||
if (en) { | |||||
UECONX = (1<<EPEN); | |||||
UECFG0X = pgm_read_byte(cfg++); | |||||
UECFG1X = pgm_read_byte(cfg++); | |||||
} else { | |||||
UECONX = 0; | |||||
} | } | ||||
} | } | ||||
UERST = 0x7E; | UERST = 0x7E; | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
if (wIndex == KEYBOARD_INTERFACE) { | |||||
if (wIndex == KBD_INTERFACE) { | |||||
if (bmRequestType == 0xA1) { | if (bmRequestType == 0xA1) { | ||||
if (bRequest == HID_GET_REPORT) { | if (bRequest == HID_GET_REPORT) { | ||||
usb_wait_in_ready(); | usb_wait_in_ready(); |
#include "usb_keyboard.h" | #include "usb_keyboard.h" | ||||
#include "print.h" | #include "print.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "util.h" | |||||
// keyboard report. | // keyboard report. | ||||
static usb_keyboard_report_t _report0 = { {0}, 0 }; | |||||
static usb_keyboard_report_t _report1 = { {0}, 0 }; | |||||
static usb_keyboard_report_t _report0 = { {0}, 0, false }; | |||||
static usb_keyboard_report_t _report1 = { {0}, 0, false }; | |||||
usb_keyboard_report_t *usb_keyboard_report = &_report0; | usb_keyboard_report_t *usb_keyboard_report = &_report0; | ||||
usb_keyboard_report_t *usb_keyboard_report_prev = &_report1; | usb_keyboard_report_t *usb_keyboard_report_prev = &_report1; | ||||
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | // 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | ||||
volatile uint8_t usb_keyboard_leds=0; | volatile uint8_t usb_keyboard_leds=0; | ||||
// enable NKRO | |||||
bool usb_keyboard_nkro = false; | |||||
int8_t usb_keyboard_send(void) | int8_t usb_keyboard_send(void) | ||||
{ | { | ||||
return usb_keyboard_send_report(usb_keyboard_report); | return usb_keyboard_send_report(usb_keyboard_report); | ||||
} | } | ||||
static inline int8_t _send_report(usb_keyboard_report_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end); | |||||
int8_t usb_keyboard_send_report(usb_keyboard_report_t *report) | int8_t usb_keyboard_send_report(usb_keyboard_report_t *report) | ||||
{ | { | ||||
uint8_t i, intr_state, timeout; | |||||
if (!usb_configured()) return -1; | |||||
intr_state = SREG; | |||||
cli(); | |||||
UENUM = KEYBOARD_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_configured()) return -1; | |||||
// have we waited too long? | |||||
if (UDFNUML == timeout) return -1; | |||||
// get ready to try checking again | |||||
intr_state = SREG; | |||||
cli(); | |||||
UENUM = KEYBOARD_ENDPOINT; | |||||
} | |||||
UEDATX = report->mods; | |||||
UEDATX = 0; | |||||
for (i = 0; i < 6; i++) { | |||||
UEDATX = report->keys[i]; | |||||
} | |||||
UEINTX = 0x3A; | |||||
SREG = intr_state; | |||||
#ifdef USB_12KRO | |||||
if (!usb_configured()) return -1; | |||||
intr_state = SREG; | |||||
cli(); | |||||
UENUM = KEYBOARD_ENDPOINT2; | |||||
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_configured()) return -1; | |||||
// have we waited too long? | |||||
if (UDFNUML == timeout) return -1; | |||||
// get ready to try checking again | |||||
intr_state = SREG; | |||||
cli(); | |||||
UENUM = KEYBOARD_ENDPOINT2; | |||||
} | |||||
UEDATX = report->mods; | |||||
UEDATX = 0; | |||||
for (i = 6; i < 12; i++) { | |||||
UEDATX = report->keys[i]; | |||||
} | |||||
UEINTX = 0x3A; | |||||
SREG = intr_state; | |||||
int8_t result = 0; | |||||
#ifdef NKRO_ENABLE | |||||
if (usb_keyboard_nkro) | |||||
result = _send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS); | |||||
else | |||||
#endif | #endif | ||||
{ | |||||
if (usb_keyboard_protocol) | |||||
result = _send_report(report, KBD_ENDPOINT, 0, KBD_REPORT_KEYS); | |||||
else | |||||
result = _send_report(report, KBD_ENDPOINT, 0, 6); | |||||
} | |||||
usb_keyboard_idle_count = 0; | |||||
report->is_sent =true; | |||||
usb_keyboard_print_report(report); | |||||
return 0; | |||||
if (result) return result; | |||||
usb_keyboard_idle_count = 0; | |||||
report->is_sent =true; | |||||
usb_keyboard_print_report(report); | |||||
return 0; | |||||
} | } | ||||
void usb_keyboard_swap_report(void) { | void usb_keyboard_swap_report(void) { | ||||
} | } | ||||
void usb_keyboard_clear_keys(void) { | void usb_keyboard_clear_keys(void) { | ||||
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) usb_keyboard_report->keys[i] = 0; | |||||
for (int i = 0; i < KEYS_MAX; i++) usb_keyboard_report->keys[i] = 0; | |||||
} | } | ||||
void usb_keyboard_clear_mods(void) | void usb_keyboard_clear_mods(void) | ||||
usb_keyboard_report->mods = 0; | usb_keyboard_report->mods = 0; | ||||
} | } | ||||
void usb_keyboard_set_keys(uint8_t *keys) | |||||
{ | |||||
for (int i = 0; i < KEYS_MAX; i++) | |||||
usb_keyboard_report->keys[i] = keys[i]; | |||||
} | |||||
void usb_keyboard_set_mods(uint8_t mods) | |||||
{ | |||||
usb_keyboard_report->mods = mods; | |||||
} | |||||
void usb_keyboard_add_code(uint8_t code) | void usb_keyboard_add_code(uint8_t code) | ||||
{ | { | ||||
if (IS_MOD(code)) { | if (IS_MOD(code)) { | ||||
} | } | ||||
} | } | ||||
static inline void _add_key_byte(uint8_t code); | |||||
static inline void _add_key_bit(uint8_t code); | |||||
void usb_keyboard_add_key(uint8_t code) | void usb_keyboard_add_key(uint8_t code) | ||||
{ | { | ||||
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) { | |||||
if (!usb_keyboard_report->keys[i]) { | |||||
usb_keyboard_report->keys[i] = code; | |||||
return; | |||||
} | |||||
#ifdef NKRO_ENABLE | |||||
if (usb_keyboard_nkro) { | |||||
_add_key_bit(code); | |||||
return; | |||||
} | } | ||||
} | |||||
void usb_keyboard_set_keys(uint8_t *keys) | |||||
{ | |||||
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) | |||||
usb_keyboard_report->keys[i] = keys[i]; | |||||
} | |||||
void usb_keyboard_set_mods(uint8_t mods) | |||||
{ | |||||
usb_keyboard_report->mods = mods; | |||||
#endif | |||||
_add_key_byte(code); | |||||
} | } | ||||
void usb_keyboard_add_mod(uint8_t code) | void usb_keyboard_add_mod(uint8_t code) | ||||
void usb_keyboard_del_key(uint8_t code) | void usb_keyboard_del_key(uint8_t code) | ||||
{ | { | ||||
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) { | |||||
#ifdef NKRO_ENABLE | |||||
if ((code>>3) < KEYS_MAX) { | |||||
usb_keyboard_keys[code>>3] &= ~(1<<(code&7)); | |||||
} | |||||
#else | |||||
for (int i = 0; i < KEYS_MAX; i++) { | |||||
if (usb_keyboard_report->keys[i] == code) { | if (usb_keyboard_report->keys[i] == code) { | ||||
usb_keyboard_report->keys[i] = KB_NO; | usb_keyboard_report->keys[i] = KB_NO; | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
#endif | |||||
} | } | ||||
void usb_keyboard_del_mod(uint8_t code) | void usb_keyboard_del_mod(uint8_t code) | ||||
bool usb_keyboard_has_key(void) | bool usb_keyboard_has_key(void) | ||||
{ | { | ||||
uint8_t keys = 0; | uint8_t keys = 0; | ||||
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) keys |= usb_keyboard_report->keys[i]; | |||||
for (int i = 0; i < KEYS_MAX; i++) keys |= usb_keyboard_report->keys[i]; | |||||
return keys ? true : false; | return keys ? true : false; | ||||
} | } | ||||
return usb_keyboard_report->mods ? true : false; | return usb_keyboard_report->mods ? true : false; | ||||
} | } | ||||
uint8_t usb_keyboard_get_key(void) | |||||
{ | |||||
#ifdef NKRO_ENABLE | |||||
if (usb_keyboard_nkro) { | |||||
uint8_t i = 0; | |||||
for (; i < KEYS_MAX && !usb_keyboard_keys[i]; i++); | |||||
return i<<3 | biton(usb_keyboard_keys[i]); | |||||
} | |||||
#endif | |||||
return usb_keyboard_keys[0]; | |||||
} | |||||
void usb_keyboard_print_report(usb_keyboard_report_t *report) | void usb_keyboard_print_report(usb_keyboard_report_t *report) | ||||
{ | { | ||||
if (!debug_keyboard) return; | if (!debug_keyboard) return; | ||||
print("keys: "); | print("keys: "); | ||||
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) { phex(report->keys[i]); print(" "); } | |||||
for (int i = 0; i < KEYS_MAX; i++) { phex(report->keys[i]); print(" "); } | |||||
print(" mods: "); phex(report->mods); print("\n"); | print(" mods: "); phex(report->mods); print("\n"); | ||||
} | } | ||||
static inline int8_t _send_report(usb_keyboard_report_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end) | |||||
{ | |||||
uint8_t intr_state, timeout; | |||||
if (!usb_configured()) return -1; | |||||
intr_state = SREG; | |||||
cli(); | |||||
UENUM = 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_configured()) return -1; | |||||
// have we waited too long? | |||||
if (UDFNUML == timeout) return -1; | |||||
// get ready to try checking again | |||||
intr_state = SREG; | |||||
cli(); | |||||
UENUM = endpoint; | |||||
} | |||||
UEDATX = report->mods; | |||||
UEDATX = 0; | |||||
for (uint8_t i = keys_start; i < keys_end; i++) { | |||||
UEDATX = report->keys[i]; | |||||
} | |||||
UEINTX = 0x3A; | |||||
SREG = intr_state; | |||||
return 0; | |||||
} | |||||
static inline void _add_key_byte(uint8_t code) | |||||
{ | |||||
// TODO: fix ugly code | |||||
int8_t i = 0; | |||||
int8_t empty = -1; | |||||
for (; i < KEYS_MAX; i++) { | |||||
if (usb_keyboard_keys_prev[i] == code) { | |||||
usb_keyboard_keys[i] = code; | |||||
break; | |||||
} | |||||
if (empty == -1 && | |||||
usb_keyboard_keys_prev[i] == 0 && | |||||
usb_keyboard_keys[i] == 0) { | |||||
empty = i; | |||||
} | |||||
} | |||||
if (i == KEYS_MAX) { | |||||
if (empty != -1) { | |||||
usb_keyboard_keys[empty] = code; | |||||
} | |||||
} | |||||
} | |||||
static inline void _add_key_bit(uint8_t code) | |||||
{ | |||||
if ((code>>3) < KEYS_MAX) { | |||||
usb_keyboard_keys[code>>3] |= 1<<(code&7); | |||||
} | |||||
} | |||||
#include "usb.h" | #include "usb.h" | ||||
#define KEYBOARD_INTERFACE 0 | |||||
#define KEYBOARD_ENDPOINT 1 | |||||
#ifdef USB_12KRO | |||||
#define KEYBOARD_INTERFACE2 4 | |||||
#define KEYBOARD_ENDPOINT2 5 | |||||
#define KBD_INTERFACE 0 | |||||
#define KBD_ENDPOINT 1 | |||||
#define KBD_SIZE 8 | |||||
#define KBD_BUFFER EP_DOUBLE_BUFFER | |||||
#define KBD_REPORT_KEYS (KBD_SIZE - 2) | |||||
// secondary keyboard | |||||
#ifdef NKRO_ENABLE | |||||
#define KBD2_INTERFACE 4 | |||||
#define KBD2_ENDPOINT 5 | |||||
#define KBD2_SIZE 16 | |||||
#define KBD2_BUFFER EP_DOUBLE_BUFFER | |||||
#define KBD2_REPORT_KEYS (KBD2_SIZE - 2) | |||||
#endif | |||||
#if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS | |||||
#define KEYS_MAX KBD2_REPORT_KEYS | |||||
#else | |||||
#define KEYS_MAX KBD_REPORT_KEYS | |||||
#endif | #endif | ||||
#define KEYBOARD_SIZE 8 | |||||
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER | |||||
#define BIT_LCTRL (1<<0) | #define BIT_LCTRL (1<<0) | ||||
#define BIT_LSHIFT (1<<1) | #define BIT_LSHIFT (1<<1) | ||||
#define BIT_LSFT BIT_LSHIFT | #define BIT_LSFT BIT_LSHIFT | ||||
#define BIT_RSFT BIT_RSHIFT | #define BIT_RSFT BIT_RSHIFT | ||||
#ifdef USB_12KRO | |||||
# define KEYBOARD_REPORT_MAX 12 | |||||
#else | |||||
# define KEYBOARD_REPORT_MAX 6 | |||||
#endif | |||||
typedef struct report { | typedef struct report { | ||||
uint8_t keys[KEYBOARD_REPORT_MAX]; | |||||
uint8_t keys[KEYS_MAX]; | |||||
uint8_t mods; | uint8_t mods; | ||||
bool is_sent; | bool is_sent; | ||||
} usb_keyboard_report_t; | } usb_keyboard_report_t; | ||||
extern uint8_t usb_keyboard_idle_config; | extern uint8_t usb_keyboard_idle_config; | ||||
extern uint8_t usb_keyboard_idle_count; | extern uint8_t usb_keyboard_idle_count; | ||||
extern volatile uint8_t usb_keyboard_leds; | extern volatile uint8_t usb_keyboard_leds; | ||||
extern bool usb_keyboard_nkro; | |||||
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier); | |||||
int8_t usb_keyboard_send(void); | int8_t usb_keyboard_send(void); | ||||
int8_t usb_keyboard_send_report(usb_keyboard_report_t *report); | int8_t usb_keyboard_send_report(usb_keyboard_report_t *report); | ||||
void usb_keyboard_clear_keys(void); | void usb_keyboard_clear_keys(void); | ||||
void usb_keyboard_clear_mods(void); | void usb_keyboard_clear_mods(void); | ||||
void usb_keyboard_set_keys(uint8_t keys[6]); | |||||
void usb_keyboard_set_keys(uint8_t *keys); | |||||
void usb_keyboard_set_mods(uint8_t mods); | void usb_keyboard_set_mods(uint8_t mods); | ||||
void usb_keyboard_add_code(uint8_t code); | void usb_keyboard_add_code(uint8_t code); | ||||
bool usb_keyboard_has_key(void); | bool usb_keyboard_has_key(void); | ||||
bool usb_keyboard_has_mod(void); | bool usb_keyboard_has_mod(void); | ||||
uint8_t usb_keyboard_get_key(void); | |||||
void usb_keyboard_print_report(usb_keyboard_report_t *report); | void usb_keyboard_print_report(usb_keyboard_report_t *report); | ||||
#endif | #endif |
UEDATX = mouse_buttons; | UEDATX = mouse_buttons; | ||||
UEDATX = x; | UEDATX = x; | ||||
UEDATX = y; | UEDATX = y; | ||||
UEDATX = wheel; | |||||
UEDATX = hwheel; | |||||
if (mouse_protocol) { | |||||
UEDATX = wheel; | |||||
UEDATX = hwheel; | |||||
} | |||||
UEINTX = 0x3A; | UEINTX = 0x3A; | ||||
SREG = intr_state; | SREG = intr_state; |
#include "util.h" | #include "util.h" | ||||
// bit population | |||||
int bitpop(uint8_t bits) | int bitpop(uint8_t bits) | ||||
{ | { | ||||
int c; | int c; | ||||
return c; | return c; | ||||
} | } | ||||
// most significant on-bit | |||||
int biton(uint8_t bits) | int biton(uint8_t bits) | ||||
{ | { | ||||
int n = 0; | int n = 0; |