Teensy 2.0 with NKRO Keyboard

Status
Not open for further replies.

joshuass

Member
Hey guys,

I've been working on a converter to convert a SNES pad to keyboard presses (better latency in some emulators).

Its been working pretty well so far with the 6-key limitation with the current Teensy 2.0 library. However, I'd like to extend the converter to handle 2 pads, which requires more keys.

I've calculated that each pad would need 20 keys (10 each, assuming Left and Right or Down and Up cannot be pressed simulaneously).

I went through the Teensy extensions to the Arduino IDE and started learning about the wonderful world that is USB and was wondering how much work would it be to add an additional keyboard device to the Teensy? I haven't worked much in C but am willing to learn. I've done comparisons between some other keyboard firmwares and the code for the Teensy and have a general idea of what is required.

Additionally, I have a feeling it would require modification to the Keyboard API since you are no longer limited to just 6 keys. My guess is that you would need some something like
Code:
Keyboard.begin()
Keyboard.press()
Keyboard.end()
similar to the Arduino keyboard library. Or, the ability to send an array of key presses.

Any thoughts on this? Am I barking up the wrong tree?

Thanks
 
The easiest change would be increasing from 6 keys to, well, many more. Going from an 8 byte packet to 32 bytes would give 30 keys.
 
Thanks, Paul. I was looking over the code again and since I do not need to worry about the Teensy being a boot device that would be the easiest option.

My next question is where is the report size specified?
 
Within usb.c theres the keyboard_hid_report_desc[] array for the keyboard report descriptor. I can see that the report count is 6 at 1 byte (6 bytes total).

I should be able to modify this to a report count of 30 at the same report size of 1 byte (30 + 2 = 32 bytes) correct?

Then, it would be a matter of sending more keys...
 
Yes. This ought to do it in the report descriptor.

Code:
        0x95, 0x1E,             //  Report Count (30),
        0x75, 0x08,             //  Report Size (8),
        0x15, 0x00,             //  Logical Minimum (0),
        0x25, 0x7F,             //  Logical Maximum(104),

There's other stuff to modify too...

In usb_private.h, change KEYBOARD_SIZE to 32.

Code:
#define KEYBOARD_SIZE           32

Since this no longer complies with the boot protocol, edit the 2 boot protocol numbers in usb.c in the keyboard interface to zero.

Code:
        0x03,                                   // bInterfaceClass (0x03 = HID)
        0x00,                                   // bInterfaceSubClass (0x01 = Boot)
        0x00,                                   // bInterfaceProtocol (0x01 = Keyboard)

Change the size of keyboard_report_data to 32 bytes:

Code:
// byte1: media keys (TODO: document these)
// bytes2-7: which keys are currently pressed, up to 6 keys may be down at once
uint8_t keyboard_report_data[8] USBSTATE;

In usb_init(), add code to clear the new 24 bytes.

There are 2 places in usb.c that transmit the keyboard report. You'll need to edit both of them to send all 32 bytes.

Code:
                                        for (i=0; i < 32; i++) {
                                                UEDATX = keyboard_report_data[i];
                                        }
                                        UEINTX = 0x3A;

Then you're ready to edit the code in usb_api.cpp, which actually does the work of sending your keys.

The 6 keys are used in usb_keyboard_class::write_key and usb_keyboard_class::send_now. Just add another 24 lines for the new bytes, or write it to use a loop if you like. Then add more usb_keyboard_class::set_key* functions for the 24 new bytes. Or you could just write directly into the array from your program.


I believe that's everything you'll need to edit. I might have missed something? If you try this, please post here to let us know how it goes? If you get it working, I hope you'll post the edited code in case anyone else wants to use this.
 
Last edited:
Awesome man, thanks for the help.

If I can get it working right, I think you should be able to integrate it into your existing Teensy extensions by adding another keyboard endpoint that supports more keys. That way you can keep your boot-compatible keyboard descriptor, and still allow for additional key presses beyond six.

I'll update this post if I get it going!
 
Eventually I'm going to try using a bitmap for all 104 keys. That's only 13 bytes and would allow any combination. But it requires significant reprogramming....
 
Awesome News!

So I spent the other night trying to work out an extended report config for giving the keyboard more simultaneous presses. I couldn't get it to work so I attempted to put together a bitmap report instead.

IT WORKED!

I basically reworked all the descriptors for the keyboard to give me a bitmap of 104 keys (13 bytes). I keep the report size to 16B and so in short:

byte 0: Modifier byte
byte 1 - 13: bitmap of keys
byte 14 - 15: padding

Turns out the tmk keyboard firmware library had code to bit shift all the usage ids for keys 0 through 103, which I cribbed from to rebuild the usb_api.cpp file.

