To make it easier to configure which HID implementation - and which parts of it - a particular board uses, we turn our current HID facade (`kaleidoscope::hid`) into a proper, Props-supported driver. This also allows us to get rid of the `Kaleidoscope-HIDAdaptor-KeyboardioHID` library. Signed-off-by: Gergely Nagy <algernon@keyboard.io>pull/771/head
parent
2b9103fe64
commit
3af7921f40
@ -0,0 +1,68 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "kaleidoscope/key_defs.h"
|
||||||
|
|
||||||
|
#include "base/Keyboard.h"
|
||||||
|
#include "base/Mouse.h"
|
||||||
|
#include "base/AbsoluteMouse.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
|
||||||
|
struct BaseProps {
|
||||||
|
typedef base::KeyboardProps KeyboardProps;
|
||||||
|
typedef base::Keyboard<KeyboardProps> Keyboard;
|
||||||
|
typedef base::MouseProps MouseProps;
|
||||||
|
typedef base::Mouse<MouseProps> Mouse;
|
||||||
|
typedef base::AbsoluteMouseProps AbsoluteMouseProps;
|
||||||
|
typedef base::AbsoluteMouse<AbsoluteMouseProps> AbsoluteMouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class Base {
|
||||||
|
private:
|
||||||
|
typename _Props::Keyboard keyboard_;
|
||||||
|
typename _Props::Mouse mouse_;
|
||||||
|
typename _Props::AbsoluteMouse absolute_mouse_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Base() {}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
keyboard().setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto keyboard() -> decltype(keyboard_) & {
|
||||||
|
return keyboard_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mouse() -> decltype(mouse_) & {
|
||||||
|
return mouse_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto absoluteMouse() -> decltype(absolute_mouse_) & {
|
||||||
|
return absolute_mouse_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <KeyboardioHID.h>
|
||||||
|
#include "kaleidoscope/key_defs.h"
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/hid/Base.h"
|
||||||
|
|
||||||
|
#include "keyboardio/Keyboard.h"
|
||||||
|
#include "keyboardio/Mouse.h"
|
||||||
|
#include "keyboardio/AbsoluteMouse.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
|
||||||
|
struct KeyboardioProps: public BaseProps {
|
||||||
|
typedef keyboardio::KeyboardProps KeyboardProps;
|
||||||
|
typedef keyboardio::Keyboard<KeyboardProps> Keyboard;
|
||||||
|
typedef keyboardio::MouseProps MouseProps;
|
||||||
|
typedef keyboardio::Mouse<MouseProps> Mouse;
|
||||||
|
typedef keyboardio::AbsoluteMouseProps AbsoluteMouseProps;
|
||||||
|
typedef keyboardio::AbsoluteMouse<AbsoluteMouseProps> AbsoluteMouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class Keyboardio: public Base<_Props> {};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
class NoAbsoluteMouse {
|
||||||
|
public:
|
||||||
|
NoAbsoluteMouse() {}
|
||||||
|
|
||||||
|
void begin() {}
|
||||||
|
void move(int8_t x, int8_t y, int8_t wheel) {}
|
||||||
|
void moveTo(uint16_t x, uint16_t y, uint8_t wheel) {}
|
||||||
|
|
||||||
|
void click(uint8_t buttons) {}
|
||||||
|
void press(uint8_t buttons) {}
|
||||||
|
void release(uint8_t buttons) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbsoluteMouseProps {
|
||||||
|
typedef NoAbsoluteMouse AbsoluteMouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class AbsoluteMouse {
|
||||||
|
private:
|
||||||
|
typename _Props::AbsoluteMouse absolute_mouse_;
|
||||||
|
public:
|
||||||
|
AbsoluteMouse() {}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
absolute_mouse_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void move(int8_t x, int8_t y, int8_t wheel) {
|
||||||
|
absolute_mouse_.move(x, y, wheel);
|
||||||
|
}
|
||||||
|
void moveTo(uint16_t x, uint16_t y, uint8_t wheel) {
|
||||||
|
absolute_mouse_.moveTo(x, y, wheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clickButtons(uint8_t buttons) {
|
||||||
|
absolute_mouse_.click(buttons);
|
||||||
|
}
|
||||||
|
void pressButtons(uint8_t buttons) {
|
||||||
|
absolute_mouse_.press(buttons);
|
||||||
|
}
|
||||||
|
void releaseButtons(uint8_t buttons) {
|
||||||
|
absolute_mouse_.release(buttons);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,485 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "kaleidoscope/key_defs.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
class NoBootKeyboard {
|
||||||
|
public:
|
||||||
|
NoBootKeyboard() {}
|
||||||
|
void begin() {}
|
||||||
|
|
||||||
|
uint8_t getProtocol() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void setProtocol(uint8_t protocol) {}
|
||||||
|
void setDefaultProtocol(uint8_t protocol) {}
|
||||||
|
|
||||||
|
void sendReport();
|
||||||
|
|
||||||
|
void press(uint8_t code) {}
|
||||||
|
void release(uint8_t code) {}
|
||||||
|
void releaseAll() {}
|
||||||
|
|
||||||
|
bool isModifierActive(uint8_t code) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool wasModifierActive(uint8_t code) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool isAnyModifierActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool wasAnyModifierActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getLeds() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NoNKROKeyboard {
|
||||||
|
public:
|
||||||
|
NoNKROKeyboard() {}
|
||||||
|
void begin() {}
|
||||||
|
|
||||||
|
void sendReport() {}
|
||||||
|
|
||||||
|
void press(uint8_t code) {}
|
||||||
|
void release(uint8_t code) {}
|
||||||
|
void releaseAll() {}
|
||||||
|
|
||||||
|
bool isModifierActive(Key key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool wasModifierActive(Key key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool isAnyModifierActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool wasAnyModifierActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getLeds() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NoConsumerControl {
|
||||||
|
public:
|
||||||
|
NoConsumerControl() {}
|
||||||
|
void begin() {}
|
||||||
|
|
||||||
|
void sendReport() {}
|
||||||
|
void releaseAll() {}
|
||||||
|
|
||||||
|
void press(uint8_t code) {}
|
||||||
|
void release(uint8_t code) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NoSystemControl {
|
||||||
|
public:
|
||||||
|
NoSystemControl() {}
|
||||||
|
void begin() {}
|
||||||
|
|
||||||
|
void press(uint8_t code) {}
|
||||||
|
void release() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyboardProps {
|
||||||
|
typedef NoBootKeyboard BootKeyboard;
|
||||||
|
typedef NoNKROKeyboard NKROKeyboard;
|
||||||
|
typedef NoConsumerControl ConsumerControl;
|
||||||
|
typedef NoSystemControl SystemControl;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class Keyboard {
|
||||||
|
private:
|
||||||
|
typename _Props::BootKeyboard boot_keyboard_;
|
||||||
|
typename _Props::NKROKeyboard nkro_keyboard_;
|
||||||
|
typename _Props::ConsumerControl consumer_control_;
|
||||||
|
typename _Props::SystemControl system_control_;
|
||||||
|
public:
|
||||||
|
Keyboard() {}
|
||||||
|
|
||||||
|
void setup() __attribute__((noinline)) {
|
||||||
|
boot_keyboard_.begin();
|
||||||
|
nkro_keyboard_.begin();
|
||||||
|
consumer_control_.begin();
|
||||||
|
system_control_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendReport() __attribute__((noinline)) {
|
||||||
|
// Before sending the report, we add any modifier flags that are currently
|
||||||
|
// allowed, based on the latest keypress:
|
||||||
|
pressModifiers(requested_modifier_flags & modifier_flag_mask);
|
||||||
|
|
||||||
|
// If a key has been toggled on in this cycle, we might need to send an extra
|
||||||
|
// HID report to the host, because that key might have the same keycode as
|
||||||
|
// another key that was already in the report on the previous cycle. For
|
||||||
|
// example, a user could have two `Key_E` keys in their keymap, in order to
|
||||||
|
// avoid repeating the same key with one finger. Or one might have a
|
||||||
|
// `LCTRL(Key_S)` and a plain `Key_S`, and have a reason to press them in
|
||||||
|
// rapid succession. In order to make this work, we need to call `release()` &
|
||||||
|
// `sendReport()` to send a release event to the host so that its normal
|
||||||
|
// repeat-rate-limiting behaviour won't effectively mask the second keypress.
|
||||||
|
// Then we call `press()` to add the keycode back in before sending the normal
|
||||||
|
// report.
|
||||||
|
//
|
||||||
|
// In most cases, this won't result in any difference from the previous report
|
||||||
|
// (because the newly-toggled-on keycode won't be in the previous report), so
|
||||||
|
// no extra report will be sent (because we suppress duplicate reports in
|
||||||
|
// KeyboardioHID). If there is a difference in the modifiers byte, an extra
|
||||||
|
// report would be sent later, regardless (also in KeyboardioHID).
|
||||||
|
//
|
||||||
|
// Furthermore, we need to send a report without the keycode for the
|
||||||
|
// newly-toggled-on key, but with any masked modifiers from flags removed. For
|
||||||
|
// example, if we roll over from `LSHIFT(Key_A)` to `Key_B`, we need to first
|
||||||
|
// send a report without the `shift`, then a second report with the `B`. If
|
||||||
|
// both of those bits are changed in the same report, at least one major OS
|
||||||
|
// processes the `B` keypress first, and we end up with `AB` instead of `Ab`
|
||||||
|
// in the output.
|
||||||
|
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
if (last_keycode_toggled_on) {
|
||||||
|
boot_keyboard_.release(last_keycode_toggled_on);
|
||||||
|
boot_keyboard_.sendReport();
|
||||||
|
boot_keyboard_.press(last_keycode_toggled_on);
|
||||||
|
last_keycode_toggled_on = 0;
|
||||||
|
}
|
||||||
|
boot_keyboard_.sendReport();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_keycode_toggled_on) {
|
||||||
|
// It would be good if KeyboardioHID's Keyboard object offered a way to
|
||||||
|
// compare the modifiers bytes of the current and previous key reports. That
|
||||||
|
// would allow us to only send these extra reports when either
|
||||||
|
// `last_keycode_toggled_on` was already held, or the modifiers byte
|
||||||
|
// changed. Likewise for BootKeyboard above.
|
||||||
|
nkro_keyboard_.release(last_keycode_toggled_on);
|
||||||
|
nkro_keyboard_.sendReport();
|
||||||
|
nkro_keyboard_.press(last_keycode_toggled_on);
|
||||||
|
last_keycode_toggled_on = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nkro_keyboard_.sendReport();
|
||||||
|
consumer_control_.sendReport();
|
||||||
|
}
|
||||||
|
void releaseAllKeys() __attribute__((noinline)) {
|
||||||
|
resetModifierTracking();
|
||||||
|
nkro_keyboard_.releaseAll();
|
||||||
|
consumer_control_.releaseAll();
|
||||||
|
}
|
||||||
|
void pressConsumerControl(Key mapped_key) {
|
||||||
|
consumer_control_.press(CONSUMER(mapped_key));
|
||||||
|
}
|
||||||
|
void releaseConsumerControl(Key mapped_key) {
|
||||||
|
consumer_control_.release(CONSUMER(mapped_key));
|
||||||
|
}
|
||||||
|
void pressSystemControl(Key mapped_key) {
|
||||||
|
system_control_.press(mapped_key.getKeyCode());
|
||||||
|
}
|
||||||
|
void releaseSystemControl(Key mapped_key) {
|
||||||
|
system_control_.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// pressKey takes a Key, as well as optional boolean 'toggledOn' which defaults
|
||||||
|
// to 'true'
|
||||||
|
|
||||||
|
// If toggled_on is not set to false, this routine adds the modifier flags on
|
||||||
|
// this key to the bitmask of modifiers that are allowed to be added to the
|
||||||
|
// upcoming report. We do this so that when we roll over from a key with a
|
||||||
|
// modifier flag to one without it, that modifier flag won't affect the new
|
||||||
|
// keypress.
|
||||||
|
|
||||||
|
// If the key we're processing is a modifier key, any modifier flags attached to
|
||||||
|
// it are added directly to the report along with the modifier from its keycode
|
||||||
|
// byte.
|
||||||
|
//
|
||||||
|
// (A 'modifier key' is one of the eight modifier keys defined by the HID
|
||||||
|
// standard: left and right variants of Control, Shift, Alt, and GUI.)
|
||||||
|
|
||||||
|
// Eventually it calls pressRawKey.
|
||||||
|
|
||||||
|
void pressKey(Key pressed_key, boolean toggled_on = true) __attribute__((noinline)) {
|
||||||
|
if (toggled_on) {
|
||||||
|
// If two keys are toggled on during the same USB report, we would ideally
|
||||||
|
// send an extra USB report to help the host handle each key correctly, but
|
||||||
|
// this is problematic.
|
||||||
|
|
||||||
|
// If we simply allow modifiers associated with the second newly-pressed
|
||||||
|
// key, it is possible to drop a modifier before the report is sent.
|
||||||
|
// Instead, we send modifiers associated with any newly-pressed keys.
|
||||||
|
|
||||||
|
// The downside of this behavior is that in cases where the user presses
|
||||||
|
// down keys with conflicting modifiers at the exact same moment, they may
|
||||||
|
// get unexpected behavior.
|
||||||
|
|
||||||
|
// If this is the first 'new' keycode being pressed in this cycle, reset the
|
||||||
|
// bitmask of modifiers we're willing to attach to USB HID keyboard reports
|
||||||
|
if (!last_keycode_toggled_on) {
|
||||||
|
modifier_flag_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any modifiers attached to this key to the bitmask of modifiers we're
|
||||||
|
// willing to attach to USB HID keyboard reports
|
||||||
|
modifier_flag_mask |= pressed_key.getFlags();
|
||||||
|
|
||||||
|
if (!isModifierKey(pressed_key)) {
|
||||||
|
last_keycode_toggled_on = pressed_key.getKeyCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isModifierKey(pressed_key)) {
|
||||||
|
// If the key is a modifier key with additional modifiers attached to it as
|
||||||
|
// flags (as one might when creating a 'Hyper' key or a "Control Alt" key,
|
||||||
|
// we assume that all those modifiers are intended to modify other keys
|
||||||
|
// pressed while this key is held, so they are never masked out.
|
||||||
|
pressModifiers(pressed_key.getFlags());
|
||||||
|
} else {
|
||||||
|
// If, instead, the modifiers are attached to a 'printable' or non-modifier
|
||||||
|
// key, we assume that they're not intended to modify other keys, so we add
|
||||||
|
// them to requested_modifier_flags, and only allow them to affect the report if
|
||||||
|
// the most recent keypress includes those modifiers.
|
||||||
|
requestModifiers(pressed_key.getFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
pressRawKey(pressed_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pressRawKey takes a Key object and calles KeyboardioHID's ".press" method
|
||||||
|
// with its keycode. It does no processing of any flags or modifiers on the key
|
||||||
|
void pressRawKey(Key pressed_key) {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
boot_keyboard_.press(pressed_key.getKeyCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nkro_keyboard_.press(pressed_key.getKeyCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseRawKey(Key released_key) {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
boot_keyboard_.release(released_key.getKeyCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nkro_keyboard_.release(released_key.getKeyCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseKey(Key released_key) {
|
||||||
|
// Remove any modifiers attached to this key from the bitmask of modifiers we're
|
||||||
|
// willing to attach to USB HID keyboard reports
|
||||||
|
modifier_flag_mask ^= released_key.getFlags();
|
||||||
|
|
||||||
|
if (!isModifierKey(released_key)) {
|
||||||
|
|
||||||
|
// TODO: this code is incomplete, but is better than nothing
|
||||||
|
// If we're toggling off the most recently toggled on key, clear
|
||||||
|
// last_keycode_toggled_on
|
||||||
|
if (last_keycode_toggled_on == released_key.getKeyCode()) {
|
||||||
|
last_keycode_toggled_on = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the modifiers are attached to a 'printable' or non-modifier
|
||||||
|
// key, we need to clean up after the key press which would have requested
|
||||||
|
// the modifiers be pressed if the most recent keypress includes those modifiers.
|
||||||
|
cancelModifierRequest(released_key.getFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseModifiers(released_key.getFlags());
|
||||||
|
releaseRawKey(released_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isModifierKeyActive(Key modifier_key) {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
return boot_keyboard_.isModifierActive(modifier_key.getKeyCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nkro_keyboard_.isModifierActive(modifier_key.getKeyCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean wasModifierKeyActive(Key modifier_key) {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
return boot_keyboard_.wasModifierActive(modifier_key.getKeyCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nkro_keyboard_.wasModifierActive(modifier_key.getKeyCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAnyModifierKeyActive() {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
return boot_keyboard_.isAnyModifierActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nkro_keyboard_.isAnyModifierActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean wasAnyModifierKeyActive() {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
return boot_keyboard_.wasAnyModifierActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nkro_keyboard_.wasAnyModifierActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getKeyboardLEDs() {
|
||||||
|
if (boot_keyboard_.getProtocol() == HID_BOOT_PROTOCOL) {
|
||||||
|
return boot_keyboard_.getLeds();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nkro_keyboard_.getLeds();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getProtocol() {
|
||||||
|
return boot_keyboard_.getProtocol();
|
||||||
|
}
|
||||||
|
void setProtocol(uint8_t protocol) {
|
||||||
|
boot_keyboard_.setProtocol(protocol);
|
||||||
|
}
|
||||||
|
void setDefaultProtocol(uint8_t protocol) {
|
||||||
|
boot_keyboard_.setDefaultProtocol(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// modifier_flag_mask is a bitmask of modifiers that we found attached to
|
||||||
|
// keys that were newly pressed down during the most recent cycle with any new
|
||||||
|
// keypresses.
|
||||||
|
|
||||||
|
// This is used to determine which modifier flags will be allowed to be added to
|
||||||
|
// the current keyboard HID report. It gets set during any cycle where one or
|
||||||
|
// more new keys is toggled on and presists until the next cycle with a newly
|
||||||
|
// detected keypress.
|
||||||
|
|
||||||
|
uint8_t modifier_flag_mask = 0;
|
||||||
|
|
||||||
|
// The functions in this namespace are primarily to solve the problem of
|
||||||
|
// rollover from a key with a modifier flag (e.g. `LSHIFT(Key_T)`) to one
|
||||||
|
// without (e.g. `Key_H`), which used to result in the mod flag being applied to
|
||||||
|
// keys other than the one with the flag. By using `modifier_flag_mask`, we can
|
||||||
|
// mask out any modifier flags that aren't attached to modifier keys or keys
|
||||||
|
// pressed or held in the most recent cycle, mitigating the rollover problem,
|
||||||
|
// and getting the intended `The` instead of `THe`.
|
||||||
|
|
||||||
|
// requested_modifier_flags is bitmap of the modifiers attached to any non-modifier
|
||||||
|
// key found to be pressed during the most recent cycle. For example, it would
|
||||||
|
// include modifiers attached to Key_A, but not modifiers attached to
|
||||||
|
// Key_LeftControl
|
||||||
|
|
||||||
|
uint8_t requested_modifier_flags = 0;
|
||||||
|
|
||||||
|
// last_keycode_toggled_on is the keycode of the key most recently toggled on
|
||||||
|
// for this report. This is set when a keypress is first detected and cleared
|
||||||
|
// after the report is sent. If multiple keys are toggled on during a single
|
||||||
|
// cycle, this contains the most recently handled one.
|
||||||
|
|
||||||
|
uint8_t last_keycode_toggled_on = 0;
|
||||||
|
|
||||||
|
void resetModifierTracking(void) {
|
||||||
|
last_keycode_toggled_on = 0;
|
||||||
|
requested_modifier_flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// isModifierKey takes a Key and returns true if the key is a
|
||||||
|
// keyboard key corresponding to a modifier like Control, Alt or Shift
|
||||||
|
// TODO: This function should be lifted to the Kaleidoscope core, somewhere.
|
||||||
|
|
||||||
|
bool isModifierKey(Key key) {
|
||||||
|
// If it's not a keyboard key, return false
|
||||||
|
if (key.getFlags() & (SYNTHETIC | RESERVED)) return false;
|
||||||
|
|
||||||
|
return (key.getKeyCode() >= HID_KEYBOARD_FIRST_MODIFIER &&
|
||||||
|
key.getKeyCode() <= HID_KEYBOARD_LAST_MODIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// requestModifiers takes a bitmap of modifiers that might apply
|
||||||
|
// to the next USB HID report and adds them to a bitmap of all such modifiers.
|
||||||
|
|
||||||
|
void requestModifiers(byte flags) {
|
||||||
|
requested_modifier_flags |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancelModifierRequest takes a bitmap of modifiers that should no longer apply
|
||||||
|
// to the next USB HID report and removes them from the bitmap of all such modifiers.
|
||||||
|
|
||||||
|
void cancelModifierRequest(byte flags) {
|
||||||
|
requested_modifier_flags ^= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pressModifiers takes a bitmap of modifier keys that must be included in
|
||||||
|
// the upcoming USB HID report and passes them through to KeyboardioHID
|
||||||
|
// immediately
|
||||||
|
|
||||||
|
void pressModifiers(byte flags) {
|
||||||
|
if (flags & SHIFT_HELD) {
|
||||||
|
pressRawKey(Key_LeftShift);
|
||||||
|
}
|
||||||
|
if (flags & CTRL_HELD) {
|
||||||
|
pressRawKey(Key_LeftControl);
|
||||||
|
}
|
||||||
|
if (flags & LALT_HELD) {
|
||||||
|
pressRawKey(Key_LeftAlt);
|
||||||
|
}
|
||||||
|
if (flags & RALT_HELD) {
|
||||||
|
pressRawKey(Key_RightAlt);
|
||||||
|
}
|
||||||
|
if (flags & GUI_HELD) {
|
||||||
|
pressRawKey(Key_LeftGui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// releaseModifiers takes a bitmap of modifier keys that must not be included in
|
||||||
|
// the upcoming USB HID report and passes them through to KeyboardioHID
|
||||||
|
// immediately
|
||||||
|
|
||||||
|
void releaseModifiers(byte flags) {
|
||||||
|
if (flags & SHIFT_HELD) {
|
||||||
|
releaseRawKey(Key_LeftShift);
|
||||||
|
}
|
||||||
|
if (flags & CTRL_HELD) {
|
||||||
|
releaseRawKey(Key_LeftControl);
|
||||||
|
}
|
||||||
|
if (flags & LALT_HELD) {
|
||||||
|
releaseRawKey(Key_LeftAlt);
|
||||||
|
}
|
||||||
|
if (flags & RALT_HELD) {
|
||||||
|
releaseRawKey(Key_RightAlt);
|
||||||
|
}
|
||||||
|
if (flags & GUI_HELD) {
|
||||||
|
releaseRawKey(Key_LeftGui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
class NoMouse {
|
||||||
|
public:
|
||||||
|
NoMouse() {}
|
||||||
|
|
||||||
|
void begin() {}
|
||||||
|
void sendReport() {}
|
||||||
|
void move(int8_t x, int8_t y, int8_t vWheel, int8_t hWheel) {}
|
||||||
|
void releaseAll() {}
|
||||||
|
void press(uint8_t buttons) {}
|
||||||
|
void release(uint8_t buttons) {}
|
||||||
|
void click(uint8_t buttons) {}
|
||||||
|
HID_MouseReport_Data_t getReport() {
|
||||||
|
static HID_MouseReport_Data_t report;
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MouseProps {
|
||||||
|
typedef NoMouse Mouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class Mouse {
|
||||||
|
private:
|
||||||
|
typename _Props::Mouse mouse_;
|
||||||
|
public:
|
||||||
|
Mouse() {}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
mouse_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendReport() {
|
||||||
|
mouse_.sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void move(int8_t x, int8_t y, int8_t vWheel = 0, int8_t hWheel = 0) {
|
||||||
|
mouse_.move(x, y, vWheel, hWheel);
|
||||||
|
}
|
||||||
|
void stop(bool x, bool y, bool vWheel = false, bool hWheel = false) {
|
||||||
|
HID_MouseReport_Data_t report = mouse_.getReport();
|
||||||
|
|
||||||
|
if (x)
|
||||||
|
report.xAxis = 0;
|
||||||
|
if (y)
|
||||||
|
report.yAxis = 0;
|
||||||
|
if (vWheel)
|
||||||
|
report.vWheel = 0;
|
||||||
|
if (hWheel)
|
||||||
|
report.hWheel = 0;
|
||||||
|
move(report.xAxis, report.yAxis, report.vWheel, report.hWheel);
|
||||||
|
}
|
||||||
|
void releaseAllButtons() {
|
||||||
|
mouse_.releaseAll();
|
||||||
|
}
|
||||||
|
void pressButtons(uint8_t buttons) {
|
||||||
|
mouse_.press(buttons);
|
||||||
|
}
|
||||||
|
void releaseButtons(uint8_t buttons) {
|
||||||
|
mouse_.release(buttons);
|
||||||
|
}
|
||||||
|
void clickButtons(uint8_t buttons) {
|
||||||
|
mouse_.click(buttons);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <KeyboardioHID.h>
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/hid/base/AbsoluteMouse.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
namespace keyboardio {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are wrapping `SingleAbsoluteMouse` here, instead of directly using the
|
||||||
|
* class in `AbsoluteMouseProps` below. We do this, because this lets the linker
|
||||||
|
* optimize this whole thing out if it is unused. It can do that because
|
||||||
|
* instantiating `SingleAbsoluteMouse` is in a separate compilation unit.
|
||||||
|
*
|
||||||
|
* While it would have been cleaner and shorter to instantiate them here, and
|
||||||
|
* drop the global objects, that prevents optimizing them out, and that's a cost
|
||||||
|
* we do not want to pay.
|
||||||
|
*/
|
||||||
|
class AbsoluteMouseWrapper {
|
||||||
|
public:
|
||||||
|
AbsoluteMouseWrapper() {}
|
||||||
|
|
||||||
|
void begin() {
|
||||||
|
SingleAbsoluteMouse.begin();
|
||||||
|
}
|
||||||
|
void move(int8_t x, int8_t y, int8_t wheel) {
|
||||||
|
SingleAbsoluteMouse.move(x, y, wheel);
|
||||||
|
}
|
||||||
|
void moveTo(uint16_t x, uint16_t y, uint8_t wheel) {
|
||||||
|
SingleAbsoluteMouse.moveTo(x, y, wheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void click(uint8_t buttons) {
|
||||||
|
SingleAbsoluteMouse.click(buttons);
|
||||||
|
}
|
||||||
|
void press(uint8_t buttons) {
|
||||||
|
SingleAbsoluteMouse.press(buttons);
|
||||||
|
}
|
||||||
|
void release(uint8_t buttons) {
|
||||||
|
SingleAbsoluteMouse.release(buttons);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbsoluteMouseProps: public base::AbsoluteMouseProps {
|
||||||
|
typedef AbsoluteMouseWrapper AbsoluteMouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class AbsoluteMouse: public base::AbsoluteMouse<_Props> {};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,179 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <KeyboardioHID.h>
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/hid/base/Keyboard.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
namespace keyboardio {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are wrapping a few keyboard-related objects here, instead of directly
|
||||||
|
* using the classes in `KeyboardProps` below. We do this, because this lets the
|
||||||
|
* linker optimize this whole thing out if it is unused. It can do that because
|
||||||
|
* instantiating `Keyboard_` & co is in a separate compilation unit.
|
||||||
|
*
|
||||||
|
* While it would have been cleaner and shorter to instantiate them here, and
|
||||||
|
* drop the global objects, that prevents optimizing them out, and that's a cost
|
||||||
|
* we do not want to pay.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class BootKeyboardWrapper {
|
||||||
|
public:
|
||||||
|
BootKeyboardWrapper() {}
|
||||||
|
void begin() {
|
||||||
|
BootKeyboard.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getProtocol() {
|
||||||
|
return BootKeyboard.getProtocol();
|
||||||
|
}
|
||||||
|
void setProtocol(uint8_t protocol) {
|
||||||
|
BootKeyboard.setProtocol(protocol);
|
||||||
|
}
|
||||||
|
void setDefaultProtocol(uint8_t protocol) {
|
||||||
|
BootKeyboard.default_protocol = protocol;
|
||||||
|
setProtocol(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendReport() {
|
||||||
|
BootKeyboard.sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void press(uint8_t code) {
|
||||||
|
BootKeyboard.press(code);
|
||||||
|
}
|
||||||
|
void release(uint8_t code) {
|
||||||
|
BootKeyboard.release(code);
|
||||||
|
}
|
||||||
|
void releaseAll() {
|
||||||
|
BootKeyboard.releaseAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isModifierActive(uint8_t code) {
|
||||||
|
return BootKeyboard.isModifierActive(code);
|
||||||
|
}
|
||||||
|
bool wasModifierActive(uint8_t code) {
|
||||||
|
return BootKeyboard.wasModifierActive(code);
|
||||||
|
}
|
||||||
|
bool isAnyModifierActive() {
|
||||||
|
return BootKeyboard.isAnyModifierActive();
|
||||||
|
}
|
||||||
|
bool wasAnyModifierActive() {
|
||||||
|
return BootKeyboard.wasAnyModifierActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getLeds() {
|
||||||
|
return BootKeyboard.getLeds();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NKROKeyboardWrapper {
|
||||||
|
public:
|
||||||
|
NKROKeyboardWrapper() {}
|
||||||
|
void begin() {
|
||||||
|
Keyboard.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendReport() {
|
||||||
|
Keyboard.sendReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void press(uint8_t code) {
|
||||||
|
Keyboard.press(code);
|
||||||
|
}
|
||||||
|
void release(uint8_t code) {
|
||||||
|
Keyboard.release(code);
|
||||||
|
}
|
||||||
|
void releaseAll() {
|
||||||
|
Keyboard.releaseAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isModifierActive(uint8_t code) {
|
||||||
|
return Keyboard.isModifierActive(code);
|
||||||
|
}
|
||||||
|
bool wasModifierActive(uint8_t code) {
|
||||||
|
return Keyboard.wasModifierActive(code);
|
||||||
|
}
|
||||||
|
bool isAnyModifierActive() {
|
||||||
|
return Keyboard.isAnyModifierActive();
|
||||||
|
}
|
||||||
|
bool wasAnyModifierActive() {
|
||||||
|
return Keyboard.wasAnyModifierActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getLeds() {
|
||||||
|
return Keyboard.getLEDs();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConsumerControlWrapper {
|
||||||
|
public:
|
||||||
|
ConsumerControlWrapper() {}
|
||||||
|
void begin() {
|
||||||
|
ConsumerControl.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendReport() {
|
||||||
|
ConsumerControl.sendReport();
|
||||||
|
}
|
||||||
|
void releaseAll() {
|
||||||
|
ConsumerControl.releaseAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void press(uint8_t code) {
|
||||||
|
ConsumerControl.press(code);
|
||||||
|
}
|
||||||
|
void release(uint8_t code) {
|
||||||
|
ConsumerControl.release(code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SystemControlWrapper {
|
||||||
|
public:
|
||||||
|
SystemControlWrapper() {}
|
||||||
|
void begin() {
|
||||||
|
SystemControl.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void press(uint8_t code) {
|
||||||
|
SystemControl.press(code);
|
||||||
|
}
|
||||||
|
void release() {
|
||||||
|
SystemControl.release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyboardProps: public base::KeyboardProps {
|
||||||
|
typedef BootKeyboardWrapper BootKeyboard;
|
||||||
|
typedef NKROKeyboardWrapper NKROKeyboard;
|
||||||
|
typedef ConsumerControlWrapper ConsumerControl;
|
||||||
|
typedef SystemControlWrapper SystemControl;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class Keyboard: public base::Keyboard<_Props> {};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
/* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2013-2019 Keyboard.io, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <KeyboardioHID.h>
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/hid/base/Mouse.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace hid {
|
||||||
|
namespace keyboardio {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are wrapping `Mouse` here, instead of directly using the class in
|
||||||
|
* `MouseProps` below. We do this, because this lets the linker optimize this
|
||||||
|
* whole thing out if it is unused. It can do that because instantiating `Mouse`
|
||||||
|
* is in a separate compilation unit.
|
||||||
|
*
|
||||||
|
* While it would have been cleaner and shorter to instantiate them here, and
|
||||||
|
* drop the global objects, that prevents optimizing them out, and that's a cost
|
||||||
|
* we do not want to pay.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MouseWrapper {
|
||||||
|
public:
|
||||||
|
MouseWrapper() {}
|
||||||
|
|
||||||
|
void begin() {
|
||||||
|
Mouse.begin();
|
||||||
|
}
|
||||||
|
void sendReport() {
|
||||||
|
Mouse.sendReport();
|
||||||
|
}
|
||||||
|
void move(int8_t x, int8_t y, int8_t vWheel, int8_t hWheel) {
|
||||||
|
Mouse.move(x, y, vWheel, hWheel);
|
||||||
|
}
|
||||||
|
void releaseAll() {
|
||||||
|
Mouse.releaseAll();
|
||||||
|
}
|
||||||
|
void press(uint8_t buttons) {
|
||||||
|
Mouse.press(buttons);
|
||||||
|
}
|
||||||
|
void release(uint8_t buttons) {
|
||||||
|
Mouse.release(buttons);
|
||||||
|
}
|
||||||
|
void click(uint8_t buttons) {
|
||||||
|
Mouse.click(buttons);
|
||||||
|
}
|
||||||
|
HID_MouseReport_Data_t getReport() {
|
||||||
|
return Mouse.getReport();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MouseProps: public base::MouseProps {
|
||||||
|
typedef MouseWrapper Mouse;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class Mouse: public base::Mouse<_Props> {};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue