Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hybrid boot keyboard #1361

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions plugins/Kaleidoscope-USB-Quirks/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# USB-Quirks

USB-Quirks provides a few methods to deal with more obscure parts of the USB spec, such as changing between `Boot` and `Report` protocols. These are in a separate plugin, because these features are not part of the USB spec, and are often workarounds for various issues. See the provided methods for more information about what they're useful for.
USB-Quirks provides a few methods to deal with more obscure parts of the USB spec, such as changing the behavior around the boot protocol. These are in a separate plugin, because these features are not part of the USB spec, and are often workarounds for various issues. See the provided methods for more information about what they're useful for.

## Using the plugin

Expand Down Expand Up @@ -29,11 +29,32 @@ The plugin provides one object, `USBQuirks`, which provides the following method

### `.toggleKeyboardProtocol()`

> Toggle between `Boot` and `Report` protocol by detaching, and then
> re-attaching the USB devices, and setting the `BootKeyboard` protocol
> in between.
> Toggle whether the keyboard is able to send extended key reports (the
> default), or instead always sends boot reports, regardless of the
> protocol requested by the host. Switching the toggle causes the keyboard
> to detach and then re-attach to the host. (This re-attach is necessary to
> force re-enumeration with a different Report Descriptor.)
>
> This is most useful when one needs to have a boot keyboard, when one's in a
> BIOS, boot loader, or early password prompt or the like, and the host does not
> explicitly request the boot protocol for one reason or the other. With this
> toggle, we can switch between the two on-demand.
> Switching the toggle also lights up a key indicating the mode being
> switched to: by default, `B` for boot reports only, and `N` for extended
> reports enabled.
>
> The extended key report supports n-key rollover (NKRO), and is actually a
> hybrid, having a prefix containing the boot report, for compatibility
> with older hosts. The boot report only supports 6-key rollover (6KRO),
> and is meant to support constrained hosts, such as BIOS, UEFI, or other
> pre-boot environments. The keyboard changes protocols as requested by the
> host.
>
> The USB HID specification requires that hosts explicitly request boot
> protocol if they need it, and that devices default to the non-boot
> protocol. Some hosts do not follow the specification, and expect boot
> protocol, even without requesting it. The backwards compatibility prefix
> of the hybrid extended report should accommodate some of these hosts.
> This toggle helps to work with hosts that neither request boot protocol
> nor tolerate the longer hybrid report.

### `.setKeys(Key boot_led, Key nkro_led)`

> Set which keys to light up to indicate the target mode. Defaults to
> `(Key_B, Key_N)`.
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,62 @@
#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
#include "kaleidoscope/device/device.h" // for Base<>::HID, VirtualProps::HID
#include "kaleidoscope/driver/hid/keyboardio/Keyboard.h" // for Keyboard
#include "kaleidoscope/key_defs.h" // for Key
#include "kaleidoscope/plugin/LEDControl.h" // for LEDControl

namespace kaleidoscope {
namespace plugin {

KeyAddr USBQuirks::key_boot_addr = KeyAddr::none();
KeyAddr USBQuirks::key_nkro_addr = KeyAddr::none();

static KeyAddr findKey(Key search_key) {
for (auto key_addr : KeyAddr::all()) {
Key k = Layer.lookupOnActiveLayer(key_addr);

if (k == search_key) {
return key_addr;
}
}
return KeyAddr::none();
}

void USBQuirks::setKeys(Key boot_led, Key nkro_led) {
key_boot_addr = findKey(boot_led);
key_nkro_addr = findKey(nkro_led);
}

EventHandlerResult USBQuirks::onSetup() {
setKeys(Key_B, Key_N);
return EventHandlerResult::OK;
}

void USBQuirks::toggleKeyboardProtocol() {
uint8_t new_protocol = !Runtime.hid().keyboard().getProtocol();
KeyAddr key_addr;
uint8_t new_bootonly = !Runtime.hid().keyboard().getBootOnly();

if (new_bootonly) {
key_addr = key_boot_addr;
} else {
key_addr = key_nkro_addr;
}
::LEDControl.disable();
if (key_addr.isValid()) {
::LEDControl.setCrgbAt(key_addr, CRGB(0, 0, 255));
}
Runtime.device().syncLeds();
/*
* Release keys, because after detach, Windows 10 remembers keys that
* were pressed (from the MagicCombo that activated this function).
*/
Runtime.hid().keyboard().releaseAllKeys();
Runtime.hid().keyboard().sendReport();
delay(10);
Runtime.detachFromHost();
Runtime.hid().keyboard().setDefaultProtocol(new_protocol);
Runtime.hid().keyboard().setBootOnly(new_bootonly);
delay(1000);
::LEDControl.set_all_leds_to(CRGB(0, 0, 0));
::LEDControl.enable();
Runtime.attachToHost();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@

#pragma once

#include "kaleidoscope/plugin.h" // for Plugin
#include "kaleidoscope/KeyAddr.h" // for KeyAddr
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult
#include "kaleidoscope/key_defs.h" // for Key
#include "kaleidoscope/plugin.h" // for Plugin

namespace kaleidoscope {
namespace plugin {
class USBQuirks : public kaleidoscope::Plugin {
public:
void toggleKeyboardProtocol();
EventHandlerResult onSetup();
static void setKeys(Key boot_led, Key nkro_led);

private:
static KeyAddr key_boot_addr;
static KeyAddr key_nkro_addr;
};

} // namespace plugin
Expand Down
Loading
Loading