Compare commits

...

53 commits
2.4 ... master

Author SHA1 Message Date
3fcbe5ccda
Update Readme.md 2018-05-22 22:59:03 +02:00
6e4ed069be
Update Readme.md 2018-05-22 22:58:27 +02:00
aab401084b
Add files via upload 2018-05-22 22:58:09 +02:00
54d29302ae
personalised the readme 2018-05-22 22:57:17 +02:00
Nico
d4938ddcff
Merge pull request #127 from MarianoAmado/master
Added screen brightness control keys
2018-01-04 18:31:23 +01:00
Mariano Amado
4249490ab3 added screen brightness keys 2018-01-04 12:48:19 -03:00
Nico
3c5000c4b6 Merge pull request #117 from wind-rider/surface_dial
Add Surface Dial support
2017-08-31 20:21:36 +02:00
wind-rider
ee0bbd9657 Add more comments 2017-08-19 23:02:55 +02:00
wind-rider
8cdc8cca26 Add connection diagram and comments 2017-08-19 22:58:37 +02:00
wind-rider
813eb71440 Added simple example 2017-08-19 17:03:44 +02:00
wind-rider
2169d34f2c Add Surface Dial support 2017-08-19 16:55:52 +02:00
Nico
af9fff10e9 Merge pull request #101 from faxm0dem/patch-1
Fix wrong advertisement
2017-04-02 19:36:09 +02:00
Fabien Wernli
ede4a3e9cf Fix wrong advertisement
As stated elsewhere HUDloader1 is not supported anymore
2017-04-02 14:26:14 +02:00
Nico
a5e20e94d2 Merge pull request #79 from NicoHood/dev
Release 2.4.4
2017-01-27 12:26:34 +01:00
NicoHood
51611e6548
Release 2.4.4 2017-01-27 12:24:29 +01:00
NicoHood
583718f453
Fix flexible array errors 2017-01-27 12:22:02 +01:00
NicoHood
12557b5489 Added wiki submodule 2016-05-05 23:08:11 +02:00
NicoHood
7c269d9749 Added releaseAll() for abs Mouse 2016-03-05 18:02:50 +01:00
NicoHood
b33ff31253 Bump to version 2.4.4 2016-03-05 18:00:05 +01:00
NicoHood
d3147adbfd Added releaseAll() for Mouse API 2016-03-05 17:58:16 +01:00
NicoHood
3a71aaeb72 Release 2.4.3 2016-03-02 10:08:26 +01:00
Nico
f50383922e Merge pull request #76 from Scyntrus/patch-1
Use OR assignment for NKRO modifier keys
2016-02-27 01:12:01 +01:00
Scyntrus
44fbac4089 Use OR assignment for NKRO modifier keys
The DefaultKeyboardAPI implementation uses OR assignment instead of basic assignment.
2016-02-26 16:03:35 -08:00
Nico
516c6f3efd Merge pull request #69 from NicoHood/dev
Release 2.4.2
2016-01-04 18:42:12 +01:00
NicoHood
93a27986f8 Release 2.4.2 2016-01-04 18:41:06 +01:00
NicoHood
dced097808 Lowered Arduiono IDE dependency to 1.6.7 again
RawHID is fixed with 1.6.8, but its not essential for the whole library.
However 1.6.8 is recommended.
2016-01-04 18:26:31 +01:00
NicoHood
f96e09c75b Fixed Keyboard modifier add() issue #68 2016-01-04 18:22:09 +01:00
NicoHood
8e5d8571e2 Bump Arduino IDE requirement number 2016-01-04 18:14:14 +01:00
NicoHood
14f52f1879 Partly revert commit 8bb3b2339f
Arduino integrated the function now as normal fix
2016-01-04 18:13:30 +01:00
NicoHood
bb0960c9f3 Bump version number to 2.4.2 2015-12-19 02:02:11 +01:00
NicoHood
8bb3b2339f RawHID >64 byte fix 2015-12-19 02:00:42 +01:00
Nico
df98686d03 Merge pull request #67 from NicoHood/dev
Release 2.4.1
2015-12-19 01:46:47 +01:00
NicoHood
9a113eb8d2 Added udev rule example 2015-12-19 01:44:47 +01:00
NicoHood
4423cf6a47 Release 2.4.1 2015-12-19 01:43:28 +01:00
NicoHood
7754123b6e Added 1.6.7 as requirement 2015-12-05 08:00:04 +01:00
NicoHood
5c245d7a8b Changed version number to 2.4.1 2015-11-30 18:05:56 +01:00
NicoHood
e8f3178509 Merge branch 'dev' of https://github.com/NicoHood/HID into dev 2015-11-30 18:02:19 +01:00
NicoHood
e632912905 Fix NKRO example issue #64 2015-11-30 17:59:50 +01:00
NicoHood
a95361043b Removed unnecessary Arduino include 2015-11-30 17:55:27 +01:00
Nico
214802a3b6 Delete .development 2015-11-10 07:25:40 +01:00
NicoHood
86ed8a146b Moved some examples into separate folder 2015-11-08 20:09:45 +01:00
NicoHood
4c90e0b90d Added RawHID Hyperion Paintpack example 2015-11-08 20:06:46 +01:00
NicoHood
fcb32a5cf0 minor keyboard feature request fixes 2015-11-08 20:06:17 +01:00
NicoHood
c197491272 Updated RawHID with new, more intuitive API 2015-11-08 20:05:53 +01:00
NicoHood
626be84137 Fixed RawHID linux send function. 2015-11-08 19:59:23 +01:00
NicoHood
eed1098a21 Added featureReport data to constructor 2015-11-08 00:13:42 +01:00
NicoHood
0487754e10 Added Feature Report example + disabled by default 2015-11-07 23:46:58 +01:00
NicoHood
6a93f83c46 Updated Keyboard keywords.txt 2015-11-07 23:35:23 +01:00
NicoHood
a8c292a7bd Added Feature Report function to BootKeyboard
This may be added to other HID Devices as well, but Keyboard makes the most sense.
2015-11-07 23:32:02 +01:00
NicoHood
febc714df5 Improved library.properties 2015-11-07 11:11:28 +01:00
NicoHood
ef6e8e52a7 Merge commit '186c2c432c2ba896e921f1ad4ff436a6466560b3' into dev 2015-11-07 11:09:04 +01:00
NicoHood
186c2c432c Added sequence ID (aka num) to RawHID 2015-11-07 10:54:50 +01:00
NicoHood
b8bdc23208 bumped version number to 2.5 2015-11-06 23:09:56 +01:00
47 changed files with 926 additions and 529 deletions

View file

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "HID.wiki"]
path = HID.wiki
url = https://github.com/NicoHood/HID.wiki.git

1
HID.wiki Submodule

@ -0,0 +1 @@
Subproject commit a1a0b086985dec037d7e7d86c6b2d5816207f202

222
Readme.md
View file