Testing with 1 controller works great, and I plan on readding the rest of the api i removed (the joystick and serial objects are non-existent at the moment). I removed mouse support since this an arcade oriented board.

I'd love to share it with anyone who wanted to check it out. It definitely needs work (joysticks are missing, and I removed some preprocessor checks for avr chips that are not the same type as the Teensy 2.0).

It might even be a possible path forward for the usb api for the rest of the boards.
 
Excellent. Which operating systems did you use this keyboard with?

I'd be curious to see the report descriptor, if you'll post it.
 
Hi again joshuass,

Great job! So as far as I understand, the current code implements more than 6 keystrokes in HID Keyboard mode, right? So, what do you mean when you say you are planning to add again the joystick and mouse stuff? Is it that the HID joystick is not independent from the keyboard one?
Looking at the github it seems like you also want to implement 2 simultaneous HID joysticks, has there been any progress on that?
 
On the testing front - I've also used the report descriptor from the tmk keyboard firmware, and (about a year ago) tested variations of it against Win7 64 bit and linux (mint 13) 32 bit (and I think WinXP 32 bit, but not 100% sure on that one).

The linux system recognised and used a bitmap keyboard report in pretty much any configuration - odd things like 20 byte reports, reports without the modifier byte at the front, etc seemed to work fine.

Windows was not as well behaved. It would not "listen to" anything in a report if the first byte was not set aside as a modifier byte. Likewise, it would not listen to a report if the number of bytes was unusual - i.e. 16 bytes(1+15) and 32 bytes(1+31) works, but 20 bytes(1+19) did not (I wanted access to some of the odder keycodes like F13-F24, so 15 bytes of bitmap was going to be too small). I never tested 24 bytes, so I'm not sure if it needs multiples of 8 or if it was doubling each time. Nor would Windows listen if the bitmap didn't start from 0 - I tried shifting that to start from 4 (since that was the lowest actual keycode) and it refused to read the reports from the keyboard again.

I was still learning about it at the time so it's possible that I screwed up some of the testing...but the conclusion I came to was to stick to 16 or 32 byte reports with first byte as modifiers and remaining bytes a bitmap from 0-(numRemainingBytes*8 - 1) in order to keep it working across multiple systems.
 
Dawnmist,

