Has the been any work on this for Teensy3? It look like the core structure is much different on Teensy3 relative to Teensy2. I would like to get more than 6 simultaneous keystrokes at once.
I found a teensy3 nkro patch here:
https://dawnmist.dreamwidth.org/1250.html
Direct link to patch:
http://www.dawnmist.net/teensy/teensy3_nkro.patch.txt
This patch does not apply as-is, because it is for some 2013-version of teensyduino.
I have ported it to teensyduino 1.34, so my teensy3.5 keyboard test program can press 36 keys simultanously. Possibly more, I havent bothered testing more than a-z0-9
My patch:
diff -uN teensy3.org/usb_desc.c teensy3/usb_desc.c
--- teensy3.org/usb_desc.c 2017-01-12 00:06:43.000000000 +0100
+++ teensy3/usb_desc.c 2017-02-12 00:26:23.678539074 +0100
@@ -168,6 +168,33 @@
0xC0 // End Collection
};
#endif
+
+#ifdef NKRO_INTERFACE
+static uint8_t nkro_hid_report_desc[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x06, // Usage (Keyboard),
+ 0xA1, 0x01, // Collection (Application),
+ // bitmap of modifiers
+ 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
+ // bitmap of keys
+ 0x95, NKRO_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, NKRO_REPORT_KEYS*8-1, // Usage Maximum (),
+ 0x81, 0x02, // Input (Data, Variable, Absolute),
+ 0xc0 // End Collection
+};
+#endif
#ifdef MOUSE_INTERFACE
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
@@ -458,7 +485,15 @@
#define JOYSTICK_INTERFACE_DESC_SIZE 0
#endif
-#define MTP_INTERFACE_DESC_POS JOYSTICK_INTERFACE_DESC_POS+JOYSTICK_INTERFACE_DESC_SIZE
+#define NKRO_INTERFACE_DESC_POS JOYSTICK_INTERFACE_DESC_POS+JOYSTICK_INTERFACE_DESC_SIZE
+#ifdef NKRO_INTERFACE
+#define NKRO_INTERFACE_DESC_SIZE 9+9+7
+#define NKRO_DESC_OFFSET NKRO_INTERFACE_DESC_POS+9
+#else
+#define NKRO_INTERFACE_DESC_SIZE 0
+#endif
+
+#define MTP_INTERFACE_DESC_POS NKRO_INTERFACE_DESC_POS+NKRO_INTERFACE_DESC_SIZE
#ifdef MTP_INTERFACE
#define MTP_INTERFACE_DESC_SIZE 9+7+7+7
#else
@@ -866,6 +901,35 @@
JOYSTICK_INTERVAL, // bInterval
#endif // JOYSTICK_INTERFACE
+#ifdef NKRO_INTERFACE
+ // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+ 9, // bLength
+ 4, // bDescriptorType
+ NKRO_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass (0x03 = HID)
+ 0x00, // bInterfaceSubClass (0x01 = Boot)
+ 0x00, // bInterfaceProtocol (0x01 = Keyboard)
+ 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(nkro_hid_report_desc)), // wDescriptorLength
+ MSB(sizeof(nkro_hid_report_desc)),
+ // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+ 7, // bLength
+ 5, // bDescriptorType
+ NKRO_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (0x03=intr)
+ NKRO_SIZE, 0, // wMaxPacketSize
+ NKRO_INTERVAL, // bInterval
+#endif // NKRO_INTERFACE
+
#ifdef MTP_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
@@ -1285,6 +1349,11 @@
{0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)},
{0x2100, JOYSTICK_INTERFACE, config_descriptor+JOYSTICK_HID_DESC_OFFSET, 9},
#endif
+#ifdef NKRO_INTERFACE
+ {0x2200, NKRO_INTERFACE, nkro_hid_report_desc, sizeof(nkro_hid_report_desc)},
+ {0x2100, NKRO_INTERFACE, config_descriptor+NKRO_DESC_OFFSET, 9},
+#endif
+
#ifdef RAWHID_INTERFACE
{0x2200, RAWHID_INTERFACE, rawhid_report_desc, sizeof(rawhid_report_desc)},
{0x2100, RAWHID_INTERFACE, config_descriptor+RAWHID_HID_DESC_OFFSET, 9},
diff -uN teensy3.org/usb_desc.h teensy3/usb_desc.h
--- teensy3.org/usb_desc.h 2017-01-12 00:06:43.000000000 +0100
+++ teensy3/usb_desc.h 2017-02-11 23:20:41.338335964 +0100
@@ -205,6 +205,13 @@
#define JOYSTICK_ENDPOINT 4
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 2
+//NKRO!!!
+ #define NKRO_INTERFACE 4
+ #define NKRO_ENDPOINT 6
+ #define NKRO_SIZE 32
+ #define NKRO_REPORT_KEYS ( NKRO_SIZE - 1 )
+ #define NKRO_INTERVAL 1
+
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
@@ -251,6 +258,13 @@
#define JOYSTICK_ENDPOINT 6
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 1
+//NKRO!!!
+ #define NKRO_INTERFACE 5 // NKRO interface
+ #define NKRO_ENDPOINT 7
+ #define NKRO_SIZE 32
+ #define NKRO_REPORT_KEYS ( NKRO_SIZE - 1 )
+ #define NKRO_INTERVAL 1
+
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY
diff -uN teensy3.org/usb_dev.h teensy3/usb_dev.h
--- teensy3.org/usb_dev.h 2017-01-12 00:06:43.000000000 +0100
+++ teensy3/usb_dev.h 2017-02-11 23:22:22.354419241 +0100
@@ -90,6 +90,15 @@
extern volatile uint8_t keyboard_leds;
#endif
+#ifdef NKRO_INTERFACE
+extern uint8_t nkro_report_data[NKRO_SIZE];
+extern uint8_t nkro_protocol;
+extern uint8_t nkro_idle_config;
+extern uint8_t nkro_idle_count;
+#endif
+
+
+
#ifdef MIDI_INTERFACE
extern void usb_midi_flush_output(void);
#endif
diff -uN teensy3.org/usb_inst.cpp teensy3/usb_inst.cpp
--- teensy3.org/usb_inst.cpp 2017-01-12 00:06:43.000000000 +0100
+++ teensy3/usb_inst.cpp 2017-02-11 23:27:52.643416932 +0100
@@ -72,6 +72,9 @@
usb_serial_class Serial;
#endif
+#ifdef NKRO_INTERFACE
+usb_nkro_class Nkro;
+#endif
#else // F_CPU < 20 MHz
diff -uN teensy3.org/usb_nkro.c teensy3/usb_nkro.c
--- teensy3.org/usb_nkro.c 1970-01-01 01:00:00.000000000 +0100
+++ teensy3/usb_nkro.c 2017-02-12 00:29:33.317014148 +0100
@@ -0,0 +1,133 @@
+#include "usb_dev.h"
+#include "usb_nkro.h"
+#include "core_pins.h" // for yield()
+#include "keylayouts.h"
+//#include "HardwareSerial.h"
+#include <string.h> // for memcpy()
+
+#ifdef NKRO_INTERFACE // defined by usb_dev.h -> usb_desc.h
+
+// byte0: which modifier keys are currently pressed
+// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui
+// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui
+// bytes1-NKRO_SIZE: which keys are currently pressed, one bit
+// per key for codes 0 to ((8*NKRO_REPORT_SIZE) - 1)
+uint8_t nkro_report_data[NKRO_SIZE];
+
+// protocol setting from the host. We use exactly the same report
+// either way, so this variable only stores the setting since we
+// are required to be able to report which setting is in use.
+uint8_t nkro_protocol=1;
+
+// the idle configuration, how often we send the report to the
+// host (ms * 4) even when it hasn't changed
+uint8_t nkro_idle_config=125;
+
+// count until idle timeout
+uint8_t nkro_idle_count=0;
+
+
+// NKRO Keyboard
+void usb_nkro_reset_keys()
+{
+ uint8_t index;
+ for (index=0; index < NKRO_SIZE; index++)
+ {
+ nkro_report_data[index] = 0;
+ }
+}
+
+void usb_nkro_reset_key(uint8_t usb_keycode)
+{
+ uint8_t bit = usb_keycode % 8;
+ uint8_t byte = (usb_keycode / 8) + 1;
+
+ if (usb_keycode >= 240 && usb_keycode <= 247)
+ {
+ // Reset a modifier key
+ nkro_report_data[0] &= ~(1<< bit);
+ }
+ else if (byte > 0 && byte <= NKRO_REPORT_KEYS)
+ {
+ nkro_report_data[byte] &= ~(1 << bit);
+ }
+}
+
+void usb_nkro_set_key(uint8_t usb_keycode)
+{
+ uint8_t bit = usb_keycode % 8;
+ uint8_t byte = (usb_keycode / 8) + 1;
+
+ if (usb_keycode >= 240 && usb_keycode <= 247)
+ {
+ // Reset a modifier key
+ nkro_report_data[0] |= (1 << bit);
+ }
+ else if (byte > 0 && byte <= NKRO_REPORT_KEYS)
+ {
+ nkro_report_data[byte] |= (1 << bit);
+ }
+}
+
+// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
+#define TX_PACKET_LIMIT 4
+
+static uint8_t transmit_previous_timeout=0;
+
+// When the PC isn't listening, how long do we wait before discarding data?
+#define TX_TIMEOUT_MSEC 50
+
+#if F_CPU == 240000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600)
+#elif F_CPU == 216000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440)
+#elif F_CPU == 192000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280)
+#elif F_CPU == 180000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200)
+#elif F_CPU == 168000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100)
+#elif F_CPU == 144000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932)
+#elif F_CPU == 120000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764)
+#elif F_CPU == 96000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
+#elif F_CPU == 72000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512)
+#elif F_CPU == 48000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
+#elif F_CPU == 24000000
+ #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
+#endif
+
+
+int usb_nkro_send_nkro_now(void)
+{
+ uint32_t wait_count=0;
+ usb_packet_t *tx_packet;
+
+ while (1) {
+ if (!usb_configuration) {
+ return -1;
+ }
+ if (usb_tx_packet_count(NKRO_ENDPOINT) < TX_PACKET_LIMIT) {
+ tx_packet = usb_malloc();
+ if (tx_packet) break;
+ }
+ if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) {
+ transmit_previous_timeout = 1;
+ return -1;
+ }
+ yield();
+ }
+ memcpy(tx_packet->buf, nkro_report_data, NKRO_SIZE);
+ tx_packet->len = NKRO_SIZE;
+ usb_tx(NKRO_ENDPOINT, tx_packet);
+
+ return 0;
+
+}
+
+#endif // NKRO_INTERFACE
+
diff -uN teensy3.org/usb_nkro.h teensy3/usb_nkro.h
--- teensy3.org/usb_nkro.h 1970-01-01 01:00:00.000000000 +0100
+++ teensy3/usb_nkro.h 2017-02-11 23:30:28.097654975 +0100
@@ -0,0 +1,42 @@
+#ifndef USBnkro_h_
+#define USBnkro_h_
+
+#include "keylayouts.h"
+
+#if defined(USB_HID) || defined(USB_SERIAL_HID)
+
+#include <inttypes.h>
+
+// C language implementation
+#ifdef __cplusplus
+extern "C" {
+#endif
+void usb_nkro_reset_keys();
+void usb_nkro_reset_key(uint8_t key);
+void usb_nkro_set_key(uint8_t key);
+int usb_nkro_send_nkro_now();
+#ifdef __cplusplus
+}
+#endif
+
+
+
+// C++ interface
+#ifdef __cplusplus
+#include "Stream.h"
+
+class usb_nkro_class
+{
+ public:
+ void reset_keys() { usb_nkro_reset_keys(); }
+ void reset_key(uint8_t key) { usb_nkro_reset_key(key); }
+ void set_key(uint8_t key) { usb_nkro_set_key(key); }
+ int send_nkro_now(void) { return usb_nkro_send_nkro_now(); }
+};
+
+extern usb_nkro_class Nkro;
+
+#endif // __cplusplus
+
+#endif // USB_HID || USB_SERIAL_HID
+#endif // USBnkro_h_
Vanlige undermapper: teensy3.org/util og teensy3/util
diff -uN teensy3.org/WProgram.h teensy3/WProgram.h
--- teensy3.org/WProgram.h 2017-01-12 00:06:43.000000000 +0100
+++ teensy3/WProgram.h 2017-02-11 22:59:10.769789644 +0100
@@ -24,6 +24,7 @@
#include "usb_serial.h"
#include "usb_seremu.h"
#include "usb_keyboard.h"
+#include "usb_nkro.h"
#include "usb_mouse.h"
#include "usb_joystick.h"
#include "usb_midi.h"
nkro.ino test code:
#include "usb_nkro.h"
void loop() {
//one key at a time
for (int k=4;k<=40;++k) {
Nkro.set_key(k);
Nkro.send_nkro_now();
Nkro.reset_key(k);
}
Nkro.send_nkro_now();
delay(1000);
//press 36 keys:
for (int k=4;k<=39;++k) Nkro.set_key(k);
Nkro.send_nkro_now(); //Send all
Nkro.reset_keys(); //release all
Nkro.set_key(40); //enter
Nkro.send_nkro_now();
Nkro.reset_key(40);
Nkro.send_nkro_now();
delay(1000);
}
Some computers will get all 36 keys, some will drop a few.
The key numbers are documented in the USB standards. 4=a,5=b,6=c and so on. After the alphabet comes 0-9, then more special keys.
The Nkro object is automatically defined if the arduino USB type includes "keyboard".
Nkro.set_key( ); //set a key to pressed. Set as many as you like. They remain in the pressed state (and may autorepeat) until reset.
Nkro.reset_key(); //release a key that was pressed before
Nkro.reset_keys(); //release all pressed keys
Nkro.send_nkro_now(); //Sends the keyboard state to your computer. The computer don't see any keyboard state changes until you do this. You get simultaneous keypresses by setting several keys and then send them all in one go. Key releases must also be sent to make the computer notice and stop autorepeats.