Compare commits
7 Commits
main
...
f/driver/k
Author | SHA1 | Date |
---|---|---|
Jesse Vincent | 290a4db2d4 | 4 years ago |
Gergely Nagy | cacca53496 | 4 years ago |
Gergely Nagy | 35a8170cec | 4 years ago |
Gergely Nagy | b1e2a889bb | 4 years ago |
Gergely Nagy | 35b1fb239c | 4 years ago |
Gergely Nagy | 2c4a274cb3 | 4 years ago |
Gergely Nagy | ada56fe6b9 | 4 years ago |
@ -0,0 +1,373 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/BootKeyboard/BootKeyboard.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HIDReportObserver.h"
|
||||||
|
|
||||||
|
// See Appendix B of USB HID spec
|
||||||
|
static const uint8_t _hidReportDescriptorKeyboard[] PROGMEM = {
|
||||||
|
// Keyboard
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP,
|
||||||
|
D_USAGE, D_USAGE_KEYBOARD,
|
||||||
|
|
||||||
|
D_COLLECTION, D_APPLICATION,
|
||||||
|
// Modifiers
|
||||||
|
D_USAGE_PAGE, D_PAGE_KEYBOARD,
|
||||||
|
D_USAGE_MINIMUM, 0xe0,
|
||||||
|
D_USAGE_MAXIMUM, 0xe7,
|
||||||
|
D_LOGICAL_MINIMUM, 0x0,
|
||||||
|
D_LOGICAL_MAXIMUM, 0x1,
|
||||||
|
D_REPORT_SIZE, 0x1,
|
||||||
|
D_REPORT_COUNT, 0x8,
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE),
|
||||||
|
|
||||||
|
// Reserved byte
|
||||||
|
D_REPORT_COUNT, 0x1,
|
||||||
|
D_REPORT_SIZE, 0x8,
|
||||||
|
D_INPUT, (D_CONSTANT),
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
D_REPORT_COUNT, 0x5,
|
||||||
|
D_REPORT_SIZE, 0x1,
|
||||||
|
D_USAGE_PAGE, D_PAGE_LEDS,
|
||||||
|
D_USAGE_MINIMUM, 0x1,
|
||||||
|
D_USAGE_MAXIMUM, 0x5,
|
||||||
|
D_OUTPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE),
|
||||||
|
// Pad LEDs up to a byte
|
||||||
|
D_REPORT_COUNT, 0x1,
|
||||||
|
D_REPORT_SIZE, 0x3,
|
||||||
|
D_OUTPUT, (D_CONSTANT),
|
||||||
|
|
||||||
|
// Non-modifiers
|
||||||
|
D_REPORT_COUNT, 0x6,
|
||||||
|
D_REPORT_SIZE, 0x8,
|
||||||
|
D_LOGICAL_MINIMUM, 0x0,
|
||||||
|
D_LOGICAL_MAXIMUM, 0xff,
|
||||||
|
D_USAGE_PAGE, D_PAGE_KEYBOARD,
|
||||||
|
D_USAGE_MINIMUM, 0x0,
|
||||||
|
D_USAGE_MAXIMUM, 0xff,
|
||||||
|
D_INPUT, (D_DATA | D_ARRAY | D_ABSOLUTE),
|
||||||
|
D_END_COLLECTION
|
||||||
|
};
|
||||||
|
|
||||||
|
BootKeyboard_::BootKeyboard_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), leds(0) {
|
||||||
|
epType[0] = EP_TYPE_INTERRUPT_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BootKeyboard_::getInterface(uint8_t* interfaceCount) {
|
||||||
|
*interfaceCount += 1; // uses 1
|
||||||
|
HIDDescriptor hidInterface = {
|
||||||
|
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_BOOT_INTERFACE, HID_PROTOCOL_KEYBOARD),
|
||||||
|
D_HIDREPORT(sizeof(_hidReportDescriptorKeyboard)),
|
||||||
|
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01)
|
||||||
|
};
|
||||||
|
return USB_SendControl(0, &hidInterface, sizeof(hidInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
int BootKeyboard_::getDescriptor(USBSetup& setup) {
|
||||||
|
// Check if this is a HID Class Descriptor request
|
||||||
|
if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a HID Class Descriptor wIndex cointains the interface number
|
||||||
|
if (setup.wIndex != pluggedInterface) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol
|
||||||
|
// due to the USB specs, but Windows and Linux just assumes its in report mode.
|
||||||
|
protocol = default_protocol;
|
||||||
|
|
||||||
|
return USB_SendControl(TRANSFER_PGM, _hidReportDescriptorKeyboard, sizeof(_hidReportDescriptorKeyboard));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BootKeyboard_::begin(void) {
|
||||||
|
PluggableUSB().plug(this);
|
||||||
|
|
||||||
|
// Force API to send a clean report.
|
||||||
|
// This is important for and HID bridge where the receiver stays on,
|
||||||
|
// while the sender is resetted.
|
||||||
|
releaseAll();
|
||||||
|
sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BootKeyboard_::end(void) {
|
||||||
|
releaseAll();
|
||||||
|
sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool BootKeyboard_::setup(USBSetup& setup) {
|
||||||
|
if (pluggedInterface != setup.wIndex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t request = setup.bRequest;
|
||||||
|
uint8_t requestType = setup.bmRequestType;
|
||||||
|
|
||||||
|
if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) {
|
||||||
|
if (request == HID_GET_REPORT) {
|
||||||
|
// TODO(anyone): HID_GetReport();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_GET_PROTOCOL) {
|
||||||
|
// TODO(anyone) improve
|
||||||
|
#ifdef __AVR__
|
||||||
|
UEDATX = protocol;
|
||||||
|
#endif
|
||||||
|
#ifdef ARDUINO_ARCH_SAM
|
||||||
|
USBDevice.armSend(0, &protocol, 1);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_GET_IDLE) {
|
||||||
|
// TODO(anyone) improve
|
||||||
|
#ifdef __AVR__
|
||||||
|
UEDATX = idle;
|
||||||
|
#endif
|
||||||
|
#ifdef ARDUINO_ARCH_SAM
|
||||||
|
USBDevice.armSend(0, &idle, 1);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) {
|
||||||
|
if (request == HID_SET_PROTOCOL) {
|
||||||
|
protocol = setup.wValueL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_SET_IDLE) {
|
||||||
|
// We currently ignore SET_IDLE, because we don't really do anything with it, and implementing
|
||||||
|
// it causes issues on OSX, such as key chatter. Other operating systems do not suffer if we
|
||||||
|
// force this to zero, either.
|
||||||
|
#if 0
|
||||||
|
idle = setup.wValueL;
|
||||||
|
#else
|
||||||
|
idle = 0;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_SET_REPORT) {
|
||||||
|
// Check if data has the correct length afterwards
|
||||||
|
int length = setup.wLength;
|
||||||
|
|
||||||
|
if (setup.wValueH == HID_REPORT_TYPE_OUTPUT) {
|
||||||
|
if (length == sizeof(leds)) {
|
||||||
|
USB_RecvControl(&leds, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else { // Input (set HID report)
|
||||||
|
if (setup.wValueH == HID_REPORT_TYPE_INPUT) {
|
||||||
|
if (length == sizeof(_keyReport)) {
|
||||||
|
USB_RecvControl(&_keyReport, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BootKeyboard_::getLeds(void) {
|
||||||
|
return leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BootKeyboard_::getProtocol(void) {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BootKeyboard_::setProtocol(uint8_t protocol) {
|
||||||
|
this->protocol = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BootKeyboard_::sendReport(void) {
|
||||||
|
if (memcmp(&_lastKeyReport, &_keyReport, sizeof(_keyReport))) {
|
||||||
|
// if the two reports are different, send a report
|
||||||
|
int returnCode = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_keyReport, sizeof(_keyReport));
|
||||||
|
HIDReportObserver::observeReport(HID_REPORTID_KEYBOARD, &_keyReport, sizeof(_keyReport), returnCode);
|
||||||
|
memcpy(&_lastKeyReport, &_keyReport, sizeof(_keyReport));
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// press() adds the specified key (printing, non-printing, or modifier)
|
||||||
|
// to the persistent key report and sends the report. Because of the way
|
||||||
|
// USB HID works, the host acts like the key remains pressed until we
|
||||||
|
// call release(), releaseAll(), or otherwise clear the report and resend.
|
||||||
|
|
||||||
|
|
||||||
|
size_t BootKeyboard_::press(uint8_t k) {
|
||||||
|
uint8_t done = 0;
|
||||||
|
|
||||||
|
if ((k >= HID_KEYBOARD_FIRST_MODIFIER) && (k <= HID_KEYBOARD_LAST_MODIFIER)) {
|
||||||
|
// it's a modifier key
|
||||||
|
_keyReport.modifiers |= (0x01 << (k - HID_KEYBOARD_FIRST_MODIFIER));
|
||||||
|
} else {
|
||||||
|
// it's some other key:
|
||||||
|
// Add k to the key report only if it's not already present
|
||||||
|
// and if there is an empty slot.
|
||||||
|
for (uint8_t i = 0; i < sizeof(_keyReport.keycodes); i++) {
|
||||||
|
if (_keyReport.keycodes[i] != k) { // is k already in list?
|
||||||
|
if (0 == _keyReport.keycodes[i]) { // have we found an empty slot?
|
||||||
|
_keyReport.keycodes[i] = k;
|
||||||
|
done = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
done = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// use separate variable to check if slot was found
|
||||||
|
// for style reasons - we do not know how the compiler
|
||||||
|
// handles the for() index when it leaves the loop
|
||||||
|
if (0 == done) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// release() takes the specified key out of the persistent key report and
|
||||||
|
// sends the report. This tells the OS the key is no longer pressed and that
|
||||||
|
// it shouldn't be repeated any more.
|
||||||
|
|
||||||
|
size_t BootKeyboard_::release(uint8_t k) {
|
||||||
|
if ((k >= HID_KEYBOARD_FIRST_MODIFIER) && (k <= HID_KEYBOARD_LAST_MODIFIER)) {
|
||||||
|
// it's a modifier key
|
||||||
|
_keyReport.modifiers = _keyReport.modifiers & (~(0x01 << (k - HID_KEYBOARD_FIRST_MODIFIER)));
|
||||||
|
} else {
|
||||||
|
// it's some other key:
|
||||||
|
// Test the key report to see if k is present. Clear it if it exists.
|
||||||
|
// Check all positions in case the key is present more than once (which it shouldn't be)
|
||||||
|
for (uint8_t i = 0; i < sizeof(_keyReport.keycodes); i++) {
|
||||||
|
if (_keyReport.keycodes[i] == k) {
|
||||||
|
_keyReport.keycodes[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rearrange the keys list so that the free (= 0x00) are at the
|
||||||
|
// end of the keys list - some implementations stop for keys at the
|
||||||
|
// first occurence of an 0x00 in the keys list
|
||||||
|
// so (0x00)(0x01)(0x00)(0x03)(0x02)(0x00) becomes
|
||||||
|
// (0x03)(0x02)(0x01)(0x00)(0x00)(0x00)
|
||||||
|
uint8_t current = 0, nextpos = 0;
|
||||||
|
|
||||||
|
while (current < sizeof(_keyReport.keycodes)) {
|
||||||
|
if (_keyReport.keycodes[current]) {
|
||||||
|
uint8_t tmp = _keyReport.keycodes[nextpos];
|
||||||
|
_keyReport.keycodes[nextpos] = _keyReport.keycodes[current];
|
||||||
|
_keyReport.keycodes[current] = tmp;
|
||||||
|
++nextpos;
|
||||||
|
}
|
||||||
|
++current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BootKeyboard_::releaseAll(void) {
|
||||||
|
memset(&_keyReport.bytes, 0x00, sizeof(_keyReport.bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns true if the non-modifer key passed in will be sent during this key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean BootKeyboard_::isKeyPressed(uint8_t k) {
|
||||||
|
for (uint8_t i = 0; i < sizeof(_keyReport.keycodes); i++) {
|
||||||
|
if (_keyReport.keycodes[i] == k) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the non-modifer key passed in was sent during the previous key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean BootKeyboard_::wasKeyPressed(uint8_t k) {
|
||||||
|
for (uint8_t i = 0; i < sizeof(_keyReport.keycodes); i++) {
|
||||||
|
if (_lastKeyReport.keycodes[i] == k) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns true if the modifer key passed in will be sent during this key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean BootKeyboard_::isModifierActive(uint8_t k) {
|
||||||
|
if (k >= HID_KEYBOARD_FIRST_MODIFIER && k <= HID_KEYBOARD_LAST_MODIFIER) {
|
||||||
|
k = k - HID_KEYBOARD_FIRST_MODIFIER;
|
||||||
|
return !!(_keyReport.modifiers & (1 << k));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the modifer key passed in was being sent during the previous key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean BootKeyboard_::wasModifierActive(uint8_t k) {
|
||||||
|
if (k >= HID_KEYBOARD_FIRST_MODIFIER && k <= HID_KEYBOARD_LAST_MODIFIER) {
|
||||||
|
k = k - HID_KEYBOARD_FIRST_MODIFIER;
|
||||||
|
return !!(_lastKeyReport.modifiers & (1 << k));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if any modifier key will be sent during this key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean BootKeyboard_::isAnyModifierActive() {
|
||||||
|
return _keyReport.modifiers > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if any modifier key was being sent during the previous key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean BootKeyboard_::wasAnyModifierActive() {
|
||||||
|
return _lastKeyReport.modifiers > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BootKeyboard_ BootKeyboard;
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HIDAliases.h"
|
||||||
|
#include "kaleidoscope/HIDTables.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// Low level key report: up to 6 keys and shift, ctrl etc at once
|
||||||
|
struct {
|
||||||
|
uint8_t modifiers;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint8_t keycodes[6];
|
||||||
|
};
|
||||||
|
uint8_t bytes[8];
|
||||||
|
} HID_BootKeyboardReport_Data_t;
|
||||||
|
|
||||||
|
|
||||||
|
class BootKeyboard_ : public PluggableUSBModule {
|
||||||
|
public:
|
||||||
|
BootKeyboard_(void);
|
||||||
|
size_t press(uint8_t);
|
||||||
|
void begin(void);
|
||||||
|
void end(void);
|
||||||
|
size_t release(uint8_t);
|
||||||
|
void releaseAll(void);
|
||||||
|
|
||||||
|
int sendReport(void);
|
||||||
|
|
||||||
|
boolean isModifierActive(uint8_t k);
|
||||||
|
boolean wasModifierActive(uint8_t k);
|
||||||
|
boolean isAnyModifierActive();
|
||||||
|
boolean wasAnyModifierActive();
|
||||||
|
boolean isKeyPressed(uint8_t k);
|
||||||
|
boolean wasKeyPressed(uint8_t k);
|
||||||
|
|
||||||
|
uint8_t getLeds(void);
|
||||||
|
uint8_t getProtocol(void);
|
||||||
|
void setProtocol(uint8_t protocol);
|
||||||
|
|
||||||
|
uint8_t default_protocol = HID_REPORT_PROTOCOL;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HID_BootKeyboardReport_Data_t _keyReport, _lastKeyReport;
|
||||||
|
|
||||||
|
// Implementation of the PUSBListNode
|
||||||
|
int getInterface(uint8_t* interfaceCount);
|
||||||
|
int getDescriptor(USBSetup& setup);
|
||||||
|
bool setup(USBSetup& setup);
|
||||||
|
|
||||||
|
EPTYPE_DESCRIPTOR_SIZE epType[1];
|
||||||
|
uint8_t protocol;
|
||||||
|
uint8_t idle;
|
||||||
|
|
||||||
|
uint8_t leds;
|
||||||
|
};
|
||||||
|
extern BootKeyboard_ BootKeyboard;
|
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define D_MULTIBYTE(n) (n + 0x01)
|
||||||
|
|
||||||
|
#define D_USAGE_PAGE 0x05
|
||||||
|
#define D_USAGE 0x09
|
||||||
|
|
||||||
|
|
||||||
|
#define D_REPORT_ID 0x85
|
||||||
|
|
||||||
|
#define D_USAGE_MINIMUM 0x19
|
||||||
|
#define D_USAGE_MAXIMUM 0x29
|
||||||
|
|
||||||
|
#define D_LOGICAL_MINIMUM 0x15
|
||||||
|
#define D_LOGICAL_MAXIMUM 0x25
|
||||||
|
|
||||||
|
#define D_PHYSICAL_MINIMUM 0x35
|
||||||
|
#define D_PHYSICAL_MAXIMUM 0x45
|
||||||
|
|
||||||
|
#define D_REPORT_SIZE 0x75
|
||||||
|
#define D_REPORT_COUNT 0x95
|
||||||
|
|
||||||
|
#define D_PUSH 0xa4
|
||||||
|
#define D_POP 0xb4
|
||||||
|
|
||||||
|
// USB HID DCD 1.11 section 6.2.2.4 - Main items
|
||||||
|
//
|
||||||
|
// each of these are the type description + 0x01 for a single byte item
|
||||||
|
#define D_INPUT 0x81
|
||||||
|
#define D_OUTPUT 0x91
|
||||||
|
#define D_FEATURE 0xb1
|
||||||
|
#define D_COLLECTION 0xa1
|
||||||
|
#define D_END_COLLECTION 0xc0
|
||||||
|
|
||||||
|
// The bits that make up inputs, outputs and features
|
||||||
|
|
||||||
|
// Bit 0
|
||||||
|
#define D_DATA 0b00000000
|
||||||
|
#define D_CONSTANT 0b00000001
|
||||||
|
// Bit 1
|
||||||
|
#define D_ARRAY 0b00000000
|
||||||
|
#define D_VARIABLE 0b00000010
|
||||||
|
// Bit 2
|
||||||
|
#define D_ABSOLUTE 0b00000000
|
||||||
|
#define D_RELATIVE 0b00000100
|
||||||
|
// Bit 3
|
||||||
|
#define D_NO_WRAP 0b00000000
|
||||||
|
#define D_WRAP 0b00001000
|
||||||
|
// Bit 4
|
||||||
|
#define D_LINEAR 0b00000000
|
||||||
|
#define D_NON_LINEAR 0b00010000
|
||||||
|
// Bit 5
|
||||||
|
#define D_PREFERRED_STATE 0b00000000
|
||||||
|
#define D_NO_PREFERRED 0b00100000
|
||||||
|
// Bit 6
|
||||||
|
#define D_NO_NULL_POSITION 0b00000000
|
||||||
|
#define D_NULL_STATE 0b01000000
|
||||||
|
// Bit 7
|
||||||
|
#define D_NON_VOLATILE 0b00000000
|
||||||
|
#define D_VOLATILE 0b01000000
|
||||||
|
|
||||||
|
// Bit 8
|
||||||
|
#define D_BIT_FIELD 0b00000000
|
||||||
|
#define D_BUFFERED_BYTES 0b10000000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Collection types
|
||||||
|
|
||||||
|
|
||||||
|
#define D_PHYSICAL 0x00 // (group of axes)
|
||||||
|
#define D_APPLICATION 0x01 // (mouse, keyboard)
|
||||||
|
#define D_LOGICAL 0x02// (interrelated data)
|
||||||
|
#define D_REPORT 0x03
|
||||||
|
#define D_NAMED_ARRAY 0x04
|
||||||
|
#define D_USAGE_SWITCH 0x05
|
||||||
|
#define D_USAGE_MODIFIER 0x06
|
||||||
|
// 0x07-0x7f - Reserved
|
||||||
|
// 0x80-0xff - Vendor define
|
||||||
|
|
||||||
|
|
||||||
|
#define D_PAGE_GENERIC_DESKTOP 0x01
|
||||||
|
#define D_PAGE_SIMULATION 0x02
|
||||||
|
#define D_PAGE_VR 0x03
|
||||||
|
#define D_PAGE_SPORT 0x04
|
||||||
|
#define D_PAGE_GAME 0x05
|
||||||
|
#define D_PAGE_GENERIC_DEVICE 0x06
|
||||||
|
#define D_PAGE_KEYBOARD 0x07
|
||||||
|
#define D_PAGE_LEDS 0x08
|
||||||
|
#define D_PAGE_BUTTON 0x09
|
||||||
|
#define D_PAGE_ORDINAL 0x0A
|
||||||
|
#define D_PAGE_TELEPHONY 0x0B
|
||||||
|
#define D_PAGE_CONSUMER 0x0C
|
||||||
|
#define D_PAGE_DIGITIZER 0x0D
|
||||||
|
#define D_PAGE_RESERVED 0x0E
|
||||||
|
#define D_PAGE_PID 0x0F
|
||||||
|
#define D_PAGE_UNICODE 0x10
|
||||||
|
// 0x11-13 RESERVED
|
||||||
|
#define D_PAGE_ALPHANUMERIC_DISPLAY 0x14
|
||||||
|
#define D_PAGE_MEDICAL_INSTRUMENTS 0x40
|
||||||
|
// 0x80-83 MONITOR
|
||||||
|
// 0x84-87 POWER
|
||||||
|
#define D_PAGE_BAR_CODE_SCANNER 0x8C
|
||||||
|
#define D_PAGE_SCALE 0x8D
|
||||||
|
#define D_PAGE_MSR 0x8E
|
||||||
|
// 0x8F RESERVED POINT OF SALE
|
||||||
|
#define D_PAGE_CAMERA_CONTROL 0x90
|
||||||
|
#define D_PAGE_ARCADE 0x91
|
||||||
|
|
||||||
|
|
||||||
|
// Generic Desktop Usages HUT Section 4 p27
|
||||||
|
|
||||||
|
|
||||||
|
#define D_USAGE_POINTER 0x01
|
||||||
|
#define D_USAGE_MOUSE 0x02
|
||||||
|
// 0x03 is reserved
|
||||||
|
#define D_USAGE_JOYSTICK 0x04
|
||||||
|
#define D_USAGE_GAMEPAD 0x05
|
||||||
|
#define D_USAGE_KEYBOARD 0x06
|
||||||
|
#define D_USAGE_KEYPAD 0x07
|
||||||
|
#define D_USAGE_MULITAXIS 0x08
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/MouseButtons.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DESCRIPTOR_ABS_MOUSE_BUTTONS \
|
||||||
|
/* 8 Buttons */ \
|
||||||
|
D_USAGE_PAGE, D_PAGE_BUTTON, /* USAGE_PAGE (Button) */ \
|
||||||
|
D_USAGE_MINIMUM, 0x01, /* USAGE_MINIMUM (Button 1) */ \
|
||||||
|
D_USAGE_MAXIMUM, 0x08, /* USAGE_MAXIMUM (Button 8) */ \
|
||||||
|
D_LOGICAL_MINIMUM, 0x00, /* LOGICAL_MINIMUM (0) */ \
|
||||||
|
D_LOGICAL_MAXIMUM, 0x01, /* LOGICAL_MAXIMUM (1) */ \
|
||||||
|
D_REPORT_COUNT, 0x08, /* REPORT_COUNT (8) */ \
|
||||||
|
D_REPORT_SIZE, 0x01, /* REPORT_SIZE (1) */ \
|
||||||
|
D_INPUT, (D_DATA|D_VARIABLE|D_ABSOLUTE),
|
||||||
|
|
||||||
|
# define DESCRIPTOR_ABS_MOUSE_XY \
|
||||||
|
/* X, Y */ \
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) */ \
|
||||||
|
D_USAGE, 0x30, /* USAGE (X) */ \
|
||||||
|
D_USAGE, 0x31, /* USAGE (Y) */ \
|
||||||
|
D_MULTIBYTE(D_LOGICAL_MINIMUM), 0x00, 0x00, /* Logical Minimum (0) */ \
|
||||||
|
D_MULTIBYTE(D_LOGICAL_MAXIMUM), 0xFF, 0x7f, /* Logical Maximum (32767) */ \
|
||||||
|
D_REPORT_SIZE, 0x10, /* Report Size (16), */ \
|
||||||
|
D_REPORT_COUNT, 0x02, /* Report Count (2), */ \
|
||||||
|
D_INPUT, (D_DATA|D_VARIABLE|D_ABSOLUTE), /* Input (Data, Variable, Absolute) */
|
||||||
|
|
||||||
|
#define DESCRIPTOR_ABS_MOUSE_WHEEL \
|
||||||
|
/* Wheel */ \
|
||||||
|
D_USAGE, 0x38, /* USAGE (Wheel) */ \
|
||||||
|
D_LOGICAL_MINIMUM, 0x81, /* LOGICAL_MINIMUM (-127) */ \
|
||||||
|
D_LOGICAL_MAXIMUM, 0x7f, /* LOGICAL_MAXIMUM (127) */ \
|
||||||
|
D_REPORT_SIZE, 0x08, /* REPORT_SIZE (8) */ \
|
||||||
|
D_REPORT_COUNT, 0x01, /* REPORT_COUNT (1) */ \
|
||||||
|
D_INPUT, (D_DATA|D_VARIABLE|D_RELATIVE),
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// Absolute mouse report: 8 buttons, 2 absolute axis, wheel
|
||||||
|
struct {
|
||||||
|
uint8_t buttons;
|
||||||
|
uint16_t xAxis;
|
||||||
|
uint16_t yAxis;
|
||||||
|
int8_t wheel;
|
||||||
|
};
|
||||||
|
} HID_MouseAbsoluteReport_Data_t;
|
||||||
|
|
||||||
|
class AbsoluteMouseAPI {
|
||||||
|
public:
|
||||||
|
inline AbsoluteMouseAPI(void);
|
||||||
|
inline void begin(void);
|
||||||
|
inline void end(void);
|
||||||
|
|
||||||
|
inline void click(uint8_t b = MOUSE_LEFT);
|
||||||
|
inline void moveTo(uint16_t x, uint16_t 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 release(uint8_t b = MOUSE_LEFT);
|
||||||
|
inline bool isPressed(uint8_t b = MOUSE_LEFT);
|
||||||
|
|
||||||
|
// Sending is public in the base class for advanced users.
|
||||||
|
virtual void sendReport(void* data, int length) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint16_t xAxis;
|
||||||
|
uint16_t yAxis;
|
||||||
|
uint8_t _buttons;
|
||||||
|
|
||||||
|
inline void buttons(uint8_t b);
|
||||||
|
inline int16_t qadd16(int16_t base, int16_t increment);
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "AbsoluteMouseAPI.hpp"
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
AbsoluteMouseAPI::AbsoluteMouseAPI(void): xAxis(0), yAxis(0), _buttons(0) { // Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::buttons(uint8_t b) {
|
||||||
|
if (b != _buttons) {
|
||||||
|
_buttons = b;
|
||||||
|
moveTo(xAxis, yAxis, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t AbsoluteMouseAPI::qadd16(int16_t base, int16_t increment) {
|
||||||
|
// Separate between subtracting and adding
|
||||||
|
if (increment < 0) {
|
||||||
|
// Subtracting more would cause an undefined overflow
|
||||||
|
if ((int16_t)0x8000 - increment > base)
|
||||||
|
base = 0x8000;
|
||||||
|
else
|
||||||
|
base += increment;
|
||||||
|
} else {
|
||||||
|
// Adding more would cause an undefined overflow
|
||||||
|
if ((int16_t)0x7FFF - increment < base)
|
||||||
|
base = 0x7FFF;
|
||||||
|
else
|
||||||
|
base += increment;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::begin(void) {
|
||||||
|
// release all buttons
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::end(void) {
|
||||||
|
_buttons = 0;
|
||||||
|
moveTo(xAxis, yAxis, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::click(uint8_t b) {
|
||||||
|
_buttons = b;
|
||||||
|
moveTo(xAxis, yAxis, 0);
|
||||||
|
_buttons = 0;
|
||||||
|
moveTo(xAxis, yAxis, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::moveTo(uint16_t x, uint16_t y, signed char wheel) {
|
||||||
|
xAxis = x;
|
||||||
|
yAxis = y;
|
||||||
|
HID_MouseAbsoluteReport_Data_t report;
|
||||||
|
report.buttons = _buttons;
|
||||||
|
report.xAxis = x;
|
||||||
|
report.yAxis = y;
|
||||||
|
report.wheel = wheel;
|
||||||
|
sendReport(&report, sizeof(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::move(int x, int y, signed char wheel) {
|
||||||
|
moveTo(qadd16(xAxis, x), qadd16(yAxis, y), wheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::press(uint8_t b) {
|
||||||
|
// press LEFT by default
|
||||||
|
buttons(_buttons | b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbsoluteMouseAPI::release(uint8_t b) {
|
||||||
|
// release LEFT by default
|
||||||
|
buttons(_buttons & ~b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbsoluteMouseAPI::isPressed(uint8_t b) {
|
||||||
|
// check LEFT by default
|
||||||
|
if ((b & _buttons) > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
#define HID_REPORTID_NONE 0
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_MOUSE
|
||||||
|
#define HID_REPORTID_MOUSE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_KEYBOARD
|
||||||
|
#define HID_REPORTID_KEYBOARD 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_RAWHID
|
||||||
|
// This will not work properly in most cases.
|
||||||
|
// The number is just kept from the old number counting.
|
||||||
|
//#define HID_REPORTID_RAWHID 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_CONSUMERCONTROL
|
||||||
|
#define HID_REPORTID_CONSUMERCONTROL 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_SYSTEMCONTROL
|
||||||
|
#define HID_REPORTID_SYSTEMCONTROL 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_GAMEPAD
|
||||||
|
#define HID_REPORTID_GAMEPAD 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_MOUSE_ABSOLUTE
|
||||||
|
#define HID_REPORTID_MOUSE_ABSOLUTE 7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HID_REPORTID_NKRO_KEYBOARD
|
||||||
|
#define HID_REPORTID_NKRO_KEYBOARD 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Nico has submitted these definitions upstream, but they're not merged yet
|
||||||
|
// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request
|
||||||
|
#define HID_REPORT_TYPE_INPUT 1
|
||||||
|
#define HID_REPORT_TYPE_OUTPUT 2
|
||||||
|
#define HID_REPORT_TYPE_FEATURE 3
|
||||||
|
|
||||||
|
// Controls whether to pack messages or not. When set, any sends will be delayed
|
||||||
|
// until packing is toggled off, and sent then. This is a no-op on AVR, but is
|
||||||
|
// required for SAMD. We place a forward-declaration here to be able to avoid
|
||||||
|
// architecture-specific ifdefs elsewhere in the code.
|
||||||
|
void USB_PackMessages(bool pack);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_AVR)
|
||||||
|
|
||||||
|
#include "PluggableUSB.h"
|
||||||
|
|
||||||
|
#define EPTYPE_DESCRIPTOR_SIZE uint8_t
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_SAM)
|
||||||
|
|
||||||
|
#include "USB/PluggableUSB.h"
|
||||||
|
|
||||||
|
#define EPTYPE_DESCRIPTOR_SIZE uint32_t
|
||||||
|
#define EP_TYPE_INTERRUPT_IN (UOTGHS_DEVEPTCFG_EPSIZE_512_BYTE | \
|
||||||
|
UOTGHS_DEVEPTCFG_EPDIR_IN | \
|
||||||
|
UOTGHS_DEVEPTCFG_EPTYPE_BLK | \
|
||||||
|
UOTGHS_DEVEPTCFG_EPBK_1_BANK | \
|
||||||
|
UOTGHS_DEVEPTCFG_NBTRANS_1_TRANS | \
|
||||||
|
UOTGHS_DEVEPTCFG_ALLOC)
|
||||||
|
#define EP_TYPE_INTERRUPT_OUT (UOTGHS_DEVEPTCFG_EPSIZE_512_BYTE | \
|
||||||
|
UOTGHS_DEVEPTCFG_EPTYPE_BLK | \
|
||||||
|
UOTGHS_DEVEPTCFG_EPBK_1_BANK | \
|
||||||
|
UOTGHS_DEVEPTCFG_NBTRANS_1_TRANS | \
|
||||||
|
UOTGHS_DEVEPTCFG_ALLOC)
|
||||||
|
#define USB_EP_SIZE EPX_SIZE
|
||||||
|
#define USB_SendControl USBD_SendControl
|
||||||
|
#define USB_Available USBD_Available
|
||||||
|
#define USB_Recv USBD_Recv
|
||||||
|
#define USB_Send USBD_Send
|
||||||
|
#define USB_Flush USBD_Flush
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_SAMD)
|
||||||
|
|
||||||
|
#include "USB/PluggableUSB.h"
|
||||||
|
|
||||||
|
#define EPTYPE_DESCRIPTOR_SIZE uint32_t
|
||||||
|
#define EP_TYPE_INTERRUPT_IN USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0);
|
||||||
|
#define EP_TYPE_INTERRUPT_OUT USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_OUT(0);
|
||||||
|
#define USB_EP_SIZE EPX_SIZE
|
||||||
|
//#define USB_SendControl USBDevice.sendControl -> real C++ functions to take care of PGM overloading
|
||||||
|
#define USB_Available USBDevice.available
|
||||||
|
#define USB_Recv USBDevice.recv
|
||||||
|
#define USB_RecvControl USBDevice.recvControl
|
||||||
|
#define USB_Send USBDevice.send
|
||||||
|
#define USB_Flush USBDevice.flush
|
||||||
|
|
||||||
|
int USB_SendControl(void* y, uint8_t z);
|
||||||
|
int USB_SendControl(uint8_t x, const void* y, uint8_t z);
|
||||||
|
|
||||||
|
#define TRANSFER_PGM 0
|
||||||
|
#define TRANSFER_RELEASE 0
|
||||||
|
|
||||||
|
#define HID_REPORT_TYPE_INPUT 1
|
||||||
|
#define HID_REPORT_TYPE_OUTPUT 2
|
||||||
|
#define HID_REPORT_TYPE_FEATURE 3
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "Unsupported architecture"
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "kaleidoscope/HIDTables.h"
|
||||||
|
|
||||||
|
#define HID_FIRST_KEY HID_KEYBOARD_NO_EVENT
|
||||||
|
#define HID_LAST_KEY HID_KEYPAD_HEXADECIMAL
|
||||||
|
#define HID_KEYBOARD_FIRST_MODIFIER HID_KEYBOARD_LEFT_CONTROL
|
||||||
|
#define HID_KEYBOARD_LAST_MODIFIER HID_KEYBOARD_RIGHT_GUI
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2015-2019 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HIDReportObserver.h"
|
||||||
|
|
||||||
|
HIDReportObserver::SendReportHook HIDReportObserver::send_report_hook_ = nullptr;
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2015-2019 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class HIDReportObserver {
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef void(*SendReportHook)(uint8_t id, const void* data,
|
||||||
|
int len, int result);
|
||||||
|
|
||||||
|
static void observeReport(uint8_t id, const void* data,
|
||||||
|
int len, int result) {
|
||||||
|
if (send_report_hook_) {
|
||||||
|
(*send_report_hook_)(id, data, len, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SendReportHook currentHook() {
|
||||||
|
return send_report_hook_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SendReportHook resetHook(SendReportHook new_hook) {
|
||||||
|
auto previous_hook = send_report_hook_;
|
||||||
|
send_report_hook_ = new_hook;
|
||||||
|
return previous_hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static SendReportHook send_report_hook_;
|
||||||
|
};
|
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2015, Arduino LLC
|
||||||
|
Original code (pre-library): Copyright (c) 2011, Peter Barrett
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
above copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||||
|
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||||
|
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEYBOARDIOHID_BUILD_WITHOUT_HID
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HIDReportObserver.h"
|
||||||
|
|
||||||
|
#if defined(USBCON)
|
||||||
|
|
||||||
|
HID_& HID() {
|
||||||
|
static HID_ obj;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_::getInterface(uint8_t* interfaceCount) {
|
||||||
|
*interfaceCount += 1; // uses 1
|
||||||
|
HIDDescriptor hidInterface = {
|
||||||
|
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
|
||||||
|
D_HIDREPORT(descriptorSize),
|
||||||
|
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01)
|
||||||
|
};
|
||||||
|
return USB_SendControl(0, &hidInterface, sizeof(hidInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_::getDescriptor(USBSetup& setup) {
|
||||||
|
// Check if this is a HID Class Descriptor request
|
||||||
|
if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a HID Class Descriptor wIndex cointains the interface number
|
||||||
|
if (setup.wIndex != pluggedInterface) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
HIDSubDescriptor* node;
|
||||||
|
USB_PackMessages(true);
|
||||||
|
for (node = rootNode; node; node = node->next) {
|
||||||
|
int res = USB_SendControl(TRANSFER_PGM, node->data, node->length);
|
||||||
|
if (res == -1)
|
||||||
|
return -1;
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol
|
||||||
|
// due to the USB specs, but Windows and Linux just assumes its in report mode.
|
||||||
|
protocol = HID_REPORT_PROTOCOL;
|
||||||
|
|
||||||
|
USB_PackMessages(false);
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
uint8_t HID_::getShortName(char *name) {
|
||||||
|
name[0] = 'k';
|
||||||
|
name[1] = 'b';
|
||||||
|
name[2] = 'i';
|
||||||
|
name[3] = 'o';
|
||||||
|
name[4] = '0';
|
||||||
|
name[5] = '1';
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HID_::AppendDescriptor(HIDSubDescriptor *node) {
|
||||||
|
if (!rootNode) {
|
||||||
|
rootNode = node;
|
||||||
|
} else {
|
||||||
|
HIDSubDescriptor *current = rootNode;
|
||||||
|
while (current->next) {
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
current->next = node;
|
||||||
|
}
|
||||||
|
descriptorSize += node->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_::SendReport(uint8_t id, const void* data, int len) {
|
||||||
|
auto result = SendReport_(id, data, len);
|
||||||
|
HIDReportObserver::observeReport(id, data, len, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_::SendReport_(uint8_t id, const void* data, int len) {
|
||||||
|
/* On SAMD, we need to send the whole report in one batch; sending the id, and
|
||||||
|
* the report itself separately does not work, the report never arrives. Due
|
||||||
|
* to this, we merge the two into a single buffer, and send that.
|
||||||
|
*
|
||||||
|
* While the same would work for other architectures, AVR included, doing so
|
||||||
|
* costs RAM, which is something scarce on AVR. So on that platform, we opt to
|
||||||
|
* send the id and the report separately instead. */
|
||||||
|
#ifdef ARDUINO_ARCH_SAMD
|
||||||
|
uint8_t p[64];
|
||||||
|
p[0] = id;
|
||||||
|
memcpy(&p[1], data, len);
|
||||||
|
return USB_Send(pluggedEndpoint, p, len + 1);
|
||||||
|
#else
|
||||||
|
auto ret = USB_Send(pluggedEndpoint, &id, 1);
|
||||||
|
if (ret < 0) return ret;
|
||||||
|
auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len);
|
||||||
|
if (ret2 < 0) return ret2;
|
||||||
|
return ret + ret2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HID_::setup(USBSetup& setup) {
|
||||||
|
if (pluggedInterface != setup.wIndex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t request = setup.bRequest;
|
||||||
|
uint8_t requestType = setup.bmRequestType;
|
||||||
|
|
||||||
|
if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) {
|
||||||
|
if (request == HID_GET_REPORT) {
|
||||||
|
// TODO(anyone): HID_GetReport();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_GET_PROTOCOL) {
|
||||||
|
// TODO(anyone): Send8(protocol);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_GET_IDLE) {
|
||||||
|
// TODO(anyone): Send8(idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) {
|
||||||
|
if (request == HID_SET_PROTOCOL) {
|
||||||
|
// The USB Host tells us if we are in boot or report mode.
|
||||||
|
// This only works with a real boot compatible device.
|
||||||
|
protocol = setup.wValueL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_SET_IDLE) {
|
||||||
|
idle = setup.wValueL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_SET_REPORT) {
|
||||||
|
uint16_t length = setup.wLength;
|
||||||
|
|
||||||
|
if (length == sizeof(setReportData)) {
|
||||||
|
USB_RecvControl(&setReportData, length);
|
||||||
|
} else if (length == sizeof(setReportData.leds)) {
|
||||||
|
USB_RecvControl(&setReportData.leds, length);
|
||||||
|
setReportData.reportId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HID_::HID_(void) : PluggableUSBModule(1, 1, epType),
|
||||||
|
rootNode(NULL), descriptorSize(0),
|
||||||
|
protocol(HID_REPORT_PROTOCOL), idle(1) {
|
||||||
|
setReportData.reportId = 0;
|
||||||
|
setReportData.leds = 0;
|
||||||
|
epType[0] = EP_TYPE_INTERRUPT_IN;
|
||||||
|
PluggableUSB().plug(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HID_::begin(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* if defined(USBCON) */
|
||||||
|
|
||||||
|
#endif /* ifndef KEYBOARDIOHID_BUILD_WITHOUT_HID */
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2015, Arduino LLC
|
||||||
|
Original code (pre-library): Copyright (c) 2011, Peter Barrett
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
above copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||||
|
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||||
|
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
|
||||||
|
#if defined(USBCON)
|
||||||
|
|
||||||
|
#define _USING_HID
|
||||||
|
|
||||||
|
// HID 'Driver'
|
||||||
|
// ------------
|
||||||
|
#define HID_GET_REPORT 0x01
|
||||||
|
#define HID_GET_IDLE 0x02
|
||||||
|
#define HID_GET_PROTOCOL 0x03
|
||||||
|
#define HID_SET_REPORT 0x09
|
||||||
|
#define HID_SET_IDLE 0x0A
|
||||||
|
#define HID_SET_PROTOCOL 0x0B
|
||||||
|
|
||||||
|
#define HID_HID_DESCRIPTOR_TYPE 0x21
|
||||||
|
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
|
||||||
|
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
|
||||||
|
|
||||||
|
// HID subclass HID1.11 Page 8 4.2 Subclass
|
||||||
|
#define HID_SUBCLASS_NONE 0
|
||||||
|
#define HID_SUBCLASS_BOOT_INTERFACE 1
|
||||||
|
|
||||||
|
// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols
|
||||||
|
#define HID_PROTOCOL_NONE 0
|
||||||
|
#define HID_PROTOCOL_KEYBOARD 1
|
||||||
|
#define HID_PROTOCOL_MOUSE 2
|
||||||
|
|
||||||
|
// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request
|
||||||
|
// "protocol" variable is used for this purpose.
|
||||||
|
#define HID_BOOT_PROTOCOL 0
|
||||||
|
#define HID_REPORT_PROTOCOL 1
|
||||||
|
|
||||||
|
// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request
|
||||||
|
#define HID_REPORT_TYPE_INPUT 1
|
||||||
|
#define HID_REPORT_TYPE_OUTPUT 2
|
||||||
|
#define HID_REPORT_TYPE_FEATURE 3
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t len; // 9
|
||||||
|
uint8_t dtype; // 0x21
|
||||||
|
uint8_t addr;
|
||||||
|
uint8_t versionL; // 0x101
|
||||||
|
uint8_t versionH; // 0x101
|
||||||
|
uint8_t country;
|
||||||
|
uint8_t desctype; // 0x22 report
|
||||||
|
uint8_t descLenL;
|
||||||
|
uint8_t descLenH;
|
||||||
|
} HIDDescDescriptor;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
InterfaceDescriptor hid;
|
||||||
|
HIDDescDescriptor desc;
|
||||||
|
EndpointDescriptor in;
|
||||||
|
} HIDDescriptor;
|
||||||
|
|
||||||
|
class HIDSubDescriptor {
|
||||||
|
public:
|
||||||
|
HIDSubDescriptor *next = NULL;
|
||||||
|
HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { }
|
||||||
|
|
||||||
|
const void* data;
|
||||||
|
const uint16_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HID_ : public PluggableUSBModule {
|
||||||
|
public:
|
||||||
|
|
||||||
|
HID_(void);
|
||||||
|
int begin(void);
|
||||||
|
int SendReport(uint8_t id, const void* data, int len);
|
||||||
|
void AppendDescriptor(HIDSubDescriptor* node);
|
||||||
|
uint8_t getLEDs(void) {
|
||||||
|
return setReportData.leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Implementation of the PluggableUSBModule
|
||||||
|
int getInterface(uint8_t* interfaceCount);
|
||||||
|
int getDescriptor(USBSetup& setup);
|
||||||
|
bool setup(USBSetup& setup);
|
||||||
|
uint8_t getShortName(char* name);
|
||||||
|
|
||||||
|
int SendReport_(uint8_t id, const void* data, int len);
|
||||||
|
private:
|
||||||
|
EPTYPE_DESCRIPTOR_SIZE epType[1];
|
||||||
|
|
||||||
|
HIDSubDescriptor* rootNode;
|
||||||
|
uint16_t descriptorSize;
|
||||||
|
|
||||||
|
uint8_t protocol;
|
||||||
|
uint8_t idle;
|
||||||
|
struct {
|
||||||
|
uint8_t reportId;
|
||||||
|
uint8_t leds;
|
||||||
|
} setReportData;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Replacement for global singleton.
|
||||||
|
// This function prevents static-initialization-order-fiasco
|
||||||
|
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
|
||||||
|
HID_& HID();
|
||||||
|
|
||||||
|
#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) }
|
||||||
|
|
||||||
|
#endif // USBCON
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define MOUSE_LEFT (1 << 0)
|
||||||
|
#define MOUSE_RIGHT (1 << 1)
|
||||||
|
#define MOUSE_MIDDLE (1 << 2)
|
||||||
|
#define MOUSE_PREV (1 << 3)
|
||||||
|
#define MOUSE_NEXT (1 << 4)
|
||||||
|
// actually this mouse report has 8 buttons (for smaller descriptor)
|
||||||
|
// but the last 3 wont do anything from what I tested
|
||||||
|
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_PREV | MOUSE_NEXT)
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/MultiReport/AbsoluteMouse.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidMultiReportDescriptorAbsoluteMouse[] PROGMEM = {
|
||||||
|
/* Mouse absolute */
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) 54 */
|
||||||
|
D_USAGE, D_USAGE_MOUSE, /* USAGE (Mouse) */
|
||||||
|
D_COLLECTION, D_APPLICATION, /* COLLECTION (Application) */
|
||||||
|
D_REPORT_ID, HID_REPORTID_MOUSE_ABSOLUTE, /* REPORT_ID */
|
||||||
|
|
||||||
|
DESCRIPTOR_ABS_MOUSE_BUTTONS
|
||||||
|
DESCRIPTOR_ABS_MOUSE_XY
|
||||||
|
DESCRIPTOR_ABS_MOUSE_WHEEL
|
||||||
|
|
||||||
|
D_END_COLLECTION /* End */
|
||||||
|
};
|
||||||
|
|
||||||
|
AbsoluteMouse_::AbsoluteMouse_(void) {
|
||||||
|
static HIDSubDescriptor node(_hidMultiReportDescriptorAbsoluteMouse, sizeof(_hidMultiReportDescriptorAbsoluteMouse));
|
||||||
|
HID().AppendDescriptor(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbsoluteMouse_::sendReport(void* data, int length) {
|
||||||
|
HID().SendReport(HID_REPORTID_MOUSE_ABSOLUTE, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbsoluteMouse_ AbsoluteMouse;
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DeviceAPIs/AbsoluteMouseAPI.h"
|
||||||
|
|
||||||
|
class AbsoluteMouse_ : public AbsoluteMouseAPI {
|
||||||
|
public:
|
||||||
|
AbsoluteMouse_(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Sending is public in the base class for advanced users.
|
||||||
|
virtual void sendReport(void* data, int length);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern AbsoluteMouse_ AbsoluteMouse;
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/MultiReport/ConsumerControl.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidMultiReportDescriptorConsumer[] PROGMEM = {
|
||||||
|
/* Consumer Control (Sound/Media keys) */
|
||||||
|
D_USAGE_PAGE, 0x0C, /* usage page (consumer device) */
|
||||||
|
D_USAGE, 0x01, /* usage -- consumer control */
|
||||||
|
D_COLLECTION, D_APPLICATION, /* collection (application) */
|
||||||
|
D_REPORT_ID, HID_REPORTID_CONSUMERCONTROL, /* report id */
|
||||||
|
/* 4 Media Keys */
|
||||||
|
D_LOGICAL_MINIMUM, 0x00, /* logical minimum */
|
||||||
|
D_MULTIBYTE(D_LOGICAL_MAXIMUM), 0xFF, 0x03, /* logical maximum (3ff) */
|
||||||
|
D_USAGE_MINIMUM, 0x00, /* usage minimum (0) */
|
||||||
|
D_MULTIBYTE(D_USAGE_MAXIMUM), 0xFF, 0x03, /* usage maximum (3ff) */
|
||||||
|
D_REPORT_COUNT, 0x04, /* report count (4) */
|
||||||
|
D_REPORT_SIZE, 0x10, /* report size (16) */
|
||||||
|
D_INPUT, 0x00, /* input */
|
||||||
|
D_END_COLLECTION /* end collection */
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsumerControl_::ConsumerControl_(void) {
|
||||||
|
static HIDSubDescriptor node(_hidMultiReportDescriptorConsumer, sizeof(_hidMultiReportDescriptorConsumer));
|
||||||
|
HID().AppendDescriptor(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::begin(void) {
|
||||||
|
// release all buttons
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::end(void) {
|
||||||
|
memset(&_report, 0, sizeof(_report));
|
||||||
|
sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::write(uint16_t m) {
|
||||||
|
press(m);
|
||||||
|
release(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::press(uint16_t m) {
|
||||||
|
// search for a free spot
|
||||||
|
for (uint8_t i = 0; i < sizeof(HID_ConsumerControlReport_Data_t) / 2; i++) {
|
||||||
|
if (_report.keys[i] == 0x00) {
|
||||||
|
_report.keys[i] = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::release(uint16_t m) {
|
||||||
|
// search and release the keypress
|
||||||
|
for (uint8_t i = 0; i < sizeof(HID_ConsumerControlReport_Data_t) / 2; i++) {
|
||||||
|
if (_report.keys[i] == m) {
|
||||||
|
_report.keys[i] = 0x00;
|
||||||
|
// no break to delete multiple keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::releaseAll(void) {
|
||||||
|
memset(&_report, 0, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::sendReportUnchecked(void) {
|
||||||
|
HID().SendReport(HID_REPORTID_CONSUMERCONTROL, &_report, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumerControl_::sendReport(void) {
|
||||||
|
// If the last report is different than the current report, then we need to send a report.
|
||||||
|
// We guard sendReport like this so that calling code doesn't end up spamming the host with empty reports
|
||||||
|
// if sendReport is called in a tight loop.
|
||||||
|
|
||||||
|
// if the previous report is the same, return early without a new report.
|
||||||
|
if (memcmp(&_lastReport, &_report, sizeof(_report)) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sendReportUnchecked();
|
||||||
|
memcpy(&_lastReport, &_report, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsumerControl_ ConsumerControl;
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// Every usable Consumer key possible, up to 4 keys presses possible
|
||||||
|
uint16_t keys[4];
|
||||||
|
struct {
|
||||||
|
uint16_t key1;
|
||||||
|
uint16_t key2;
|
||||||
|
uint16_t key3;
|
||||||
|
uint16_t key4;
|
||||||
|
};
|
||||||
|
} HID_ConsumerControlReport_Data_t;
|
||||||
|
|
||||||
|
|
||||||
|
class ConsumerControl_ {
|
||||||
|
public:
|
||||||
|
ConsumerControl_(void);
|
||||||
|
void begin(void);
|
||||||
|
void end(void);
|
||||||
|
void write(uint16_t m);
|
||||||
|
void press(uint16_t m);
|
||||||
|
void release(uint16_t m);
|
||||||
|
void releaseAll(void);
|
||||||
|
|
||||||
|
// Sending is public in the base class for advanced users.
|
||||||
|
void sendReport(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HID_ConsumerControlReport_Data_t _report;
|
||||||
|
HID_ConsumerControlReport_Data_t _lastReport;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendReportUnchecked(void);
|
||||||
|
};
|
||||||
|
extern ConsumerControl_ ConsumerControl;
|
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/MultiReport/Gamepad.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidMultiReportDescriptorGamepad[] PROGMEM = {
|
||||||
|
/* Gamepad with 32 buttons and 6 axis*/
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) */
|
||||||
|
D_USAGE, D_USAGE_JOYSTICK, /* USAGE (Joystick) */
|
||||||
|
D_COLLECTION, D_APPLICATION, /* COLLECTION (Application) */
|
||||||
|
D_REPORT_ID, HID_REPORTID_GAMEPAD, /* REPORT_ID */
|
||||||
|
/* 32 Buttons */
|
||||||
|
D_USAGE_PAGE, D_PAGE_BUTTON, /* USAGE_PAGE (Button) */
|
||||||
|
D_USAGE_MINIMUM, 0x01, /* USAGE_MINIMUM (Button 1) */
|
||||||
|
D_USAGE_MAXIMUM, 0x20, /* USAGE_MAXIMUM (Button 32) */
|
||||||
|
D_LOGICAL_MINIMUM, 0x00, /* _LOGICAL_MINIMUM (0) */
|
||||||
|
D_LOGICAL_MAXIMUM, 0x01, /* _LOGICAL_MAXIMUM (1) */
|
||||||
|
D_REPORT_SIZE, 0x01, /* REPORT_SIZE (1) */
|
||||||
|
D_REPORT_COUNT, 0x20, /* REPORT_COUNT (32) */
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE), /* INPUT (Data,Var,Abs) */
|
||||||
|
/* 4 16bit Axis */
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) */
|
||||||
|
D_COLLECTION, D_PHYSICAL, /* COLLECTION (Physical) */
|
||||||
|
D_USAGE, 0x30, /* USAGE (X) */
|
||||||
|
D_USAGE, 0x31, /* USAGE (Y) */
|
||||||
|
D_USAGE, 0x33, /* USAGE (Rx) */
|
||||||
|
D_USAGE, 0x34, /* USAGE (Ry) */
|
||||||
|
D_MULTIBYTE(D_LOGICAL_MINIMUM), 0x00, 0x80, /* _LOGICAL_MINIMUM (-32768) */
|
||||||
|
D_MULTIBYTE(D_LOGICAL_MAXIMUM), 0xFF, 0x7F, /* _LOGICAL_MAXIMUM (32767) */
|
||||||
|
D_REPORT_SIZE, 0x10, /* REPORT_SIZE (16) */
|
||||||
|
D_REPORT_COUNT, 0x04, /* REPORT_COUNT (4) */
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE), /* INPUT (Data,Var,Abs) */
|
||||||
|
/* 2 8bit Axis */
|
||||||
|
D_USAGE, 0x32, /* USAGE (Z) */
|
||||||
|
D_USAGE, 0x35, /* USAGE (Rz) */
|
||||||
|
D_LOGICAL_MINIMUM, 0x80, /* _LOGICAL_MINIMUM (-128) */
|
||||||
|
D_LOGICAL_MAXIMUM, 0x7F, /* _LOGICAL_MAXIMUM (127) */
|
||||||
|
D_REPORT_SIZE, 0x08, /* REPORT_SIZE (8) */
|
||||||
|
D_REPORT_COUNT, 0x02, /* REPORT_COUNT (2) */
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE), /* INPUT (Data,Var,Abs) */
|
||||||
|
D_END_COLLECTION, /* END_COLLECTION */
|
||||||
|
|
||||||
|
/* 2 Hat Switches */
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) */
|
||||||
|
D_USAGE, 0x39, /* USAGE (Hat switch) */
|
||||||
|
D_USAGE, 0x39, /* USAGE (Hat switch) */
|
||||||
|
D_LOGICAL_MINIMUM, 0x01, /* _LOGICAL_MINIMUM (1) */
|
||||||
|
D_LOGICAL_MAXIMUM, 0x08, /* _LOGICAL_MAXIMUM (8) */
|
||||||
|
D_REPORT_COUNT, 0x02, /* REPORT_COUNT (2) */
|
||||||
|
D_REPORT_SIZE, 0x04, /* REPORT_SIZE (4) */
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE), /* INPUT (Data,Var,Abs) */
|
||||||
|
D_END_COLLECTION /* END_COLLECTION */
|
||||||
|
};
|
||||||
|
|
||||||
|
Gamepad_::Gamepad_(void) {
|
||||||
|
static HIDSubDescriptor node(_hidMultiReportDescriptorGamepad, sizeof(_hidMultiReportDescriptorGamepad));
|
||||||
|
HID().AppendDescriptor(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::begin(void) {
|
||||||
|
// release all buttons
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gamepad_::end(void) {
|
||||||
|
memset(&_report, 0x00, sizeof(_report));
|
||||||
|
sendReport(&_report, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gamepad_::write(void) {
|
||||||
|
sendReport(&_report, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::press(uint8_t b) {
|
||||||
|
_report.buttons |= (uint32_t)1 << (b - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::release(uint8_t b) {
|
||||||
|
_report.buttons &= ~((uint32_t)1 << (b - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::releaseAll(void) {
|
||||||
|
memset(&_report, 0x00, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gamepad_::buttons(uint32_t b) {
|
||||||
|
_report.buttons = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::xAxis(int16_t a) {
|
||||||
|
_report.xAxis = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::yAxis(int16_t a) {
|
||||||
|
_report.yAxis = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::zAxis(int8_t a) {
|
||||||
|
_report.zAxis = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::rxAxis(int16_t a) {
|
||||||
|
_report.rxAxis = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::ryAxis(int16_t a) {
|
||||||
|
_report.ryAxis = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::rzAxis(int8_t a) {
|
||||||
|
_report.rzAxis = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::dPad1(int8_t d) {
|
||||||
|
_report.dPad1 = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::dPad2(int8_t d) {
|
||||||
|
_report.dPad2 = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Gamepad_::sendReport(void* data, int length) {
|
||||||
|
HID().SendReport(HID_REPORTID_GAMEPAD, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gamepad_ Gamepad;
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
|
||||||
|
// Dpad directions
|
||||||
|
#define GAMEPAD_DPAD_CENTERED 0
|
||||||
|
#define GAMEPAD_DPAD_UP 1
|
||||||
|
#define GAMEPAD_DPAD_UP_RIGHT 2
|
||||||
|
#define GAMEPAD_DPAD_RIGHT 3
|
||||||
|
#define GAMEPAD_DPAD_DOWN_RIGHT 4
|
||||||
|
#define GAMEPAD_DPAD_DOWN 5
|
||||||
|
#define GAMEPAD_DPAD_DOWN_LEFT 6
|
||||||
|
#define GAMEPAD_DPAD_LEFT 7
|
||||||
|
#define GAMEPAD_DPAD_UP_LEFT 8
|
||||||
|
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// 32 Buttons, 6 Axis, 2 D-Pads
|
||||||
|
uint32_t buttons;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t button1 : 1;
|
||||||
|
uint8_t button2 : 1;
|
||||||
|
uint8_t button3 : 1;
|
||||||
|
uint8_t button4 : 1;
|
||||||
|
uint8_t button5 : 1;
|
||||||
|
uint8_t button6 : 1;
|
||||||
|
uint8_t button7 : 1;
|
||||||
|
uint8_t button8 : 1;
|
||||||
|
|
||||||
|
uint8_t button9 : 1;
|
||||||
|
uint8_t button10 : 1;
|
||||||
|
uint8_t button11 : 1;
|
||||||
|
uint8_t button12 : 1;
|
||||||
|
uint8_t button13 : 1;
|
||||||
|
uint8_t button14 : 1;
|
||||||
|
uint8_t button15 : 1;
|
||||||
|
uint8_t button16 : 1;
|
||||||
|
|
||||||
|
uint8_t button17 : 1;
|
||||||
|
uint8_t button18 : 1;
|
||||||
|
uint8_t button19 : 1;
|
||||||
|
uint8_t button20 : 1;
|
||||||
|
uint8_t button21 : 1;
|
||||||
|
uint8_t button22 : 1;
|
||||||
|
uint8_t button23 : 1;
|
||||||
|
uint8_t button24 : 1;
|
||||||
|
|
||||||
|
uint8_t button25 : 1;
|
||||||
|
uint8_t button26 : 1;
|
||||||
|
uint8_t button27 : 1;
|
||||||
|
uint8_t button28 : 1;
|
||||||
|
uint8_t button29 : 1;
|
||||||
|
uint8_t button30 : 1;
|
||||||
|
uint8_t button31 : 1;
|
||||||
|
uint8_t button32 : 1;
|
||||||
|
|
||||||
|
int16_t xAxis;
|
||||||
|
int16_t yAxis;
|
||||||
|
|
||||||
|
int16_t rxAxis;
|
||||||
|
int16_t ryAxis;
|
||||||
|
|
||||||
|
int8_t zAxis;
|
||||||
|
int8_t rzAxis;
|
||||||
|
|
||||||
|
uint8_t dPad1 : 4;
|
||||||
|
uint8_t dPad2 : 4;
|
||||||
|
};
|
||||||
|
} HID_GamepadReport_Data_t;
|
||||||
|
|
||||||
|
class Gamepad_ {
|
||||||
|
public:
|
||||||
|
Gamepad_(void);
|
||||||
|
|
||||||
|
void begin(void);
|
||||||
|
void end(void);
|
||||||
|
void write(void);
|
||||||
|
void press(uint8_t b);
|
||||||
|
void release(uint8_t b);
|
||||||
|
void releaseAll(void);
|
||||||
|
|
||||||
|
void buttons(uint32_t b);
|
||||||
|
void xAxis(int16_t a);
|
||||||
|
void yAxis(int16_t a);
|
||||||
|
void zAxis(int8_t a);
|
||||||
|
void rxAxis(int16_t a);
|
||||||
|
void ryAxis(int16_t a);
|
||||||
|
void rzAxis(int8_t a);
|
||||||
|
void dPad1(int8_t d);
|
||||||
|
void dPad2(int8_t d);
|
||||||
|
|
||||||
|
void sendReport(void* data, int length);
|
||||||
|
protected:
|
||||||
|
HID_GamepadReport_Data_t _report;
|
||||||
|
};
|
||||||
|
extern Gamepad_ Gamepad;
|
@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/MultiReport/Keyboard.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidMultiReportDescriptorKeyboard[] PROGMEM = {
|
||||||
|
// NKRO Keyboard
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP,
|
||||||
|
D_USAGE, D_USAGE_KEYBOARD,
|
||||||
|
D_COLLECTION, D_APPLICATION,
|
||||||
|
D_REPORT_ID, HID_REPORTID_NKRO_KEYBOARD,
|
||||||
|
D_USAGE_PAGE, D_PAGE_KEYBOARD,
|
||||||
|
|
||||||
|
|
||||||
|
/* Key modifier byte */
|
||||||
|
D_USAGE_MINIMUM, HID_KEYBOARD_FIRST_MODIFIER,
|
||||||
|
D_USAGE_MAXIMUM, HID_KEYBOARD_LAST_MODIFIER,
|
||||||
|
D_LOGICAL_MINIMUM, 0x00,
|
||||||
|
D_LOGICAL_MAXIMUM, 0x01,
|
||||||
|
D_REPORT_SIZE, 0x01,
|
||||||
|
D_REPORT_COUNT, 0x08,
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE),
|
||||||
|
|
||||||
|
|
||||||
|
/* 5 LEDs for num lock etc, 3 left for advanced, custom usage */
|
||||||
|
D_USAGE_PAGE, D_PAGE_LEDS,
|
||||||
|
D_USAGE_MINIMUM, 0x01,
|
||||||
|
D_USAGE_MAXIMUM, 0x08,
|
||||||
|
D_REPORT_COUNT, 0x08,
|
||||||
|
D_REPORT_SIZE, 0x01,
|
||||||
|
D_OUTPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE),
|
||||||
|
|
||||||
|
/* NKRO Keyboard */
|
||||||
|
D_USAGE_PAGE, D_PAGE_KEYBOARD,
|
||||||
|
|
||||||
|
// Padding 4 bits, to skip NO_EVENT & 3 error states.
|
||||||
|
D_REPORT_SIZE, 0x04,
|
||||||
|
D_REPORT_COUNT, 0x01,
|
||||||
|
D_INPUT, (D_CONSTANT),
|
||||||
|
|
||||||
|
D_USAGE_MINIMUM, HID_KEYBOARD_A_AND_A,
|
||||||
|
D_USAGE_MAXIMUM, HID_LAST_KEY,
|
||||||
|
D_LOGICAL_MINIMUM, 0x00,
|
||||||
|
D_LOGICAL_MAXIMUM, 0x01,
|
||||||
|
D_REPORT_SIZE, 0x01,
|
||||||
|
D_REPORT_COUNT, (HID_LAST_KEY - HID_KEYBOARD_A_AND_A),
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE),
|
||||||
|
|
||||||
|
// Padding (3 bits) to round up the report to byte boundary.
|
||||||
|
D_REPORT_SIZE, 0x03,
|
||||||
|
D_REPORT_COUNT, 0x01,
|
||||||
|
D_INPUT, (D_CONSTANT),
|
||||||
|
|
||||||
|
D_END_COLLECTION,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Keyboard_::Keyboard_(void) {
|
||||||
|
static HIDSubDescriptor node(_hidMultiReportDescriptorKeyboard, sizeof(_hidMultiReportDescriptorKeyboard));
|
||||||
|
HID().AppendDescriptor(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Keyboard_::begin(void) {
|
||||||
|
// Force API to send a clean report.
|
||||||
|
// This is important for and HID bridge where the receiver stays on,
|
||||||
|
// while the sender is resetted.
|
||||||
|
releaseAll();
|
||||||
|
sendReportUnchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Keyboard_::end(void) {
|
||||||
|
releaseAll();
|
||||||
|
sendReportUnchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Keyboard_::sendReportUnchecked(void) {
|
||||||
|
return HID().SendReport(HID_REPORTID_NKRO_KEYBOARD, &keyReport, sizeof(keyReport));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Keyboard_::sendReport(void) {
|
||||||
|
// If the last report is different than the current report, then we need to send a report.
|
||||||
|
// We guard sendReport like this so that calling code doesn't end up spamming the host with empty reports
|
||||||
|
// if sendReport is called in a tight loop.
|
||||||
|
|
||||||
|
if (memcmp(lastKeyReport.allkeys, keyReport.allkeys, sizeof(keyReport))) {
|
||||||
|
// if the two reports are different, send a report
|
||||||
|
|
||||||
|
// ChromeOS 51-60 (at least) bug: if a modifier and a normal keycode are added in the
|
||||||
|
// same report, in some cases the shift is not applied (e.g. `shift`+`[` doesn't yield
|
||||||
|
// `{`). To compensate for this, check to see if the modifier byte has changed.
|
||||||
|
|
||||||
|
|
||||||
|
// If modifiers are being turned on at the same time as any change
|
||||||
|
// to the non-modifier keys in the report, then we send the previous
|
||||||
|
// report with the new modifiers
|
||||||
|
if (((lastKeyReport.modifiers ^ keyReport.modifiers) & keyReport.modifiers)
|
||||||
|
&& (memcmp(lastKeyReport.keys, keyReport.keys, sizeof(keyReport.keys)))) {
|
||||||
|
uint8_t last_mods = lastKeyReport.modifiers;
|
||||||
|
lastKeyReport.modifiers = keyReport.modifiers;
|
||||||
|
int returnCode = HID().SendReport(HID_REPORTID_NKRO_KEYBOARD, &lastKeyReport, sizeof(lastKeyReport));
|
||||||
|
lastKeyReport.modifiers = last_mods;
|
||||||
|
} else {
|
||||||
|
// If modifiers are being turned off, then we send the new report with the previous modifiers.
|
||||||
|
// We need to do this, at least on Linux 4.17 + Wayland.
|
||||||
|
// Jesse has observed that sending Shift + 3 key up events in the same report
|
||||||
|
// will sometimes result in a spurious '3' rather than '#', especially when the keys
|
||||||
|
// had been held for a while
|
||||||
|
|
||||||
|
if (((lastKeyReport.modifiers ^ keyReport.modifiers) & lastKeyReport.modifiers)
|
||||||
|
&& (memcmp(lastKeyReport.keys, keyReport.keys, sizeof(keyReport.keys)))) {
|
||||||
|
uint8_t mods = keyReport.modifiers;
|
||||||
|
keyReport.modifiers = lastKeyReport.modifiers;
|
||||||
|
int returnCode = HID().SendReport(HID_REPORTID_NKRO_KEYBOARD, &keyReport, sizeof(lastKeyReport));
|
||||||
|
keyReport.modifiers = mods;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int returnCode = sendReportUnchecked();
|
||||||
|
if (returnCode > 0)
|
||||||
|
memcpy(lastKeyReport.allkeys, keyReport.allkeys, sizeof(keyReport));
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the modifer key passed in will be sent during this key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean Keyboard_::isModifierActive(uint8_t k) {
|
||||||
|
if (k >= HID_KEYBOARD_FIRST_MODIFIER && k <= HID_KEYBOARD_LAST_MODIFIER) {
|
||||||
|
k = k - HID_KEYBOARD_FIRST_MODIFIER;
|
||||||
|
return !!(keyReport.modifiers & (1 << k));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the modifer key passed in was being sent during the previous key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean Keyboard_::wasModifierActive(uint8_t k) {
|
||||||
|
if (k >= HID_KEYBOARD_FIRST_MODIFIER && k <= HID_KEYBOARD_LAST_MODIFIER) {
|
||||||
|
k = k - HID_KEYBOARD_FIRST_MODIFIER;
|
||||||
|
return !!(lastKeyReport.modifiers & (1 << k));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if *any* modifier will be sent during this key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean Keyboard_::isAnyModifierActive() {
|
||||||
|
return keyReport.modifiers > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if *any* modifier was being sent during the previous key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean Keyboard_::wasAnyModifierActive() {
|
||||||
|
return lastKeyReport.modifiers > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns true if the non-modifier key passed in will be sent during this key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean Keyboard_::isKeyPressed(uint8_t k) {
|
||||||
|
if (k <= HID_LAST_KEY) {
|
||||||
|
uint8_t bit = 1 << (uint8_t(k) % 8);
|
||||||
|
return !!(keyReport.keys[k / 8] & bit);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the non-modifer key passed in was sent during the previous key report
|
||||||
|
* Returns false in all other cases
|
||||||
|
* */
|
||||||
|
boolean Keyboard_::wasKeyPressed(uint8_t k) {
|
||||||
|
|
||||||
|
if (k <= HID_LAST_KEY) {
|
||||||
|
uint8_t bit = 1 << (uint8_t(k) % 8);
|
||||||
|
return !!(lastKeyReport.keys[k / 8] & bit);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t Keyboard_::press(uint8_t k) {
|
||||||
|
// If the key is in the range of 'printable' keys
|
||||||
|
if (k <= HID_LAST_KEY) {
|
||||||
|
uint8_t bit = 1 << (uint8_t(k) % 8);
|
||||||
|
keyReport.keys[k / 8] |= bit;
|
||||||
|
return 1;
|
||||||
|
} else { // It's a modifier key
|
||||||
|
if (k >= HID_KEYBOARD_FIRST_MODIFIER && k <= HID_KEYBOARD_LAST_MODIFIER) {
|
||||||
|
// Convert key into bitfield (0 - 7)
|
||||||
|
k = k - HID_KEYBOARD_FIRST_MODIFIER;
|
||||||
|
keyReport.modifiers |= (1 << k);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No empty/pressed key was found
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Keyboard_::release(uint8_t k) {
|
||||||
|
// If we're releasing a printable key
|
||||||
|
if (k <= HID_LAST_KEY) {
|
||||||
|
uint8_t bit = 1 << (k % 8);
|
||||||
|
keyReport.keys[k / 8] &= ~bit;
|
||||||
|
return 1;
|
||||||
|
} else { // It's a modifier key
|
||||||
|
if (k >= HID_KEYBOARD_FIRST_MODIFIER && k <= HID_KEYBOARD_LAST_MODIFIER) {
|
||||||
|
// Convert key into bitfield (0 - 7)
|
||||||
|
k = k - HID_KEYBOARD_FIRST_MODIFIER;
|
||||||
|
keyReport.modifiers &= ~(1 << k);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No empty/pressed key was found
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Keyboard_::releaseAll(void) {
|
||||||
|
// Release all keys
|
||||||
|
memset(&keyReport.allkeys, 0x00, sizeof(keyReport.allkeys));
|
||||||
|
}
|
||||||
|
|
||||||
|
Keyboard_ Keyboard;
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
|
||||||
|
#include "kaleidoscope/HIDTables.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HIDAliases.h"
|
||||||
|
|
||||||
|
#define KEY_BYTES 28
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// Modifiers + keymap
|
||||||
|
struct {
|
||||||
|
uint8_t modifiers;
|
||||||
|
uint8_t keys[KEY_BYTES ];
|
||||||
|
};
|
||||||
|
uint8_t allkeys[1 + KEY_BYTES];
|
||||||
|
} HID_KeyboardReport_Data_t;
|
||||||
|
|
||||||
|
class Keyboard_ {
|
||||||
|
public:
|
||||||
|
Keyboard_(void);
|
||||||
|
void begin(void);
|
||||||
|
void end(void);
|
||||||
|
|
||||||
|
size_t press(uint8_t k);
|
||||||
|
size_t release(uint8_t k);
|
||||||
|
void releaseAll(void);
|
||||||
|
int sendReport(void);
|
||||||
|
|
||||||
|
boolean isKeyPressed(uint8_t k);
|
||||||
|
boolean wasKeyPressed(uint8_t k);
|
||||||
|
boolean isModifierActive(uint8_t k);
|
||||||
|
boolean wasModifierActive(uint8_t k);
|
||||||
|
boolean isAnyModifierActive();
|
||||||
|
boolean wasAnyModifierActive();
|
||||||
|
|
||||||
|
uint8_t getLEDs() {
|
||||||
|
return HID().getLEDs();
|
||||||
|
}
|
||||||
|
|
||||||
|
HID_KeyboardReport_Data_t keyReport;
|
||||||
|
HID_KeyboardReport_Data_t lastKeyReport;
|
||||||
|
private:
|
||||||
|
int sendReportUnchecked(void);
|
||||||
|
};
|
||||||
|
extern Keyboard_ Keyboard;
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/MultiReport/Mouse.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidMultiReportDescriptorMouse[] PROGMEM = {
|
||||||
|
/* Mouse relative */
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, // USAGE_PAGE (Generic Desktop)
|
||||||
|
D_USAGE, D_USAGE_MOUSE, // USAGE (Mouse)
|
||||||
|
D_COLLECTION, D_APPLICATION, // COLLECTION (Application)
|
||||||
|
D_REPORT_ID, HID_REPORTID_MOUSE, // REPORT_ID (Mouse)
|
||||||
|
|
||||||
|
/* 8 Buttons */
|
||||||
|
D_USAGE_PAGE, D_PAGE_BUTTON, // USAGE_PAGE (Button)
|
||||||
|
D_USAGE_MINIMUM, 0x01, // USAGE_MINIMUM (Button 1)
|
||||||
|
D_USAGE_MAXIMUM, 0x08, // USAGE_MAXIMUM (Button 8)
|
||||||
|
D_LOGICAL_MINIMUM, 0x00, // LOGICAL_MINIMUM (0)
|
||||||
|
D_LOGICAL_MAXIMUM, 0x01, // LOGICAL_MAXIMUM (1)
|
||||||
|
D_REPORT_COUNT, 0x08, // REPORT_COUNT (8)
|
||||||
|
D_REPORT_SIZE, 0x01, // REPORT_SIZE (1)
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_ABSOLUTE), // INPUT (Data,Var,Abs)
|
||||||
|
|
||||||
|
/* X, Y, Wheel */
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, // USAGE_PAGE (Generic Desktop)
|
||||||
|
D_USAGE, 0x30, // USAGE (X)
|
||||||
|
D_USAGE, 0x31, // USAGE (Y)
|
||||||
|
D_USAGE, 0x38, // USAGE (Wheel)
|
||||||
|
D_LOGICAL_MINIMUM, 0x81, // LOGICAL_MINIMUM (-127)
|
||||||
|
D_LOGICAL_MAXIMUM, 0x7f, // LOGICAL_MAXIMUM (127)
|
||||||
|
D_REPORT_SIZE, 0x08, // REPORT_SIZE (8)
|
||||||
|
D_REPORT_COUNT, 0x03, // REPORT_COUNT (3)
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_RELATIVE), // INPUT (Data,Var,Rel)
|
||||||
|
|
||||||
|
/* Horizontal wheel */
|
||||||
|
D_USAGE_PAGE, D_PAGE_CONSUMER, // USAGE_PAGE (Consumer)
|
||||||
|
D_PAGE_ORDINAL, 0x38, 0x02, // PAGE (AC Pan)
|
||||||
|
D_LOGICAL_MINIMUM, 0x81, // LOGICAL_MINIMUM (-127)
|
||||||
|
D_LOGICAL_MAXIMUM, 0x7f, // LOGICAL_MAXIMUM (127)
|
||||||
|
D_REPORT_SIZE, 0x08, // REPORT_SIZE (8)
|
||||||
|
D_REPORT_COUNT, 0x01, // REPORT_COUNT (1)
|
||||||
|
D_INPUT, (D_DATA | D_VARIABLE | D_RELATIVE), // INPUT (Data,Var,Rel)
|
||||||
|
|
||||||
|
/* End */
|
||||||
|
D_END_COLLECTION // END_COLLECTION
|
||||||
|
};
|
||||||
|
|
||||||
|
Mouse_::Mouse_(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::begin(void) {
|
||||||
|
static HIDSubDescriptor node(_hidMultiReportDescriptorMouse, sizeof(_hidMultiReportDescriptorMouse));
|
||||||
|
HID().AppendDescriptor(&node);
|
||||||
|
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::end(void) {
|
||||||
|
releaseAll();
|
||||||
|
sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::click(uint8_t b) {
|
||||||
|
press(b);
|
||||||
|
sendReport();
|
||||||
|
release(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::move(signed char x, signed char y, signed char vWheel, signed char hWheel) {
|
||||||
|
report.xAxis = x;
|
||||||
|
report.yAxis = y;
|
||||||
|
report.vWheel = vWheel;
|
||||||
|
report.hWheel = hWheel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::releaseAll(void) {
|
||||||
|
memset(&report, 0, sizeof(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::press(uint8_t b) {
|
||||||
|
report.buttons |= b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::release(uint8_t b) {
|
||||||
|
report.buttons &= ~b;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mouse_::isPressed(uint8_t b) {
|
||||||
|
if ((b & report.buttons) > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::sendReportUnchecked(void) {
|
||||||
|
HID().SendReport(HID_REPORTID_MOUSE, &report, sizeof(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse_::sendReport(void) {
|
||||||
|
// If the last report is different than the current report, then we need to send a report.
|
||||||
|
// We guard sendReport like this so that calling code doesn't end up spamming the host with empty reports
|
||||||
|
// if sendReport is called in a tight loop.
|
||||||
|
|
||||||
|
// if the two reports are the same, check if they're empty, and return early
|
||||||
|
// without a report if they are.
|
||||||
|
static HID_MouseReport_Data_t emptyReport;
|
||||||
|
if (memcmp(&lastReport, &report, sizeof(report)) == 0 &&
|
||||||
|
memcmp(&report, &emptyReport, sizeof(report)) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sendReportUnchecked();
|
||||||
|
memcpy(&lastReport, &report, sizeof(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
Mouse_ Mouse;
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/MouseButtons.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// Mouse report: 8 buttons, position, wheel
|
||||||
|
struct {
|
||||||
|
uint8_t buttons;
|
||||||
|
int8_t xAxis;
|
||||||
|
int8_t yAxis;
|
||||||
|
int8_t vWheel;
|
||||||
|
int8_t hWheel;
|
||||||
|
};
|
||||||
|
} HID_MouseReport_Data_t;
|
||||||
|
|
||||||
|
|
||||||
|
class Mouse_ {
|
||||||
|
public:
|
||||||
|
Mouse_(void);
|
||||||
|
void begin(void);
|
||||||
|
void end(void);
|
||||||
|
void click(uint8_t b = MOUSE_LEFT);
|
||||||
|
void move(signed char x, signed char y, signed char vWheel = 0, signed char hWheel = 0);
|
||||||
|
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
|
||||||
|
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
|
||||||
|
bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
|
||||||
|
|
||||||
|
/** getReport returns the current report.
|
||||||
|
*
|
||||||
|
* The current report is the one to be send next time sendReport() is called.
|
||||||
|
*
|
||||||
|
* @returns A copy of the report.
|
||||||
|
*/
|
||||||
|
const HID_MouseReport_Data_t getReport() {
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
void sendReport(void);
|
||||||
|
|
||||||
|
void releaseAll(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HID_MouseReport_Data_t report;
|
||||||
|
HID_MouseReport_Data_t lastReport;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendReportUnchecked(void);
|
||||||
|
};
|
||||||
|
extern Mouse_ Mouse;
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/MultiReport/SystemControl.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DescriptorPrimitives.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidMultiReportDescriptorSystem[] PROGMEM = {
|
||||||
|
//TODO(anyone): limit to system keys only?
|
||||||
|
/* System Control (Power Down, Sleep, Wakeup, ...) */
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) */
|
||||||
|
D_USAGE, 0x80, /* USAGE (System Control) */
|
||||||
|
D_COLLECTION, D_APPLICATION, /* COLLECTION (Application) */
|
||||||
|
D_REPORT_ID, HID_REPORTID_SYSTEMCONTROL, /* REPORT_ID */
|
||||||
|
/* 1 system key */
|
||||||
|
D_LOGICAL_MINIMUM, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||||
|
D_MULTIBYTE(D_LOGICAL_MAXIMUM), 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
|
||||||
|
D_USAGE_MINIMUM, 0x00, /* USAGE_MINIMUM (Undefined) */
|
||||||
|
D_USAGE_MAXIMUM, 0xff, /* USAGE_MAXIMUM (System Menu Down) */
|
||||||
|
D_REPORT_COUNT, 0x01, /* REPORT_COUNT (1) */
|
||||||
|
D_REPORT_SIZE, 0x08, /* REPORT_SIZE (8) */
|
||||||
|
D_INPUT, (D_DATA | D_ARRAY | D_ABSOLUTE), /* INPUT (Data,Ary,Abs) */
|
||||||
|
D_END_COLLECTION /* END_COLLECTION */
|
||||||
|
};
|
||||||
|
|
||||||
|
SystemControl_::SystemControl_(void) {
|
||||||
|
static HIDSubDescriptor node(_hidMultiReportDescriptorSystem, sizeof(_hidMultiReportDescriptorSystem));
|
||||||
|
HID().AppendDescriptor(&node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl_::begin(void) {
|
||||||
|
// release all buttons
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl_::end(void) {
|
||||||
|
uint8_t _report = 0x00;
|
||||||
|
sendReport(&_report, sizeof(_report));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl_::write(uint8_t s) {
|
||||||
|
press(s);
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl_::release(void) {
|
||||||
|
begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl_::releaseAll(void) {
|
||||||
|
begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl_::press(uint8_t s) {
|
||||||
|
if (s == HID_SYSTEM_WAKE_UP) {
|
||||||
|
#ifdef __AVR__
|
||||||
|
USBDevice.wakeupHost();
|
||||||
|
#endif
|
||||||
|
#ifdef ARDUINO_ARCH_SAMD
|
||||||
|
// This is USBDevice_SAMD21G18x.wakeupHost(). But we can't include that
|
||||||
|
// header, because it redefines a few symbols, and causes linking
|
||||||
|
// errors. So we simply reimplement the same thing here.
|
||||||
|
USB->DEVICE.CTRLB.bit.UPRSM = 1;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
sendReport(&s, sizeof(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SystemControl_::sendReport(void* data, int length) {
|
||||||
|
HID().SendReport(HID_REPORTID_SYSTEMCONTROL, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemControl_ SystemControl;
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
#include "kaleidoscope/HIDTables.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
// Every usable system control key possible
|
||||||
|
uint8_t key;
|
||||||
|
} HID_SystemControlReport_Data_t;
|
||||||
|
|
||||||
|
|
||||||
|
class SystemControl_ {
|
||||||
|
public:
|
||||||
|
void begin(void);
|
||||||
|
void end(void);
|
||||||
|
void write(uint8_t s);
|
||||||
|
void press(uint8_t s);
|
||||||
|
void release(void);
|
||||||
|
void releaseAll(void);
|
||||||
|
void sendReport(void* data, int length);
|
||||||
|
|
||||||
|
SystemControl_(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern SystemControl_ SystemControl;
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/SingleReport/SingleAbsoluteMouse.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HIDReportObserver.h"
|
||||||
|
|
||||||
|
static const uint8_t _hidSingleReportDescriptorAbsoluteMouse[] PROGMEM = {
|
||||||
|
D_USAGE_PAGE, D_PAGE_GENERIC_DESKTOP, /* USAGE_PAGE (Generic Desktop) 54 */
|
||||||
|
D_USAGE, D_USAGE_MOUSE, /* USAGE (Mouse) */
|
||||||
|
D_COLLECTION, D_APPLICATION, /* COLLECTION (Application) */
|
||||||
|
|
||||||
|
DESCRIPTOR_ABS_MOUSE_BUTTONS
|
||||||
|
DESCRIPTOR_ABS_MOUSE_XY
|
||||||
|
DESCRIPTOR_ABS_MOUSE_WHEEL
|
||||||
|
D_END_COLLECTION /* End */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SingleAbsoluteMouse_::SingleAbsoluteMouse_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) {
|
||||||
|
epType[0] = EP_TYPE_INTERRUPT_IN;
|
||||||
|
PluggableUSB().plug(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SingleAbsoluteMouse_::getInterface(uint8_t* interfaceCount) {
|
||||||
|
*interfaceCount += 1; // uses 1
|
||||||
|
HIDDescriptor hidInterface = {
|
||||||
|
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
|
||||||
|
D_HIDREPORT(sizeof(_hidSingleReportDescriptorAbsoluteMouse)),
|
||||||
|
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01)
|
||||||
|
};
|
||||||
|
return USB_SendControl(0, &hidInterface, sizeof(hidInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
int SingleAbsoluteMouse_::getDescriptor(USBSetup& setup) {
|
||||||
|
// Check if this is a HID Class Descriptor request
|
||||||
|
if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a HID Class Descriptor wIndex cointains the interface number
|
||||||
|
if (setup.wIndex != pluggedInterface) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol
|
||||||
|
// due to the USB specs, but Windows and Linux just assumes its in report mode.
|
||||||
|
protocol = HID_REPORT_PROTOCOL;
|
||||||
|
|
||||||
|
return USB_SendControl(TRANSFER_PGM, _hidSingleReportDescriptorAbsoluteMouse, sizeof(_hidSingleReportDescriptorAbsoluteMouse));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleAbsoluteMouse_::setup(USBSetup& setup) {
|
||||||
|
if (pluggedInterface != setup.wIndex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t request = setup.bRequest;
|
||||||
|
uint8_t requestType = setup.bmRequestType;
|
||||||
|
|
||||||
|
if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) {
|
||||||
|
if (request == HID_GET_REPORT) {
|
||||||
|
// TODO(anyone): HID_GetReport();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_GET_PROTOCOL) {
|
||||||
|
// TODO(anyone): Send8(protocol);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) {
|
||||||
|
if (request == HID_SET_PROTOCOL) {
|
||||||
|
protocol = setup.wValueL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_SET_IDLE) {
|
||||||
|
idle = setup.wValueL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == HID_SET_REPORT) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleAbsoluteMouse_::sendReport(void* data, int length) {
|
||||||
|
auto result = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length);
|
||||||
|
HIDReportObserver::observeReport(HID_REPORTID_MOUSE_ABSOLUTE, data, length, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleAbsoluteMouse_ SingleAbsoluteMouse;
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2018 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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 "kaleidoscope/driver/hid/keyboardio/usb/HID_.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/HID-Settings.h"
|
||||||
|
#include "kaleidoscope/driver/hid/keyboardio/usb/DeviceAPIs/AbsoluteMouseAPI.h"
|
||||||
|
|
||||||
|
|
||||||
|
class SingleAbsoluteMouse_ : public PluggableUSBModule, public AbsoluteMouseAPI {
|
||||||
|
public:
|
||||||
|
SingleAbsoluteMouse_(void);
|
||||||
|
uint8_t getLeds(void);
|
||||||
|
uint8_t getProtocol(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Implementation of the PUSBListNode
|
||||||
|
int getInterface(uint8_t* interfaceCount);
|
||||||
|
int getDescriptor(USBSetup& setup);
|
||||||
|
bool setup(USBSetup& setup);
|
||||||
|
|
||||||
|
EPTYPE_DESCRIPTOR_SIZE epType[1];
|
||||||
|
uint8_t protocol;
|
||||||
|
uint8_t idle;
|
||||||
|
|
||||||
|
inline void sendReport(void* data, int length) override;
|
||||||
|
};
|
||||||
|
extern SingleAbsoluteMouse_ SingleAbsoluteMouse;
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 NicoHood
|
||||||
|
Copyright (c) 2015-2020 Keyboard.io, Inc
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// Keyboard Leds
|
||||||
|
enum KeyboardLeds : uint8_t {
|
||||||
|
LED_NUM_LOCK = (1 << 0),
|
||||||
|
LED_CAPS_LOCK = (1 << 1),
|
||||||
|
LED_SCROLL_LOCK = (1 << 2),
|
||||||
|
LED_COMPOSE = (1 << 3),
|
||||||
|
LED_KANA = (1 << 4),
|
||||||
|
LED_POWER = (1 << 5),
|
||||||
|
LED_SHIFT = (1 << 6),
|
||||||
|
LED_DO_NOT_DISTURB = (1 << 7),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Include all HID libraries (.a linkage required to work) properly
|
||||||
|
#include "MultiReport/AbsoluteMouse.h"
|
||||||
|
#include "MultiReport/Mouse.h"
|
||||||
|
#include "MultiReport/ConsumerControl.h"
|
||||||
|
#include "MultiReport/Gamepad.h"
|
||||||
|
#include "MultiReport/SystemControl.h"
|
||||||
|
#include "MultiReport/Keyboard.h"
|
||||||
|
|
||||||
|
#include "SingleReport/SingleAbsoluteMouse.h"
|
||||||
|
|
||||||
|
#include "BootKeyboard/BootKeyboard.h"
|
@ -0,0 +1,8 @@
|
|||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_AVR
|
||||||
|
|
||||||
|
void USB_PackMessages(bool pack) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,17 @@
|
|||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_SAMD
|
||||||
|
|
||||||
|
int USB_SendControl(void* b, unsigned char c) {
|
||||||
|
USBDevice.sendControl(b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int USB_SendControl(uint8_t a, const void* b, uint8_t c) {
|
||||||
|
USBDevice.sendControl(b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_PackMessages(bool pack) {
|
||||||
|
USBDevice.packMessages(pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in new issue