Its good that I left my report size to 16bytes for compatibility sake. And luckily, I only needed like 20 keys simultaneously so it ended up working out ok (Also didn't need a bootable keyboard either). I read your posts on the subject of Windows goofiness and it looked like I was able to stay away from the bugs it has regarding keyboards.

zeroneo,

I've actually be re-adding the joystick stuff to the file. I'm kind of learning as I go. Now because the SNES pads do not have any analog components, my implementation will be a digital only directional pad. Not sure if you need the analog stuff, but it shouldn't be too hard to implement. I'll hopefully have something up by tonight or so.
 
I managed to add the Joystick support back in. Its not tested but my repo has been updated with an example INO file and updated api/c code with the additional descriptors and endpoints.

As I am still at work, I'll try and test this over the weekend. I am fairly certain the gamepad descriptors should work, though the D-Pad directionality may be reversed or completely fubar.
 
I managed to add the Joystick support back in. Its not tested but my repo has been updated with an example INO file and updated api/c code with the additional descriptors and endpoints.

As I am still at work, I'll try and test this over the weekend. I am fairly certain the gamepad descriptors should work, though the D-Pad directionality may be reversed or completely fubar.

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.
 
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.
 
Sorry, I missed seeing the thread's update/query in November last year. Hafting has found the last published version of the patch I did - I think it was against Teensyduino 1.18 or thereabouts, so it would likely have needed a few updates to pull it forward to newer teensyduino versions. At the time I did have it working fully, and I used it in a home-built gaming keypad up until about 18 months ago when health issues meant I couldn't game anymore. It's only had sporadic use since then, so I hadn't felt a need to update the code any further.

For the report size: A report size of 16 (15 + modifier byte) is enough to get the normal keys on a keyboard inside the report. How the report works is that each keycode is assigned a particular bit in a list of bytes - so keycode number "4" is the 4th bit in the list. For the gaming keypad I wanted the ability to report additional keys that are rarely used now - for example the old F13-F24 IBM keyboard keys - so that I could use them in gaming keymaps. So for myself I'd set the report size to 32 (31+modifier) bytes. What I ended up finding was that most programs didn't listen to those keys anymore so that it wasn't all that useful. So if you want to reduce communication size, you can change the "#define NKRO_SIZE 32" to "#define NKRO_SIZE 16" in teensy3/usb_desc.h

Please feel free to reuse/share/extend/etc. That's why I published my original Teensy 2 and then later Teensy 3 patches - partly so that anyone else wanting to do the same could do so, and partly so that if I vanished the information still existed for other people to be able to pick up/extend/continue with. :)
 
Thank you for implementing NKRO on teensy3! It is so much easier to work on a patch like this, than to make a usb device from scratch.
It turns out I got some of the usb endpoints numbers wrong in the previous patch, this caused disruption of "media keys". So here is an improved patch, with these improvements:
* Correct endpoint numbers, both nkro keyboard and media keys works at the same time
* All usb types with keyboard gets nkro added, not only some of them
* Various smaller bugfixes & cleanups, makes use of usb_undef.h for example
* To get nkro on usb type "all devices" I had to disable another device, so I disabled touchscreen. I don't know what the limit is - perhaps 16 endpoints is a problem? Or timing constraints with many devices?
Of course the patch is posted in the hope that it might be useful, so feel free to use or build on it.
The new patch:
diff -uN teensy3.org/usb_desc.c teensy3/usb_desc.c
--- teensy3.org/usb_desc.c 2017-01-16 11:35:22.000000000 +0100
+++ teensy3/usb_desc.c 2017-02-13 10:25:36.737435046 +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-16 11:35:22.000000000 +0100
+++ teensy3/usb_desc.h 2017-02-14 11:01:09.445383104 +0100
@@ -146,9 +146,9 @@
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d'}
#define PRODUCT_NAME_LEN 8
#define EP0_SIZE 64
- #define NUM_ENDPOINTS 4
+ #define NUM_ENDPOINTS 5
#define NUM_USB_BUFFERS 14
- #define NUM_INTERFACE 3
+ #define NUM_INTERFACE 4
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
@@ -164,6 +164,12 @@
#define KEYMEDIA_ENDPOINT 4
#define KEYMEDIA_SIZE 8
#define KEYMEDIA_INTERVAL 4
+ #define NKRO_INTERFACE 6 // N-key rollover kbd
+ #define NKRO_ENDPOINT 5
+ #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
@@ -179,9 +185,9 @@
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
#define PRODUCT_NAME_LEN 23
#define EP0_SIZE 64
- #define NUM_ENDPOINTS 6
+ #define NUM_ENDPOINTS 7
#define NUM_USB_BUFFERS 24
- #define NUM_INTERFACE 5
+ #define NUM_INTERFACE 6
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
@@ -205,12 +211,19 @@
#define JOYSTICK_ENDPOINT 4
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 2
+ #define NKRO_INTERFACE 5 // N-key rollover kbd
+ #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_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY
+ #define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY

#elif defined(USB_SERIAL_HID)
#define VENDOR_ID 0x16C0
@@ -223,9 +236,9 @@
#define PRODUCT_NAME {'S','e','r','i','a','l','/','K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}
#define PRODUCT_NAME_LEN 30
#define EP0_SIZE 64
- #define NUM_ENDPOINTS 7
+ #define NUM_ENDPOINTS 8
#define NUM_USB_BUFFERS 30
- #define NUM_INTERFACE 6
+ #define NUM_INTERFACE 7
#define CDC_IAD_DESCRIPTOR 1
#define CDC_STATUS_INTERFACE 0
#define CDC_DATA_INTERFACE 1 // Serial
@@ -251,6 +264,12 @@
#define JOYSTICK_ENDPOINT 6
#define JOYSTICK_SIZE 16
#define JOYSTICK_INTERVAL 1
+ #define NKRO_INTERFACE 6 // N-key rollover kbd
+ #define NKRO_ENDPOINT 8
+ #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
@@ -258,6 +277,7 @@
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY
+ #define ENDPOINT8_CONFIG ENDPOINT_TRANSIMIT_ONLY

#elif defined(USB_TOUCHSCREEN)
#define VENDOR_ID 0x16C0
@@ -267,9 +287,9 @@
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','T','o','u','c','h','s','c','r','e','e','n'}
#define PRODUCT_NAME_LEN 20
#define EP0_SIZE 64
- #define NUM_ENDPOINTS 5
+ #define NUM_ENDPOINTS 6
#define NUM_USB_BUFFERS 15
- #define NUM_INTERFACE 4
+ #define NUM_INTERFACE 5
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
@@ -289,11 +309,18 @@
#define MULTITOUCH_ENDPOINT 5
#define MULTITOUCH_SIZE 9
#define MULTITOUCH_FINGERS 10
+ #define NKRO_INTERFACE 4 // N-key rollover kbd
+ #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
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
+ #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY

#elif defined(USB_HID_TOUCHSCREEN)
#define VENDOR_ID 0x16C0
@@ -303,9 +330,9 @@
#define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','T','o','u','c','h','s','c','r','e','e','n'}
#define PRODUCT_NAME_LEN 26
#define EP0_SIZE 64
- #define NUM_ENDPOINTS 6
+ #define NUM_ENDPOINTS 7
#define NUM_USB_BUFFERS 20
- #define NUM_INTERFACE 5
+ #define NUM_INTERFACE 6
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
@@ -329,12 +356,19 @@
#define MULTITOUCH_ENDPOINT 5
#define MULTITOUCH_SIZE 9
#define MULTITOUCH_FINGERS 10
+ #define NKRO_INTERFACE 5 // N-key rollover kbd
+ #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_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY
+ #define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY

#elif defined(USB_MIDI)
#define VENDOR_ID 0x16C0
@@ -670,10 +704,18 @@
#define AUDIO_RX_ENDPOINT 13
#define AUDIO_RX_SIZE 180
#define AUDIO_SYNC_ENDPOINT 14
+/*
#define MULTITOUCH_INTERFACE 12 // Touchscreen
#define MULTITOUCH_ENDPOINT 15
#define MULTITOUCH_SIZE 9
#define MULTITOUCH_FINGERS 10
+*/
+ #define NKRO_INTERFACE 12 // N-key rollover kbd
+ #define NKRO_ENDPOINT 15
+ #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_TRANSMIT_AND_RECEIVE
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_AND_RECEIVE
@@ -689,6 +731,7 @@
#define ENDPOINT13_CONFIG (ENDPOINT_RECEIVE_ISOCHRONOUS|ENDPOINT_TRANSMIT_ISOCHRONOUS)
#define ENDPOINT14_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT15_CONFIG ENDPOINT_TRANSIMIT_ONLY
+// #define ENDPOINT16_CONFIG ENDPOINT_TRANSIMIT_ONLY

#endif

diff -uN teensy3.org/usb_dev.h teensy3/usb_dev.h
--- teensy3.org/usb_dev.h 2017-01-16 11:35:22.000000000 +0100
+++ teensy3/usb_dev.h 2017-02-13 10:25:36.737435046 +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-16 11:35:22.000000000 +0100
+++ teensy3/usb_inst.cpp 2017-02-13 10:25:36.737435046 +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-13 10:25:36.737435046 +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-13 17:46:23.968578415 +0100
@@ -0,0 +1,43 @@
+#ifndef USBnkro_h_
+#define USBnkro_h_
+
+#include "usb_desc.h"
+#include "keylayouts.h"
+
+#if defined (NKRO_INTERFACE)
+
+#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 // NKRO_INTERFACE
+#endif // USBnkro_h_
diff -uN teensy3.org/usb_undef.h teensy3/usb_undef.h
--- teensy3.org/usb_undef.h 2017-01-16 11:35:22.000000000 +0100
+++ teensy3/usb_undef.h 2017-02-13 17:36:31.229850719 +0100
@@ -209,6 +209,21 @@
#ifdef MTP_EVENT_INTERVAL
#undef MTP_EVENT_INTERVAL
#endif
+#ifdef NKRO_INTERFACE
+#undef NKRO_INTERFACE
+#endif
+#ifdef NKRO_ENDPOINT
+#undef NKRO_ENDPOINT
+#endif
+#ifdef NKRO_SIZE
+#undef NKRO_SIZE
+#endif
+#ifdef NKRO_REPORT_KEYS
+#undef NKRO_REPORT_KEYS
+#endif
+#ifdef NKRO_INTERVAL
+#undef NKRO_INTERVAL
+#endif
#ifdef ENDPOINT1_CONFIG
#undef ENDPOINT1_CONFIG
#endif
@@ -254,4 +269,7 @@
#ifdef ENDPOINT15_CONFIG
#undef ENDPOINT15_CONFIG
#endif
+#ifdef ENDPOINT16_CONFIG
+#undef ENDPOINT16_CONFIG
+#endif

Vanlige undermapper: teensy3.org/util og teensy3/util
diff -uN teensy3.org/WProgram.h teensy3/WProgram.h
--- teensy3.org/WProgram.h 2017-01-16 11:35:22.000000000 +0100
+++ teensy3/WProgram.h 2017-02-13 10:25:36.737435046 +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"
 
Thank you for the update. While I am new to tinkering with Teensy and coding in general, I am not familiar with the best way to use the diffs that you listed. Do I manually update each line in the diffs? Or is there a program where I can copy/paste your diffs and the files get automatically updated? Of course this is not too much to manually do, but I like to use the proper tools is there is such a thing.
 
Status
Not open for further replies.
Back
Top