@ -1,223 +1,29 @@
Arduino HID Project 2.4 **Arduino Silly Keyboard** forked from Arduino HID Project 2.4.4
======================= =========================
![Header Picture](header.jpg) ![Header Picture](virtualkeyb.jpg)
This project went through a lot of phases and has now reached a new Arduino ~~USB-Core~~ Library This is targetted at the Leonardo or compatible boards (32U4) and will be built around one of these:
with a lot of new functions like extended HID. It also supports HoodLoader1+2. https://www.aliexpress.com/item/Beetle-Virtual-Keyboard-BadUSB-Pro-Micro-ATMEGA32U4-Module-Mini-Development-Expansion-Board-For-Arduino-Leonardo-R3/32847715254.html?spm=2114.search0104.3.1.7d542341ScymPz&ws_ab_test=searchweb0_0,searchweb201602_1_10152_10151_10065_10344_10068_10342_10343_10340_5722611_10341_10696_5722911_5722811_10084_5722711_10083_10618_10307_10134_5711211_10059_308_100031_10103_10624_10623_10622_10621_10620_5711311_5722511_10814_10815,searchweb201603_25,ppcSwitch_5&algo_expid=c50f562a-35a5-4cbe-9391-2b1586b8823e-0&algo_pvid=c50f562a-35a5-4cbe-9391-2b1586b8823e&priceBeautifyAB=0
The idea is to enable enhanced USB functions to almost all 'standard' Arduino boards.
**Supported Arduinos (IDE 1.6.6 or higher!):** It's going to act like a keyboard (HID) and will write random words at random times with the purpose of being an entertaining toy for the office to play (innocent) jokes on colleagues.
* Uno (with [HoodLoader2](https://github.com/NicoHood/HoodLoader2))
* Mega (with [HoodLoader2](https://github.com/NicoHood/HoodLoader2))
* Leonardo
* (Pro)Micro
* Any other 8u2/16u2/at90usb8/162/32u2/32u4 compatible board
* No SAM/ARM support (Due, Zero etc)
**Supported HID devices:** If I get clever, then it will insert words at just the right time when someone is typing - for example when the space bar is pressed and it's the perfect perfect time to insert a new new word word. Replay replay retyping things that were already typed would also be great. But I have some learning to do first!
* Keyboard with Leds out (8 modifiers + 6 keys pressed at the same time, + 1 limited linux consumer key)
* ~~Teensy Keyboard with different keyboard layouts (german, french and many more)~~ soon
* NKRO Keyboard with Leds out (press up to 113 keys at the same time)
* Mouse (5 buttons, move, wheel)
* BootKeyboard/BootMouse BIOS protocol support
* Absolute Mouse
* Consumer/Media Keys (4 keys for music player, web browser and more)
* System Key (for PC standby/shutdown)
* Gamepad (32 buttons, 4 16bit axis, 2 8bit axis, 2 D-Pads)
* RawHID
* Each device is available as single or multi report device (except RawHID)
See the [wiki](https://github.com/NicoHood/HID/wiki/Features) for more information about features etc. The project will advance more when the hardware arrives (sometime in the next 5-6 weeks).
Wiki
====
All documentation moved to the [wiki page](https://github.com/NicoHood/HID/wiki).
An offline snapshot is available in [releases](https://github.com/NicoHood/HID/releases).
Contact Forked at
======= 2.4.4 Release (27.01.2017)
* Added releaseAll() to Mouse API
You can contact me on my wordpress blog in the contact section. * Fix flexible array errors
www.nicohood.de
Version History
===============
```
2.4 Release (06.11.2015)
* Added Arduino IDE 1.6.6 compatibility with Pluggable HID
* Improved Pluggable HID (see Arduyuino changelog for my improvements)
* Changed USB-Core into a simple library, only made possible with Pluggable HID
* Removed HID presets in boards menu (like mouse + keyboard + consumer + system)
* Added NKRO Keyboard
* Added Led report for Keyboard
* Added 1 Linux consumer key for keyboard
* Added BootKeyboard/Mouse support (BIOS compatibility)
* Added RawHID
* Added a few key definitions
* Renew whole Keyboard API and its definitions via enum
* Uses .alinkage custom IDE option
* Improved and updated examples
* A lot of other minor and major fixes I missed to mention.
2.3 Release (never released)
* Updated Libraries
* Updated Arduino Core
* Added Minor Consumer definitions
* Fixed platforms.txt
* SERIAL_RX_BUFFER_SIZE reverted to 16 (TODO add -D to build option)
2.2 Release (12.04.2015)
* added experimental, not finished nor documented HID-Bridge between 16u2 and 328/2560
* increased HW Serial1 RX buffer size from 16 to 32 (TX still 16)
* added colour highlighting (through HID-Bridge library)
* removed fixed size in report buffers
* used HID_KeyboardReport_Data_t now in Keyboard API
* Arduino as ISP fix for 328
* Upload verification on USB hubs fix for HL2.0.4
* No USB workaround for Leonardo integrated into variants
* Changed USB Wakeup in System API
* Consumer Key fix (issue #3)
* Gamepad fix (issue #14)
* Added Keycode example
* Mouse press + release fix
2.1 Release (28.01.2015)
* Reworked the whole USB-Core from scratch
* Uses less flash if HID or Serial is not used
* Extended and compacter(flash) HID Report Descriptors
* Fixed USB Device Descriptor
* Added u2 compatibility with smaller USB_EP_SIZE (16u2 etc)
* Added Serial Event for LineEncoding and LineState
* Added Serial Function to get dtr state, line encoding etc
* Added Keyboard Led Out report to get Led states (for numlock etc)
* Made CDC-Core independent from USB-Core
* Made HID-Core independent from USB-Core
* Made HID-API independent from HID-Core
* Removed not needed virtual functions in Keyboard
* Made HID Reports and its IDs replaceable via pins_Arduino.h
* Added Absolute Mouse
* Removed uint8_t USBPutChar(uint8_t c); in HID.cpp
* Made void Recv(volatile u8* data, u8 count) in USBCore.cpp static inline
* HID-APIs sends a clean report on begin() and end() now.
* Removed virtual functions in Keyboard API
* Added Keycode functions in Keyboard API
* Inlined a lot of the HID API functions to save flash
* Added Gamepad
* Added RawHID API (but RawHID itself isnt working still)
* Added USB Wakeup support
* Separated USB-Core in its own folder
* Added HID Tables
* USB-Serial now fully reprogrammable
* Easy USB-Core selection via Tools->USB-Core
* Added Arduino as ISP fix for 32u4 and 16u2
* Moved documentation to the wiki
* Added AVR libraries to the core with the better SoftSerial
2.0 Release (29.11.2014)
* Added HoodLoader2
* Separated HoodLoader1&2 more
* Added u2 series for USB-Core
* Extended USB core and fixed minor things for the u2 series
* Added Led Out report.
* Added CDC Line state
* Reworked the whole library structure again
1.8 Beta Release (26.08.2014)
* Changes in the Hoodloader1:
* **Huge improvements**, see Hoodloader1 repository
* Reworked the whole library, easy installation now
* HID fixes for Media Keys/Ubuntu
* Removed Joystick, added 4 Gamepads
1.7.3 Beta Release (10.08.2014)
* Changes in the Hoodloader1:
* Fixed HID flush bug (1.6 - 1.7.2)
1.7.2 Beta Release (10.08.2014)
* Changes in the Hoodloader1:
* Added Lite version for 8u2
* Added Versions that show up as Uno/Mega (not recommended)
* Makefile and structure changes
1.7.1 Beta Release (10.08.2014)
* Changes in the Hoodloader1:
* Fixed HID deactivation bug
1.7 Beta Release (10.08.2014)
* Changes in the Hoodloader1:
* Works as ISP now. See Hoodloader1 Repository for more information.
* Exceeded 8kb limit. For flashing a 8u2 use v1.6 please!
* Changed Readme text
1.6 Beta Release (09.08.2014)
* Bugfixes in the Hoodloader1:
* Changed HID management (not blocking that much, faster)
* added RawHID in/out (HID to Serial)
* Added RawHID Class and example
1.5 Beta Release (21.07.2014)
* Moved Hoodloader1 source to a separate Github page
* Bugfixes in the Hoodloader:
* Firmware is still available here
* Overall a lot of ram improvements, now with a big global union of ram
* Removed USBtoUSART buffer (not needed, saved 128/500 bytes)
* Removed Lite version because of better ram usage not needed
* Separated different modes better to not cause any errors in default mode
* Improved the deactivate option
* Integrated NHP directly
* Replaced LightweightRingbuffer with native Lufa Ringbuffer
* Improved writing to CDC Host
* Fixed a bug in checkNHPProtocol: & needs to be a ==
* General structure changes
* Improved stability
* Fixed Arduino as ISP bug
1.4.1 Beta Release (10.07.2014)
* #define Bugfix in USBAPI.h
1.4 Beta Release (10.07.2014)
* Bugfixes in the Hoodloader1:
* Added Lite Version with less ram usage
* Changed PIDs, edited driver file
* merged v1.0.x and v1.5.x together (both are compatible!)
* added IDE v1.5.7 support
* added Tutorials
1.3 Beta Release (01.07.2014)
* Bugfixes in the Hoodloader1:
* Improved ram usage
* **Important NHP fix inside the HID Class for Uno/Mega**
1.2 Beta Release (22.06.2014)
* Added 1.0.x/1.5.x support
* Bugfixes in the Hoodloader1:
* Sometimes HID Devices weren't updating
when using more than 1 Device (set forcewrite to true)
* Fast updates crashed the bootloader
(too much ram usage, set CDC buffer from 128b to 100b each)
* Minor file structure changes
1.1 Beta Release (05.06.2014)
* Added Leonardo/Micro support
* Included NicoHoodProtocol
* Minor fixes
1.0 Beta Release (03.06.2014)
```
Licence and Copyright Licence and Copyright
===================== =====================
If you use this library for any cool project let me know! Here's the original License conditions from NicoHood (AWESOME WORK!).
``` ```
Copyright (c) 2014-2015 NicoHood Copyright (c) 2014-2016 NicoHood
See the readme for credit to other people. See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

View file

@ -35,17 +35,17 @@ void loop() {
// Do not press to many at once or some OS will have problems. // Do not press to many at once or some OS will have problems.
// Note that the resulting pressed order might differ, // Note that the resulting pressed order might differ,
// because all keys are pressed at the same time. // because all keys are pressed at the same time.
NKROKeyboard.addKeyToReport('0'); NKROKeyboard.add('0');
NKROKeyboard.addKeyToReport('1'); NKROKeyboard.add('1');
NKROKeyboard.addKeyToReport('2'); NKROKeyboard.add('2');
NKROKeyboard.addKeyToReport('3'); NKROKeyboard.add('3');
NKROKeyboard.addKeyToReport('4'); NKROKeyboard.add('4');
NKROKeyboard.addKeyToReport('5'); NKROKeyboard.add('5');
NKROKeyboard.addKeyToReport('6'); NKROKeyboard.add('6');
NKROKeyboard.addKeyToReport('7'); NKROKeyboard.add('7');
NKROKeyboard.addKeyToReport('8'); NKROKeyboard.add('8');
NKROKeyboard.addKeyToReport('9'); NKROKeyboard.add('9');
NKROKeyboard.send_now(); NKROKeyboard.send();
// Release all keys and hit enter // Release all keys and hit enter
NKROKeyboard.releaseAll(); NKROKeyboard.releaseAll();

View file

@ -0,0 +1,84 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
KeyboardFeatureReport example
Shows how to use BootKeyboard with a modified Hyperion Lightpack device.
This example also works with RawHID.
Might only work under linux.
https://github.com/tvdzwan/hyperion/pull/407
https://github.com/tvdzwan/hyperion/wiki
https://github.com/FastLED/FastLED
See HID Project documentation for more information.
https://github.com/NicoHood/HID/wiki/RawHID-API
https://github.com/NicoHood/HID/wiki/Keyboard-API#boot-keyboard
*/
#include "HID-Project.h"
const int pinLed = LED_BUILTIN;
// FastLED
#include "FastLED.h"
#define LED_PINS MOSI, SCK // DATA_PIN, or DATA_PIN, CLOCK_PIN
#define COLOR_ORDER RGB
#define CHIPSET WS2801 // WS2811, LPD8806, etc
#define NUM_LEDS 25
#define BRIGHTNESS 255 // Reduce power consumption
#define LED_DITHER 255 // Try 0 to disable flickering
#define CORRECTION TypicalLEDStrip
CRGB leds[NUM_LEDS]; // Define the array of leds
void setup() {
// FastLED setup
FastLED.addLeds<CHIPSET, LED_PINS, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(CORRECTION);
FastLED.setBrightness(BRIGHTNESS);
FastLED.setDither(LED_DITHER);
// Startup animation
fill_solid(leds, NUM_LEDS, CRGB::Red);
FastLED.show();
delay(500);
fill_solid(leds, NUM_LEDS, CRGB::Green);
FastLED.show();
delay(500);
fill_solid(leds, NUM_LEDS, CRGB::Blue);
FastLED.show();
delay(500);
FastLED.clear();
FastLED.show();
pinMode(pinLed, OUTPUT);
// Sends a clean report to the host. This is important on any Arduino type.
BootKeyboard.begin();
// Let the feature report data directly point at the led array
BootKeyboard.setFeatureReport(leds, sizeof(leds));
BootKeyboard.enableFeatureReport();
}
void loop() {
// Check if there is new feature request data from the keyboard
if (BootKeyboard.availableFeatureReport())
{
digitalWrite(pinLed, HIGH);
// Update leds, do not update in the loop, to avoid corrupted data.
// For example if you write (0, 0, 0) and the interrupt
// changes the data to (255, 255, 255) you might get (0, 255, 255).
// Using a duplicated led array in cli() context would also work.
FastLED.show();
// Release data to let the USB interrupt overwrite it again
BootKeyboard.enableFeatureReport();
digitalWrite(pinLed, LOW);
}
}

View file

@ -1,103 +0,0 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Advanced RawHID example
Shows how to send bytes via RawHID.
Press a button to send some example values.
Every received data is mirrored to the host.
The use of the RawHIDEvent() function is shown too.
This sketch only tries to show the possiblities
and is not perfect.You might want to use RawHID differently.
See HID Project documentation for more information.
https://github.com/NicoHood/HID/wiki/RawHID-API
*/
#include "HID-Project.h"
const int pinLed = LED_BUILTIN;
const int pinButton = 2;
uint8_t data[255];
volatile size_t len = 0;
void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT_PULLUP);
// No begin/end function required for RawHID
}
void loop() {
// Send data to the host
if (!digitalRead(pinButton)) {
digitalWrite(pinLed, HIGH);
// Create buffer with numbers and send it
uint8_t megabuff[100];
for (uint8_t i = 0; i < sizeof(megabuff); i++) {
megabuff[i] = i;
}
RawHID.write(megabuff, sizeof(megabuff));
// Simple debounce
delay(300);
digitalWrite(pinLed, LOW);
}
// This will miss longer RawHID data transmissions
// and return an error to the host if data was missed.
// Only use this for non changing/less important data.
// Or you can use this if the event aborted on a full buffer.
// Please note, that all data after this full buffer is missed anyways.
auto bytesAvailable = RawHID.available();
while (bytesAvailable--) {
if (len < sizeof(data)) {
data[len++] = RawHID.read();
}
}
// Process data from the host
if (len) {
digitalWrite(pinLed, HIGH);
// Disable interrupts while processing the data
uint8_t oldSREG = SREG;
cli();
// Mirror the incoming data from the host back
RawHID.write(data, len);
len = 0;
SREG = oldSREG;
// Simple debounce for led
delay(300);
digitalWrite(pinLed, LOW);
}
}
void RawHIDEvent(void) {
// This event is called via interrupt.
// Do not use print inside, or other long function calls!
// If you not use this event function,
// you might miss some data in the loop,
// if the host sends too fast or too much data at once.
auto bytesAvailable = RawHID.available();
while (bytesAvailable--) {
// Only add data to the buffer if its not full.
// If it is, no more event will occur
// and the data should be discarded
// or read (as shown) in the loop above.
if (len < sizeof(data)) {
data[len++] = RawHID.read();
}
}
}

View file

@ -0,0 +1,71 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Advanced RawHID example
Shows how to send bytes via RawHID.
Press a button to send some example values.
Every received data is mirrored to the host via Serial.
See HID Project documentation for more information.
https://github.com/NicoHood/HID/wiki/RawHID-API
*/
#include "HID-Project.h"
const int pinLed = LED_BUILTIN;
const int pinButton = 2;
// Buffer to hold RawHID data.
// If host tries to send more data than this,
// it will respond with an error.
// If the data is not read until the host sends the next data
// it will also respond with an error and the data will be lost.
uint8_t rawhidData[255];
void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT_PULLUP);
Serial.begin(115200);
// Set the RawHID OUT report array.
// Feature reports are also (parallel) possible, see the other example for this.
RawHID.begin(rawhidData, sizeof(rawhidData));
}
void loop() {
// Send data to the host
if (!digitalRead(pinButton)) {
digitalWrite(pinLed, HIGH);
// Create buffer with numbers and send it
uint8_t megabuff[100];
for (uint8_t i = 0; i < sizeof(megabuff); i++) {
megabuff[i] = i;
}
RawHID.write(megabuff, sizeof(megabuff));
// Simple debounce
delay(300);
digitalWrite(pinLed, LOW);
}
// Check if there is new data from the RawHID device
auto bytesAvailable = RawHID.available();
if (bytesAvailable)
{
digitalWrite(pinLed, HIGH);
// Mirror data via Serial
while (bytesAvailable--) {
Serial.println(RawHID.read());
}
digitalWrite(pinLed, LOW);
}
}

View file

@ -0,0 +1,92 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
RawHIDPaintpack example
Shows how to use RawHID with the Hyperion Lightpack device.
https://github.com/tvdzwan/hyperion/wiki
https://github.com/FastLED/FastLED
See HID Project documentation for more information.
https://github.com/NicoHood/HID/wiki/RawHID-API
https://github.com/NicoHood/HID/wiki/Keyboard-API#boot-keyboard
*/
#include "HID-Project.h"
const int pinLed = LED_BUILTIN;
// FastLED
#include "FastLED.h"
#define LED_PINS MOSI, SCK // DATA_PIN, or DATA_PIN, CLOCK_PIN
#define COLOR_ORDER RGB
#define CHIPSET WS2801 // WS2811, LPD8806, etc
#define NUM_LEDS 25
#define BRIGHTNESS 255 // Reduce power consumption
#define LED_DITHER 255 // Try 0 to disable flickering
#define CORRECTION TypicalLEDStrip
CRGB leds[NUM_LEDS]; // Define the array of leds
uint8_t rawhidData[sizeof(leds) + 2];
void setup() {
// FastLED setup
FastLED.addLeds<CHIPSET, LED_PINS, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(CORRECTION);
FastLED.setBrightness(BRIGHTNESS);
FastLED.setDither(LED_DITHER);
// Startup animation
fill_solid(leds, NUM_LEDS, CRGB::Red);
FastLED.show();
delay(500);
fill_solid(leds, NUM_LEDS, CRGB::Green);
FastLED.show();
delay(500);
fill_solid(leds, NUM_LEDS, CRGB::Blue);
FastLED.show();
delay(500);
FastLED.clear();
FastLED.show();
pinMode(pinLed, OUTPUT);
// Set the RawHID OUT report array.
// Feature reports are also (parallel) possible, see the other example for this.
RawHID.begin(rawhidData, sizeof(rawhidData));
}
void loop() {
// Check if there is new data from the RawHID device
auto bytesAvailable = RawHID.available();
if (bytesAvailable == sizeof(rawhidData))
{
digitalWrite(pinLed, HIGH);
// Check header for errors
if (RawHID.read() != 3) {
return;
}
if (RawHID.read() != 0) {
return;
}
// Write data to led array
uint8_t* ptr = (uint8_t*)leds;
for (int i = 0; i < sizeof(leds); i++) {
*ptr = RawHID.read();
ptr++;
}
// Update leds, do not update in the loop, to avoid corrupted data.
// For example if you write (0, 0, 0) and the interrupt
// changes the data to (255, 255, 255) you might get (0, 255, 255).
// Using a duplicated led array in cli() context would also work.
FastLED.show();
digitalWrite(pinLed, LOW);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

View file

@ -0,0 +1,85 @@
/*
Copyright (c) 2017 wind-rider
See the readme for credit to other people.
Surface dial example
Use an encoder and a button to create a Surface Dial-compatible device.
See the connection diagram how to wire it up.
Please note that:
- I tested it using an Arduino Pro Micro; TinkerCad didn't have that in its component library
- you obviously don't need a motor, but TinkerCad didn't have a separate encoder
The encoder processing code is coming from https://www.allwinedesigns.com/blog/pocketnc-jog-wheel
*/
#include "HID-Project.h"
// input pins for encoder channel A and channel B
int pinA = 2;
int pinB = 3;
// input pin for pushbutton
int pinButton = 4;
volatile bool previousButtonValue = false;
volatile int previous = 0;
volatile int counter = 0;
void setup() {
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
pinMode(pinButton, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinA), changed, CHANGE);
attachInterrupt(digitalPinToInterrupt(pinB), changed, CHANGE);
SurfaceDial.begin();
}
void changed() {
int A = digitalRead(pinA);
int B = digitalRead(pinB);
int current = (A << 1) | B;
int combined = (previous << 2) | current;
if(combined == 0b0010 ||
combined == 0b1011 ||
combined == 0b1101 ||
combined == 0b0100) {
counter++;
}
if(combined == 0b0001 ||
combined == 0b0111 ||
combined == 0b1110 ||
combined == 0b1000) {
counter--;
}
previous = current;
}
void loop(){
bool buttonValue = digitalRead(pinButton);
if(buttonValue != previousButtonValue){
if(buttonValue) {
SurfaceDial.press();
} else {
SurfaceDial.release();
}
previousButtonValue = buttonValue;
}
if(counter >= 4) {
SurfaceDial.rotate(10);
counter -= 4;
} else if(counter <= -4) {
SurfaceDial.rotate(-10);
counter += 4;
}
}

View file

@ -0,0 +1,44 @@
# Original taken and modified from:
# https://github.com/ihowson/Teensy-Raw-HID-in-Python/blob/master/teensy_loader_cli/49-teensy.rules
#
# This file must be placed at:
#
# /etc/udev/rules.d/ArduinoRawHID.rules (preferred location)
# or
# /lib/udev/rules.d/ArduinoRawHID.rules (req'd on some broken systems)
#
# SUBSYSTEMS=="usb", ATTRS{idVendor}=="0x2341", ATTRS{idProduct}=="0x8036", MODE:="0666"
#
# Reload udev rules:
# udevadm control --reload && udevadm trigger
#
#
# Arduino devices (leonardo only, or all Arduino devices):
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8036", MODE:="0666"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", MODE:="0666"
#
#
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", MODE:="0666"
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="8000", MODE:="0666"
#KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", SYMLINK+="ttyUSB00%n", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
#
# If you share your linux system with other users, or just don't like the
# idea of write permission for everybody, you can replace MODE:="0666" with
# OWNER:="yourusername" to create the device owned by you, or with
# GROUP:="somegroupname" and mange access using standard unix groups.
#
#
# If using USB Serial you get a new device each time (Ubuntu 9.10)
# eg: /dev/ttyACM0, ttyACM1, ttyACM2, ttyACM3, ttyACM4, etc
# apt-get remove --purge modemmanager (reboot may be necessary)
#
#
# Older modem proding (eg, Ubuntu 9.04) caused very slow serial device detection.
# To fix, add this near top of /lib/udev/rules.d/77-nm-probe-modem-capabilities.rules
# SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", GOTO="nm_modem_probe_end"
#
#
# (old udev rules)
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="047[78]", MODE:="0666"
#SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="048[02]", MODE:="0666"
#KERNEL=="ttyACM*", SYMLINK+="ttyUSB00%n", MODE:="0666"

View file

@ -144,7 +144,7 @@ int rawhid_send(int num, void *buf, int len, int timeout)
if (hid->ep_out) { if (hid->ep_out) {
return usb_interrupt_write(hid->usb, hid->ep_out, buf, len, timeout); return usb_interrupt_write(hid->usb, hid->ep_out, buf, len, timeout);
} else { } else {
return usb_control_msg(hid->usb, 0x21, 9, 0, hid->iface, buf, len, timeout); return usb_control_msg(hid->usb, 0x21, 9, 0x0200, hid->iface, buf, len, timeout);
} }
} }

View file

@ -13,6 +13,8 @@
begin KEYWORD2 begin KEYWORD2
end KEYWORD2 end KEYWORD2
press KEYWORD2 press KEYWORD2
add KEYWORD2
remove KEYWORD2
release KEYWORD2 release KEYWORD2
releaseAll KEYWORD2 releaseAll KEYWORD2
@ -22,13 +24,10 @@ moveTo KEYWORD2
isPressed KEYWORD2 isPressed KEYWORD2
getLeds KEYWORD2 getLeds KEYWORD2
pressKeycode KEYWORD2 setFeatureReport KEYWORD2
releaseKeycode KEYWORD2 availableFeatureReport KEYWORD2
writeKeycode KEYWORD2 enableFeatureReport KEYWORD2
addKeyToReport KEYWORD2 disableFeatureReport KEYWORD2
addKeycodeToReport KEYWORD2
removeKeyFromReport KEYWORD2
removeKeycodeFromReport KEYWORD2
write_unicode KEYWORD2 write_unicode KEYWORD2
set_modifier KEYWORD2 set_modifier KEYWORD2
@ -39,7 +38,7 @@ set_key4 KEYWORD2
set_key5 KEYWORD2 set_key5 KEYWORD2
set_key6 KEYWORD2 set_key6 KEYWORD2
set_media KEYWORD2 set_media KEYWORD2
send_now KEYWORD2 send KEYWORD2
buttons KEYWORD2 buttons KEYWORD2
xAxis KEYWORD2 xAxis KEYWORD2

View file

@ -1,10 +1,10 @@
name=HID-Project name=HID-Project
version=2.4 version=2.4.4
author=NicoHood author=NicoHood
maintainer=NicoHood <blog@NicoHood.de> maintainer=NicoHood <blog@NicoHood.de>
sentence=Extended HID Functions for Arduino sentence=Extended HID Functions for Arduino
paragraph=Includes Consumer, System and Gamepad. Also compatible with Arduino Uno/Mega via HoodLoader2. paragraph=Includes BootKeyboard/Mouse, Consumer, System, Gamepad, RawHID and more features. Also compatible with Arduino Uno/Mega via HoodLoader2.
category=Device Control category=Communication
url=https://github.com/NicoHood/HID url=https://github.com/NicoHood/HID
architectures=* architectures=avr
dot_a_linkage=true dot_a_linkage=true

View file

@ -1,45 +0,0 @@
{
"packages": [
{
"name": "HID",
"maintainer": "NicoHood",
"websiteURL": "https://github.com/NicoHood/HID",
"email": "",
"help": {
"online": ""
},
"platforms": [
{
"name": "HID Project",
"architecture": "avr",
"version": "2.2",
"category": "HID",
"help": {
"online": ""
},
"url": "https://github.com/NicoHood/HID/releases/download/2.2/2.2-boards_manager.zip",
"archiveFileName": "2.2-boards_manager.zip",
"checksum": "SHA-256:9c86ee28a7ce9fe33e8b07ec643316131e0031b0d22e63bb398902a5fdadbca9",
"size": "351303",
"boards": [
{"name": "Arduino Leonardo"},
{"name": "Arduino Micro"}
],
"toolsDependencies": [
{
"packager": "arduino",
"name": "avr-gcc",
"version": "4.8.1-arduino5"
},
{
"packager": "arduino",
"name": "avrdude",
"version": "6.0.1-arduino5"
}
]
}
],
"tools": []
}
]
}

View file

@ -39,9 +39,9 @@ THE SOFTWARE.
typedef union{ typedef union{
// Absolute mouse report: 8 buttons, 2 absolute axis, wheel // Absolute mouse report: 8 buttons, 2 absolute axis, wheel
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
struct{ struct{
uint8_t buttons; uint8_t buttons;
int16_t xAxis; int16_t xAxis;
@ -71,12 +71,12 @@ public:
inline void move(int x, int y, signed char wheel = 0); inline void move(int x, int y, signed char wheel = 0);
inline void press(uint8_t b = MOUSE_LEFT); inline void press(uint8_t b = MOUSE_LEFT);
inline void release(uint8_t b = MOUSE_LEFT); inline void release(uint8_t b = MOUSE_LEFT);
inline void releaseAll(void);
inline bool isPressed(uint8_t b = MOUSE_LEFT); inline bool isPressed(uint8_t b = MOUSE_LEFT);
// Sending is public in the base class for advanced users. // Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0; virtual void SendReport(void* data, int length) = 0;
}; };
// Implementation is inline // Implementation is inline
#include "AbsoluteMouseAPI.hpp" #include "AbsoluteMouseAPI.hpp"

View file

@ -32,7 +32,7 @@ void AbsoluteMouseAPI::buttons(uint8_t b){
} }
int16_t AbsoluteMouseAPI::qadd16(int16_t base, int16_t increment) { int16_t AbsoluteMouseAPI::qadd16(int16_t base, int16_t increment) {
// Separate between subtracting and adding // Separate between subtracting and adding
if (increment < 0) { if (increment < 0) {
// Subtracting more would cause an undefined overflow // Subtracting more would cause an undefined overflow
if ((int16_t)0x8000 - increment > base) if ((int16_t)0x8000 - increment > base)
@ -50,7 +50,7 @@ int16_t AbsoluteMouseAPI::qadd16(int16_t base, int16_t increment) {
return base; return base;
} }
AbsoluteMouseAPI::AbsoluteMouseAPI(void): AbsoluteMouseAPI::AbsoluteMouseAPI(void):
xAxis(0), yAxis(0), _buttons(0) xAxis(0), yAxis(0), _buttons(0)
{ {
// Empty // Empty
@ -98,6 +98,11 @@ void AbsoluteMouseAPI::release(uint8_t b){
buttons(_buttons & ~b); buttons(_buttons & ~b);
} }
void AbsoluteMouseAPI::releaseAll(void){
_buttons = 0;
moveTo(xAxis, yAxis, 0);
}
bool AbsoluteMouseAPI::isPressed(uint8_t b){ bool AbsoluteMouseAPI::isPressed(uint8_t b){
// check LEFT by default // check LEFT by default
if ((b & _buttons) > 0) if ((b & _buttons) > 0)

View file

@ -49,6 +49,9 @@ enum ConsumerKeycode : uint16_t {
MEDIA_VOLUME_DOWN = 0xEA, MEDIA_VOLUME_DOWN = 0xEA,
MEDIA_VOL_DOWN = 0xEA, // Alias MEDIA_VOL_DOWN = 0xEA, // Alias
CONSUMER_BRIGHTNESS_UP = 0x006F,
CONSUMER_BRIGHTNESS_DOWN = 0x0070,
CONSUMER_SCREENSAVER = 0x19e, CONSUMER_SCREENSAVER = 0x19e,
CONSUMER_PROGRAMMABLE_BUTTON_CONFIGURATION = 0x182, CONSUMER_PROGRAMMABLE_BUTTON_CONFIGURATION = 0x182,
@ -450,9 +453,9 @@ enum ConsumerKeycode : uint16_t {
typedef union { typedef union {
// Every usable Consumer key possible, up to 4 keys presses possible // Every usable Consumer key possible, up to 4 keys presses possible
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
ConsumerKeycode keys[4]; ConsumerKeycode keys[4];
struct { struct {
ConsumerKeycode key1; ConsumerKeycode key1;
@ -472,7 +475,7 @@ public:
inline void press(ConsumerKeycode m); inline void press(ConsumerKeycode m);
inline void release(ConsumerKeycode m); inline void release(ConsumerKeycode m);
inline void releaseAll(void); inline void releaseAll(void);
// Sending is public in the base class for advanced users. // Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0; virtual void SendReport(void* data, int length) = 0;
@ -482,4 +485,3 @@ protected:
// Implementation is inline // Implementation is inline
#include "ConsumerAPI.hpp" #include "ConsumerAPI.hpp"

View file

@ -29,9 +29,9 @@ THE SOFTWARE.
typedef union{ typedef union{
// Low level key report: up to 6 keys and shift, ctrl etc at once // Low level key report: up to 6 keys and shift, ctrl etc at once
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
struct{ struct{
uint8_t modifiers; uint8_t modifiers;
uint8_t reserved; uint8_t reserved;
@ -74,4 +74,3 @@ private:
// Implementation is inline // Implementation is inline
#include "DefaultKeyboardAPI.hpp" #include "DefaultKeyboardAPI.hpp"

View file

@ -33,7 +33,7 @@ size_t DefaultKeyboardAPI::set(KeyboardKeycode k, bool s)
// Convert key into bitfield (0 - 7) // Convert key into bitfield (0 - 7)
k = KeyboardKeycode(uint8_t(k) - uint8_t(KEY_LEFT_CTRL)); k = KeyboardKeycode(uint8_t(k) - uint8_t(KEY_LEFT_CTRL));
if(s){ if(s){
_keyReport.modifiers = (1 << k); _keyReport.modifiers |= (1 << k);
} }
else{ else{
_keyReport.modifiers &= ~(1 << k); _keyReport.modifiers &= ~(1 << k);

View file

@ -41,9 +41,9 @@ THE SOFTWARE.
typedef union { typedef union {
// 32 Buttons, 6 Axis, 2 D-Pads // 32 Buttons, 6 Axis, 2 D-Pads
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
uint32_t buttons; uint32_t buttons;
struct{ struct{
@ -117,7 +117,7 @@ public:
inline void rzAxis(int8_t a); inline void rzAxis(int8_t a);
inline void dPad1(int8_t d); inline void dPad1(int8_t d);
inline void dPad2(int8_t d); inline void dPad2(int8_t d);
// Sending is public in the base class for advanced users. // Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0; virtual void SendReport(void* data, int length) = 0;
@ -127,4 +127,3 @@ protected:
// Implementation is inline // Implementation is inline
#include "GamepadAPI.hpp" #include "GamepadAPI.hpp"

View file

@ -39,9 +39,9 @@ THE SOFTWARE.
typedef union{ typedef union{
// Mouse report: 8 buttons, position, wheel // Mouse report: 8 buttons, position, wheel
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
struct{ struct{
uint8_t buttons; uint8_t buttons;
int8_t xAxis; int8_t xAxis;
@ -53,9 +53,9 @@ typedef union{
typedef union{ typedef union{
// BootMouse report: 3 buttons, position // BootMouse report: 3 buttons, position
// Wheel is not supported by boot protocol // Wheel is not supported by boot protocol
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
struct{ struct{
uint8_t buttons; uint8_t buttons;
int8_t xAxis; int8_t xAxis;
@ -70,14 +70,15 @@ public:
inline void begin(void); inline void begin(void);
inline void end(void); inline void end(void);
inline void click(uint8_t b = MOUSE_LEFT); inline void click(uint8_t b = MOUSE_LEFT);
inline void move(signed char x, signed char y, signed char wheel = 0); inline void move(signed char x, signed char y, signed char wheel = 0);
inline void press(uint8_t b = MOUSE_LEFT); // press LEFT by default inline void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
inline void release(uint8_t b = MOUSE_LEFT); // release LEFT by default inline void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
inline void releaseAll(void);
inline bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default inline bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
// Sending is public in the base class for advanced users. // Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0; virtual void SendReport(void* data, int length) = 0;
protected: protected:
uint8_t _buttons; uint8_t _buttons;
inline void buttons(uint8_t b); inline void buttons(uint8_t b);

View file

@ -29,12 +29,12 @@ MouseAPI::MouseAPI(void) : _buttons(0)
// Empty // Empty
} }
void MouseAPI::begin(void) void MouseAPI::begin(void)
{ {
end(); end();
} }
void MouseAPI::end(void) void MouseAPI::end(void)
{ {
_buttons = 0; _buttons = 0;
move(0, 0, 0); move(0, 0, 0);
@ -67,7 +67,7 @@ void MouseAPI::buttons(uint8_t b)
} }
} }
void MouseAPI::press(uint8_t b) void MouseAPI::press(uint8_t b)
{ {
buttons(_buttons | b); buttons(_buttons | b);
} }
@ -77,10 +77,15 @@ void MouseAPI::release(uint8_t b)
buttons(_buttons & ~b); buttons(_buttons & ~b);
} }
void MouseAPI::releaseAll(void)
{
_buttons = 0;
move(0,0,0);
}
bool MouseAPI::isPressed(uint8_t b) bool MouseAPI::isPressed(uint8_t b)
{ {
if ((b & _buttons) > 0) if ((b & _buttons) > 0)
return true; return true;
return false; return false;
} }

View file

@ -32,9 +32,9 @@ THE SOFTWARE.
typedef union{ typedef union{
// Modifier + keymap + 1 custom key // Modifier + keymap + 1 custom key
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
struct{ struct{
uint8_t modifiers; uint8_t modifiers;
uint8_t keys[NKRO_KEY_COUNT / 8]; uint8_t keys[NKRO_KEY_COUNT / 8];
@ -43,7 +43,7 @@ typedef union{
uint8_t allkeys[2 + NKRO_KEY_COUNT / 8]; uint8_t allkeys[2 + NKRO_KEY_COUNT / 8];
} HID_NKROKeyboardReport_Data_t; } HID_NKROKeyboardReport_Data_t;
class NKROKeyboardAPI : public KeyboardAPI class NKROKeyboardAPI : public KeyboardAPI
{ {
public: public:
@ -62,4 +62,3 @@ private:
// Implementation is inline // Implementation is inline
#include "NKROKeyboardAPI.hpp" #include "NKROKeyboardAPI.hpp"

View file

@ -45,7 +45,7 @@ size_t NKROKeyboardAPI::set(KeyboardKeycode k, bool s)
// Convert key into bitfield (0 - 7) // Convert key into bitfield (0 - 7)
k = KeyboardKeycode(uint8_t(k) - uint8_t(KEY_LEFT_CTRL)); k = KeyboardKeycode(uint8_t(k) - uint8_t(KEY_LEFT_CTRL));
if(s){ if(s){
_keyReport.modifiers = (1 << k); _keyReport.modifiers |= (1 << k);
} }
else{ else{
_keyReport.modifiers &= ~(1 << k); _keyReport.modifiers &= ~(1 << k);

View file

@ -0,0 +1,66 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include guard
#pragma once
#include <Arduino.h>
#include "HID-Settings.h"
typedef union{
// SurfaceDial report: 1 button, 15-bit rotation, position
uint8_t whole8[0];
uint16_t whole16[0];
uint32_t whole32[0];
struct{
uint16_t button: 1;
uint16_t rotation: 15;
//int8_t xAxis;
//int8_t yAxis;
};
} HID_SurfaceDialReport_Data_t;
class SurfaceDialAPI
{
public:
inline SurfaceDialAPI(void);
inline void begin(void);
inline void end(void);
inline void click(void);
inline void rotate(int16_t rotation);
inline void press(void);
inline void release(void);
inline void releaseAll(void);
inline bool isPressed();
// Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0;
protected:
bool _button;
inline void button(bool b);
};
// Implementation is inline
#include "SurfaceDialAPI.hpp"

View file

@ -0,0 +1,90 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include guard
#pragma once
SurfaceDialAPI::SurfaceDialAPI(void) : _button(false)
{
// Empty
}
void SurfaceDialAPI::begin(void)
{
end();
}
void SurfaceDialAPI::end(void)
{
_button = false;
rotate(0);
}
void SurfaceDialAPI::click(void)
{
_button = true;
rotate(0);
_button = false;
rotate(0);
}
void SurfaceDialAPI::rotate(int16_t rotation)
{
HID_SurfaceDialReport_Data_t report;
report.button = _button;
report.rotation = rotation;
//report.xAxis = x;
//report.yAxis = y;
SendReport(&report, sizeof(report));
}
void SurfaceDialAPI::button(bool b)
{
if (b != _button)
{
_button = b;
rotate(0);
}
}
void SurfaceDialAPI::press(void)
{
button(true);
}
void SurfaceDialAPI::release(void)
{
button(false);
}
void SurfaceDialAPI::releaseAll(void)
{
_button = false;
rotate(0);
}
bool SurfaceDialAPI::isPressed()
{
return _button;
}

View file

@ -76,7 +76,7 @@ enum SystemKeycode : uint8_t {
typedef union{ typedef union{
// Every usable system control key possible // Every usable system control key possible
uint8_t whole8[]; uint8_t whole8[0];
uint8_t key; uint8_t key;
} HID_SystemControlReport_Data_t; } HID_SystemControlReport_Data_t;
@ -89,7 +89,7 @@ public:
inline void press(SystemKeycode s); inline void press(SystemKeycode s);
inline void release(void); inline void release(void);
inline void releaseAll(void); inline void releaseAll(void);
// Sending is public in the base class for advanced users. // Sending is public in the base class for advanced users.
virtual void SendReport(void* data, int length) = 0; virtual void SendReport(void* data, int length) = 0;
}; };

View file

@ -25,13 +25,10 @@ THE SOFTWARE.
#pragma once #pragma once
// Software version // Software version
#define HID_PROJECT_VERSION 240 #define HID_PROJECT_VERSION 244
// TODO remove https://github.com/arduino/arduino-builder/issues/33 #if ARDUINO < 10607
#include <Arduino.h> #error HID Project requires Arduino IDE 1.6.7 or greater. Please update your IDE.
#if ARDUINO < 10606
#error HID Project requires Arduino IDE 1.6.6 or greater. Please update your IDE.
#endif #endif
#if !defined(USBCON) #if !defined(USBCON)
@ -54,7 +51,7 @@ THE SOFTWARE.
#include "MultiReport/ImprovedKeyboard.h" #include "MultiReport/ImprovedKeyboard.h"
#include "SingleReport/SingleNKROKeyboard.h" #include "SingleReport/SingleNKROKeyboard.h"
#include "MultiReport/NKROKeyboard.h" #include "MultiReport/NKROKeyboard.h"
#include "MultiReport/SurfaceDial.h"
// Include Teensy HID afterwards to overwrite key definitions if used // Include Teensy HID afterwards to overwrite key definitions if used
// TODO include Teensy API if non english keyboard layout was used // TODO include Teensy API if non english keyboard layout was used

View file

@ -108,3 +108,7 @@ THE SOFTWARE.
#ifndef HID_REPORTID_TEENSY_KEYBOARD #ifndef HID_REPORTID_TEENSY_KEYBOARD
#define HID_REPORTID_TEENSY_KEYBOARD 9 #define HID_REPORTID_TEENSY_KEYBOARD 9
#endif #endif
#ifndef HID_REPORTID_SURFACEDIAL
#define HID_REPORTID_SURFACEDIAL 10
#endif

View file

@ -37,8 +37,7 @@ public:
Keyboard_(void); Keyboard_(void);
void wakeupHost(void); void wakeupHost(void);
protected: virtual inline int send(void) final;
virtual inline int send(void) override;
}; };
extern Keyboard_ Keyboard; extern Keyboard_ Keyboard;

View file

@ -36,8 +36,7 @@ class NKROKeyboard_ : public NKROKeyboardAPI
public: public:
NKROKeyboard_(void); NKROKeyboard_(void);
protected: virtual int send(void) final;
virtual inline int send(void) override;
}; };
extern NKROKeyboard_ NKROKeyboard; extern NKROKeyboard_ NKROKeyboard;

View file

@ -0,0 +1,87 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "SurfaceDial.h"
static const uint8_t _hidMultiReportDescriptorSurfaceDial[] PROGMEM = {
// Integrated Radial Controller TLC
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x0e, // USAGE (System Multi-Axis Controller)
0xa1, 0x01, // COLLECTION (Application)
0x85, HID_REPORTID_SURFACEDIAL, // REPORT_ID (Radial Controller)
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x21, // USAGE (Puck)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Buttons)
0x09, 0x01, // USAGE (Button 1)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x37, // USAGE (Dial)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x0f, // REPORT_SIZE (15)
0x55, 0x0f, // UNIT_EXPONENT (-1)
0x65, 0x14, // UNIT (Degrees, English Rotation)
0x36, 0xf0, 0xf1, // PHYSICAL_MINIMUM (-3600)
0x46, 0x10, 0x0e, // PHYSICAL_MAXIMUM (3600)
0x16, 0xf0, 0xf1, // LOGICAL_MINIMUM (-3600)
0x26, 0x10, 0x0e, // LOGICAL_MAXIMUM (3600)
0x81, 0x06, // INPUT (Data,Var,Rel)
// 0x09, 0x30, // USAGE (X)
// 0x75, 0x10, // REPORT_SIZE (16)
// 0x55, 0x0d, // UNIT_EXPONENT (-3)
// 0x65, 0x13, // UNIT (Inch,EngLinear)
// 0x35, 0x00, // PHYSICAL_MINIMUM (0)
// 0x46, 0xc0, 0x5d, // PHYSICAL_MAXIMUM (24000)
// 0x15, 0x00, // LOGICAL_MINIMUM (0)
// 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
// 0x81, 0x02, // INPUT (Data,Var,Abs)
// 0x09, 0x31, // USAGE (Y)
// 0x46, 0xb0, 0x36, // PHYSICAL_MAXIMUM (14000)
// 0x81, 0x02, // INPUT (Data,Var,Abs)
// 0x05, 0x0d, // USAGE_PAGE (Digitizers)
// 0x09, 0x48, // USAGE (Width)
// 0x36, 0xb8, 0x0b, // PHYSICAL_MINIMUM (3000)
// 0x46, 0xb8, 0x0b, // PHYSICAL_MAXIMUM (3000)
// 0x16, 0xb8, 0x0b, // LOGICAL_MINIMUM (3000)
// 0x26, 0xb8, 0x0b, // LOGICAL_MAXIMUM (3000)
// 0x81, 0x03 // INPUT (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
SurfaceDial_::SurfaceDial_(void)
{
static HIDSubDescriptor node(_hidMultiReportDescriptorSurfaceDial, sizeof(_hidMultiReportDescriptorSurfaceDial));
HID().AppendDescriptor(&node);
}
void SurfaceDial_::SendReport(void *data, int length)
{
HID().SendReport(HID_REPORTID_SURFACEDIAL, data, length);
}
SurfaceDial_ SurfaceDial;

View file

@ -0,0 +1,43 @@
/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include guard
#pragma once
#include <Arduino.h>
#include "PluggableUSB.h"
#include "HID.h"
#include "HID-Settings.h"
#include "../HID-APIs/SurfaceDialAPI.h"
class SurfaceDial_ : public SurfaceDialAPI
{
public:
SurfaceDial_(void);
protected:
virtual inline void SendReport(void* data, int length) override;
};
extern SurfaceDial_ SurfaceDial;

View file

@ -71,7 +71,7 @@ static const uint8_t _hidReportDescriptorKeyboard[] PROGMEM = {
0xc0 /* END_COLLECTION */ 0xc0 /* END_COLLECTION */
}; };
BootKeyboard_::BootKeyboard_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), leds(0) BootKeyboard_::BootKeyboard_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), leds(0), featureReport(NULL), featureLength(0)
{ {
epType[0] = EP_TYPE_INTERRUPT_IN; epType[0] = EP_TYPE_INTERRUPT_IN;
PluggableUSB().plug(this); PluggableUSB().plug(this);
@ -120,10 +120,12 @@ bool BootKeyboard_::setup(USBSetup& setup)
return true; return true;
} }
if (request == HID_GET_PROTOCOL) { if (request == HID_GET_PROTOCOL) {
// TODO improve
UEDATX = protocol; UEDATX = protocol;
return true; return true;
} }
if (request == HID_GET_IDLE) { if (request == HID_GET_IDLE) {
// TODO improve
UEDATX = idle; UEDATX = idle;
return true; return true;
} }
@ -141,10 +143,39 @@ bool BootKeyboard_::setup(USBSetup& setup)
} }
if (request == HID_SET_REPORT) if (request == HID_SET_REPORT)
{ {
// Check if data has the correct length // Check if data has the correct length afterwards
auto length = setup.wLength; int length = setup.wLength;
if(length == sizeof(leds)){
USB_RecvControl(&leds, length); // Feature (set feature report)
if(setup.wValueH == HID_REPORT_TYPE_FEATURE){
// No need to check for negative featureLength values,
// except the host tries to send more then 32k bytes.
// We dont have that much ram anyways.
if (length == featureLength) {
USB_RecvControl(featureReport, featureLength);
// Block until data is read (make length negative)
disableFeatureReport();
return true;
}
// TODO fake clear data?
}
// Output (set led states)
else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){
if(length == sizeof(leds)){
USB_RecvControl(&leds, length);
return true;
}
}
// Input (set HID report)
else if(setup.wValueH == HID_REPORT_TYPE_INPUT)
{
if(length == sizeof(_keyReport)){
USB_RecvControl(&_keyReport, length);
return true;
}
} }
} }
} }

View file

@ -38,6 +38,33 @@ public:
uint8_t getLeds(void); uint8_t getLeds(void);
uint8_t getProtocol(void); uint8_t getProtocol(void);
void wakeupHost(void); void wakeupHost(void);
void setFeatureReport(void* report, int length){
if(length > 0){
featureReport = (uint8_t*)report;
featureLength = length;
// Disable feature report by default
disableFeatureReport();
}
}
int availableFeatureReport(void){
if(featureLength < 0){
return featureLength & ~0x8000;
}
return 0;
}
void enableFeatureReport(void){
featureLength &= ~0x8000;
}
void disableFeatureReport(void){
featureLength |= 0x8000;
}
virtual int send(void) final;
protected: protected:
// Implementation of the PUSBListNode // Implementation of the PUSBListNode
@ -51,7 +78,8 @@ protected:
uint8_t leds; uint8_t leds;
virtual int send(void) override; uint8_t* featureReport;
int featureLength;
}; };
extern BootKeyboard_ BootKeyboard; extern BootKeyboard_ BootKeyboard;

View file

@ -47,13 +47,7 @@ static const uint8_t _hidReportDescriptorRawHID[] PROGMEM = {
0xC0 /* end collection */ 0xC0 /* end collection */
}; };
// Weak implementation of the Event function RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0), dataAvailable(0), featureReport(NULL), featureLength(0)
void RawHIDEvent(void) __attribute__ ((weak));
void RawHIDEvent(void){
// Empty
}
RawHID_::RawHID_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), dataLength(0)
{ {
epType[0] = EP_TYPE_INTERRUPT_IN; epType[0] = EP_TYPE_INTERRUPT_IN;
PluggableUSB().plug(this); PluggableUSB().plug(this);
@ -120,50 +114,36 @@ bool RawHID_::setup(USBSetup& setup)
} }
if (request == HID_SET_REPORT) if (request == HID_SET_REPORT)
{ {
// Get the data length information and the corresponding bytes // Check if data has the correct length afterwards
int length = setup.wLength; int length = setup.wLength;
while(length)
{ // Feature (set feature report)
// Dont receive more than the USB EP has to offer if(setup.wValueH == HID_REPORT_TYPE_FEATURE){
// TODO use fixed 64 because control EP always have 64 bytes even on 16 u2. Test! // No need to check for negative featureLength values,
auto recvLength = length; // except the host tries to send more then 32k bytes.
if(recvLength > USB_EP_SIZE){ // We dont have that much ram anyways.
recvLength = USB_EP_SIZE; if (length == featureLength) {
} USB_RecvControl(featureReport, featureLength);
if(recvLength > int(sizeof(data))){
recvLength = int(sizeof(data)); // Block until data is read (make length negative)
} disableFeatureReport();
length -= recvLength; return true;
}
// Only receive data if the last one was read fully. }
// Discard data if it wasnt read yet.
// To not miss any data you can use the (weak) event function. // Output (set out report)
if(!dataLength) else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){
{ if(!dataAvailable && length <= dataLength){
// Write data to fit to the end (not the beginning) of the array // Write data to fit to the end (not the beginning) of the array
USB_RecvControl(data + (sizeof(data) - recvLength), recvLength); USB_RecvControl(data + dataLength - length, length);
dataLength = recvLength; dataAvailable = length;
RawHIDEvent(); return true;
}
// Do not read the data, flag an error to the USB Host
// TODO always return no error, even if data was discarded? -> use break then
else{
return false;
} }
} }
// Flag no error
// TODO this is required to get hyperion working
// however this blocks the CDC serial!?
return true;
} }
} }
return false; return false;
} }
void RawHID_::SendReport(void* data, int length){
USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length);
}
RawHID_ RawHID; RawHID_ RawHID;

View file

@ -54,17 +54,17 @@ THE SOFTWARE.
typedef union{ typedef union{
// a RAWHID_TX_SIZE byte buffer for tx // a RAWHID_TX_SIZE byte buffer for tx
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
uint8_t buff[RAWHID_TX_SIZE]; uint8_t buff[RAWHID_TX_SIZE];
} HID_RawKeyboardTXReport_Data_t; } HID_RawKeyboardTXReport_Data_t;
typedef union{ typedef union{
// a RAWHID_TX_SIZE byte buffer for rx // a RAWHID_TX_SIZE byte buffer for rx
uint8_t whole8[]; uint8_t whole8[0];
uint16_t whole16[]; uint16_t whole16[0];
uint32_t whole32[]; uint32_t whole32[0];
uint8_t buff[RAWHID_RX_SIZE]; uint8_t buff[RAWHID_RX_SIZE];
} HID_RawKeyboardRXReport_Data_t; } HID_RawKeyboardRXReport_Data_t;
@ -73,36 +73,77 @@ class RawHID_ : public PluggableUSBModule, public Stream
public: public:
RawHID_(void); RawHID_(void);
void begin(void){ void setFeatureReport(void* report, int length){
// empty if(length > 0){
featureReport = (uint8_t*)report;
featureLength = length;
// Disable feature report by default
disableFeatureReport();
}
}
int availableFeatureReport(void){
if(featureLength < 0){
return featureLength & ~0x8000;
}
return 0;
}
void enableFeatureReport(void){
featureLength &= ~0x8000;
}
void disableFeatureReport(void){
featureLength |= 0x8000;
}
void begin(void* report, int length){
if(length > 0){
data = (uint8_t*)report;
dataLength = length;
dataAvailable = 0;
}
} }
void end(void){ void end(void){
// empty disable();
dataLength = 0;
} }
void enable(void){
dataAvailable = 0;
}
void disable(void){
dataAvailable = -1;
}
virtual int available(void){ virtual int available(void){
return dataLength; if(dataAvailable < 0){
return 0;
}
return dataAvailable;
} }
virtual int read(){ virtual int read(){
// Check if we have data available // Check if we have data available
if(dataLength) if(dataAvailable > 0)
{ {
// Get next data byte (from the start to the end) // Get next data byte (from the start to the end)
return data[sizeof(data) - dataLength--]; return data[dataLength - dataAvailable--];
} }
return -1; return -1;
} }
virtual int peek(){ virtual int peek(){
// Check if we have data available // Check if we have data available
if(dataLength){ if(dataAvailable > 0){
return data[sizeof(data) - dataLength]; return data[dataLength - dataAvailable];
} }
return -1; return -1;
} }
virtual void flush(void){ virtual void flush(void){
// Writing will always flush by the USB driver // Writing will always flush by the USB driver
} }
@ -114,40 +155,25 @@ public:
} }
virtual size_t write(uint8_t *buffer, size_t size){ virtual size_t write(uint8_t *buffer, size_t size){
// TODO this will split the data into proper USB_EP_SIZE packets already return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, buffer, size);
SendReport(buffer, size);
return size;
size_t bytesleft = size;
// First work through the buffer thats already there
while (bytesleft >= RAWHID_TX_SIZE){
SendReport(&buffer[size - bytesleft], RAWHID_TX_SIZE);
bytesleft -= RAWHID_TX_SIZE;
}
// Write down the leftover bytes and fill with zeros
if (bytesleft){
SendReport(&buffer[size - bytesleft], bytesleft);
}
return size;
} }
void SendReport(void* data, int length);
protected: protected:
// Implementation of the PUSBListNode // Implementation of the PUSBListNode
int getInterface(uint8_t* interfaceCount); int getInterface(uint8_t* interfaceCount);
int getDescriptor(USBSetup& setup); int getDescriptor(USBSetup& setup);
bool setup(USBSetup& setup); bool setup(USBSetup& setup);
uint8_t epType[1]; uint8_t epType[1];
uint8_t protocol; uint8_t protocol;
uint8_t idle; uint8_t idle;
// Buffer pointers to hold the received data // Buffer pointers to hold the received data
int dataLength; int dataLength;
uint8_t data[RAWHID_RX_SIZE]; int dataAvailable;
uint8_t* data;
uint8_t* featureReport;
int featureLength;
}; };
extern RawHID_ RawHID; extern RawHID_ RawHID;

View file

@ -37,6 +37,8 @@ public:
SingleNKROKeyboard_(void); SingleNKROKeyboard_(void);
uint8_t getLeds(void); uint8_t getLeds(void);
uint8_t getProtocol(void); uint8_t getProtocol(void);
virtual int send(void) final;
protected: protected:
// Implementation of the PUSBListNode // Implementation of the PUSBListNode
@ -49,8 +51,6 @@ protected:
uint8_t idle; uint8_t idle;
uint8_t leds; uint8_t leds;
virtual inline int send(void) override;
}; };
extern SingleNKROKeyboard_ SingleNKROKeyboard; extern SingleNKROKeyboard_ SingleNKROKeyboard;

BIN
virtualkeyb.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB