From 22f20bfbfaffc8e83d258bd7297542306911b288 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 5 Apr 2019 09:43:29 +0200 Subject: [PATCH 1/3] Bootloader drivers The various keyboard plugins implemented a way to jump to the bootloader on their own. However, this is a bootloader-specific functionality, and as such, it makes sense to have a common implementation. This patch does just that. Signed-off-by: Gergely Nagy --- doc/driver/Bootloader.md | 68 ++++++ .../driver/bootloader/avr/Caterina.h | 57 +++++ .../driver/bootloader/avr/FLIP.cpp | 76 +++++++ src/kaleidoscope/driver/bootloader/avr/FLIP.h | 41 ++++ .../driver/bootloader/avr/HalfKay.h | 73 +++++++ src/kaleidoscope/hardware/ATMegaKeyboard.cpp | 198 ------------------ src/kaleidoscope/hardware/ATMegaKeyboard.h | 184 ++++++++++++++-- src/kaleidoscope/hardware/ez/ErgoDox.cpp | 34 --- src/kaleidoscope/hardware/ez/ErgoDox.h | 6 +- src/kaleidoscope/hardware/kbdfans/KBD4x.cpp | 23 -- src/kaleidoscope/hardware/kbdfans/KBD4x.h | 8 +- .../hardware/keyboardio/Model01.cpp | 21 -- .../hardware/keyboardio/Model01.h | 14 +- src/kaleidoscope/hardware/olkb/Planck.h | 7 +- .../hardware/softhruf/Splitography.h | 7 +- .../hardware/technomancy/Atreus.cpp | 36 ---- .../hardware/technomancy/Atreus.h | 8 +- 17 files changed, 520 insertions(+), 341 deletions(-) create mode 100644 doc/driver/Bootloader.md create mode 100644 src/kaleidoscope/driver/bootloader/avr/Caterina.h create mode 100644 src/kaleidoscope/driver/bootloader/avr/FLIP.cpp create mode 100644 src/kaleidoscope/driver/bootloader/avr/FLIP.h create mode 100644 src/kaleidoscope/driver/bootloader/avr/HalfKay.h delete mode 100644 src/kaleidoscope/hardware/ATMegaKeyboard.cpp diff --git a/doc/driver/Bootloader.md b/doc/driver/Bootloader.md new file mode 100644 index 0000000000..44ab0e02e5 --- /dev/null +++ b/doc/driver/Bootloader.md @@ -0,0 +1,68 @@ +# kaleidoscope::driver::bootloader + +We rarely have to work with or care about the bootloader from the user firmware, +but there's one scenario when we do: if we want to reset the device, and put it +into bootloader (programmable) mode, we need to do that in a bootloader-specific +manner. + +This driver provides a number of helpers that implement the reset functionality +for various bootloaders. + +## Using the driver + +To use the driver, we need to include the appropriate header, from the hardware plugin of +our keyboard: + +```c++ +#include +``` + +Next, we create a (private) member variable, based on the bootloader of our choice: + +```c++ +kaleidoscope::driver::bootloader::avr::Caterina bootloader_; +``` + +And then we can implement a thin wrapper for the bootloader's `resetDevice()` method: + +```c++ +void resetDevice() { + bootloader_.resetDevice(); +} +``` + +## Methods provided by all bootloader drivers + +### `.resetDevice()` + +> Resets the device, and forces it into bootloader (programmable) mode. + +## List of bootloaders + +All of the drivers below live below the `kaleidoscope::driver::bootloader` +namespace. + +## `avr::Caterina`: + +Used by many (most?) arduino MCUs. Provided by +`kaleidoscope/driver/bootloader/avr/Caterina.h`. + +### `avr::HalfKay` + +Used by the Teensy2. Provided by `kaleidoscope/driver/bootloader/avr/HalfKay.h`. + +### `avr::FLIP` + +Used by the ATMega32U4 MCUs by default, unless another bootloader has been +flashed on them. Provided by `kaleidoscope/driver/bootloader/avr/FLIP.h`. + +For this driver to work, one also needs to define the +`KALEIDOSCOPE_BOOTLOADER_FLIP` macro before including the driver header, for +technical reasons. + +## Notes + +When using the `ATMegaKeyboard` base class, there's no need to provide a +`resetDevice()` method, the base class does that for us. In this case, all that +is required is declaring a `bootloader_` protected member, of the appropriate +bootloader type. diff --git a/src/kaleidoscope/driver/bootloader/avr/Caterina.h b/src/kaleidoscope/driver/bootloader/avr/Caterina.h new file mode 100644 index 0000000000..6134f61ec8 --- /dev/null +++ b/src/kaleidoscope/driver/bootloader/avr/Caterina.h @@ -0,0 +1,57 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::bootloader::avr::Caterina -- Driver for the Caterina bootloader + * Copyright (C) 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 . + */ + +#pragma once + +#include + +namespace kaleidoscope { +namespace driver { +namespace bootloader { +namespace avr { + +class Caterina { + public: + Caterina() {} + + static void resetDevice() { + // Set the magic bits to get a Caterina-based device + // to reboot into the bootloader and stay there, rather + // than run move onward + // + // These values are the same as those defined in + // Caterina.c: + // https://github.com/arduino/ArduinoCore-avr/blob/5755ddea49fa69d6c505c772ebee5af5078e2ebf/bootloaders/caterina/Caterina.c#L130-L133 + + uint16_t bootKey = 0x7777; + uint16_t *const bootKeyPtr = reinterpret_cast(0x0800); + + // Stash the magic key + *bootKeyPtr = bootKey; + + // Set a watchdog timer + wdt_enable(WDTO_120MS); + + while (true) {} // This infinite loop ensures nothing else + // happens before the watchdog reboots us + } +}; + +} +} +} +} diff --git a/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp b/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp new file mode 100644 index 0000000000..e8b82faa4e --- /dev/null +++ b/src/kaleidoscope/driver/bootloader/avr/FLIP.cpp @@ -0,0 +1,76 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::bootloader::avr::FLIP -- Driver for the Atmel FLIP bootloader + * Copyright (C) 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 . + */ + +#include + +#ifdef KALEIDOSCOPE_BOOTLOADER_FLIP +#include "kaleidoscope/driver/bootloader/avr/FLIP.h" + +namespace kaleidoscope { +namespace driver { +namespace bootloader { +namespace avr { + +// The FLIP bootloader does not provide a way to boot into bootloader mode from +// within the firmware: it will always start the user firmware if available, and +// if the reset wasn't triggered by the physical reset button. To enter the +// bootloader mode, we need to jump there from the user firmware ourselves. +// +// Since we do not want to unconditionally jump into bootloader, we set a static +// memory address to a magic value, to signal our intention, then reboot via the +// watchdog timer. We need to reboot to clear registers and have a clean slate +// for the bootloader. +// +// For this to work, we need to run our signal checking code before `main()`, so +// we put the checker function into a special section that does that. +// +// Since this code cannot be optimized out on keyboards that use another +// bootloader, we need to guard this implementation with an ifdef (see above). +// +// For more information, see: +// http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html + +#define BOOTLOADER_RESET_KEY 0xB007B007 +static uint32_t reset_key __attribute__((section(".noinit"))); + +/* + * This function runs before main(), and jumps to the bootloader after a reset + * initiated by .resetDevice(). + */ +static void _bootloader_jump_after_watchdog_reset() +__attribute__((used, naked, section(".init3"))); +static void _bootloader_jump_after_watchdog_reset() { + if ((MCUSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { + reset_key = 0; + + ((void (*)(void))(((FLASHEND + 1L) - 4096) >> 1))(); + } +} + +void FLIP::resetDevice() { + reset_key = BOOTLOADER_RESET_KEY; + wdt_enable(WDTO_250MS); + while (true) {} // This infinite loop ensures nothing else + // happens before the watchdog reboots us +} + +} +} +} +} + +#endif diff --git a/src/kaleidoscope/driver/bootloader/avr/FLIP.h b/src/kaleidoscope/driver/bootloader/avr/FLIP.h new file mode 100644 index 0000000000..ad93556f2a --- /dev/null +++ b/src/kaleidoscope/driver/bootloader/avr/FLIP.h @@ -0,0 +1,41 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::bootloader::avr::FLIP -- Driver for the Atmel FLIP bootloader + * Copyright (C) 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 . + */ + +#pragma once + +#include + +#ifndef KALEIDOSCOPE_BOOTLOADER_FLIP +#error To use the FLIP bootloader driver, KALEIDOSCOPE_BOOTLOADER_FLIP *must* be defined prior to including this header! +#endif + +namespace kaleidoscope { +namespace driver { +namespace bootloader { +namespace avr { + +class FLIP { + public: + FLIP() {} + + static void resetDevice(); +}; + +} +} +} +} diff --git a/src/kaleidoscope/driver/bootloader/avr/HalfKay.h b/src/kaleidoscope/driver/bootloader/avr/HalfKay.h new file mode 100644 index 0000000000..e2ff4bc01f --- /dev/null +++ b/src/kaleidoscope/driver/bootloader/avr/HalfKay.h @@ -0,0 +1,73 @@ +/* -*- mode: c++ -*- + * kaleidoscope::driver::bootloader::avr::HalfKay -- Driver for the HalfKay bootloader + * Copyright (C) 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 . + */ + +#pragma once + +#include + +namespace kaleidoscope { +namespace driver { +namespace bootloader { +namespace avr { + +class HalfKay { + public: + HalfKay() {} + + // To reset a Teensy with the HalfKay bootloader, we need to disable all + // interrupts, all peripherals we have attached, USB, the watchdog timer, etc. + // Once done, we can jump to the bootloader address. + // + // Documentation: https://www.pjrc.com/teensy/jump_to_bootloader.html + static void resetDevice() { + cli(); + UDCON = 1; + USBCON = (1 << FRZCLK); + UCSR1B = 0; + _delay_ms(5); + + EIMSK = 0; + PCICR = 0; + SPCR = 0; + ACSR = 0; + EECR = 0; + ADCSRA = 0; + TIMSK0 = 0; + TIMSK1 = 0; + TIMSK3 = 0; + TIMSK4 = 0; + UCSR1B = 0; + TWCR = 0; + DDRB = 0; + DDRC = 0; + DDRD = 0; + DDRE = 0; + DDRF = 0; + TWCR = 0; + PORTB = 0; + PORTC = 0; + PORTD = 0; + PORTE = 0; + PORTF = 0; + asm volatile("jmp 0x7E00"); + } +}; + +} +} +} +} diff --git a/src/kaleidoscope/hardware/ATMegaKeyboard.cpp b/src/kaleidoscope/hardware/ATMegaKeyboard.cpp deleted file mode 100644 index fe866c444a..0000000000 --- a/src/kaleidoscope/hardware/ATMegaKeyboard.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* -*- mode: c++ -*- - * Kaleidoscope-Hardware-ATMegaKeyboard -- Base class for some ATMega-based boards - * Copyright (C) 2018 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 . - */ - -#include "Kaleidoscope.h" - -#if KALEIDOSCOPE_WITH_ATMEGA_KEYBOARD - -#include "kaleidoscope/hardware/ATMegaKeyboard.h" - -namespace kaleidoscope { -namespace hardware { - -bool ATMegaKeyboard::do_scan_; -uint8_t ATMegaKeyboard::debounce = 3; - -void ATMegaKeyboard::setup(void) { - wdt_disable(); - - for (uint8_t i = 0; i < KeyboardHardware.matrix_columns; i++) { - DDR_INPUT(KeyboardHardware.matrix_col_pins[i]); - ENABLE_PULLUP(KeyboardHardware.matrix_col_pins[i]); - } - - for (uint8_t i = 0; i < KeyboardHardware.matrix_rows; i++) { - DDR_OUTPUT(KeyboardHardware.matrix_row_pins[i]); - OUTPUT_HIGH(KeyboardHardware.matrix_row_pins[i]); - } - - /* Set up Timer1 for 1700usec */ - TCCR1B = _BV(WGM13); - TCCR1A = 0; - - const uint32_t cycles = (F_CPU / 2000000) * 1700; - - ICR1 = cycles; - TCCR1B = _BV(WGM13) | _BV(CS10); - TIMSK1 = _BV(TOIE1); -} - -void __attribute__((optimize(3))) ATMegaKeyboard::readMatrix(void) { - for (uint8_t current_row = 0; current_row < KeyboardHardware.matrix_rows; current_row++) { - uint16_t mask, cols; - - mask = KeyboardHardware.debounceMaskForRow(current_row); - - OUTPUT_TOGGLE(KeyboardHardware.matrix_row_pins[current_row]); - cols = (KeyboardHardware.readCols() & mask) | (KeyboardHardware.keyState_[current_row] & ~mask); - OUTPUT_TOGGLE(KeyboardHardware.matrix_row_pins[current_row]); - KeyboardHardware.debounceRow(cols ^ KeyboardHardware.keyState_[current_row], current_row); - KeyboardHardware.keyState_[current_row] = cols; - } -} - -uint8_t ATMegaKeyboard::pressedKeyswitchCount() { - uint8_t count = 0; - - for (int8_t r = 0; r < KeyboardHardware.matrix_rows; r++) { - count += __builtin_popcount(KeyboardHardware.keyState_[r]); - } - return count; -} - -bool ATMegaKeyboard::isKeyswitchPressed(KeyAddr key_addr) { - return (bitRead(KeyboardHardware.keyState_[key_addr.row()], key_addr.col()) != 0); -} - -bool ATMegaKeyboard::isKeyswitchPressed(uint8_t keyIndex) { - keyIndex--; - return isKeyswitchPressed(KeyAddr(keyIndex)); -} - - -uint8_t ATMegaKeyboard::previousPressedKeyswitchCount() { - uint8_t count = 0; - - for (int8_t r = 0; r < KeyboardHardware.matrix_rows; r++) { - count += __builtin_popcount(KeyboardHardware.previousKeyState_[r]); - } - return count; -} - -bool ATMegaKeyboard::wasKeyswitchPressed(KeyAddr key_addr) { - return (bitRead(KeyboardHardware.previousKeyState_[key_addr.row()], key_addr.col()) != 0); - -} - -bool ATMegaKeyboard::wasKeyswitchPressed(uint8_t keyIndex) { - keyIndex--; - return wasKeyswitchPressed(KeyAddr(keyIndex)); -} - - -void __attribute__((optimize(3))) ATMegaKeyboard::actOnMatrixScan() { - for (byte row = 0; row < KeyboardHardware.matrix_rows; row++) { - for (byte col = 0; col < KeyboardHardware.matrix_columns; col++) { - uint8_t keyState = (bitRead(KeyboardHardware.previousKeyState_[row], col) << 0) | - (bitRead(KeyboardHardware.keyState_[row], col) << 1); - if (keyState) { - handleKeyswitchEvent(Key_NoKey, KeyAddr(row, col), keyState); - } - } - KeyboardHardware.previousKeyState_[row] = KeyboardHardware.keyState_[row]; - } -} - -void ATMegaKeyboard::scanMatrix() { - if (do_scan_) { - do_scan_ = false; - // We only want to update our matrix if the timer has expired. - KeyboardHardware.readMatrix(); - } - // We ALWAYS want to tell Kaleidoscope about the state of the matrix - KeyboardHardware.actOnMatrixScan(); -} - -void ATMegaKeyboard::maskKey(KeyAddr key_addr) { - if (!key_addr.isValid()) - return; - - bitWrite(KeyboardHardware.masks_[key_addr.row()], key_addr.col(), 1); -} - -void ATMegaKeyboard::unMaskKey(KeyAddr key_addr) { - if (!key_addr.isValid()) - return; - - bitWrite(KeyboardHardware.masks_[key_addr.row()], key_addr.col(), 0); -} - -bool ATMegaKeyboard::isKeyMasked(KeyAddr key_addr) { - if (!key_addr.isValid()) - return false; - - return bitRead(KeyboardHardware.masks_[key_addr.row()], key_addr.col()); -} - -/* - * This function has loop unrolling disabled on purpose: we want to give the - * hardware enough time to produce stable PIN reads for us. If we unroll the - * loop, we will not have that, because even with the NOP, the codepath is too - * fast. If we don't have stable reads, then entire rows or columns will behave - * erratically. - * - * For this reason, we ask the compiler to not unroll our loop, which in turn, - * gives hardware enough time to produce stable reads, at the cost of a little - * bit of speed. - * - * Do not remove the attribute! - */ -__attribute__((optimize("no-unroll-loops"))) -uint16_t ATMegaKeyboard::readCols() { - uint16_t results = 0x00 ; - for (uint8_t i = 0; i < KeyboardHardware.matrix_columns; i++) { - asm("NOP"); // We need to pause a beat before reading or we may read before the pin is hot - results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[i]) << i); - } - return results; -} - -uint16_t ATMegaKeyboard::debounceMaskForRow(uint8_t row) { - uint16_t result = 0; - - for (uint16_t c = 0; c < KeyboardHardware.matrix_columns; ++c) { - if (KeyboardHardware.debounce_matrix_[row][c]) { - --KeyboardHardware.debounce_matrix_[row][c]; - } else { - result |= _BV(c); - } - } - return result; -} - -void ATMegaKeyboard::debounceRow(uint16_t change, uint8_t row) { - for (uint16_t i = 0; i < KeyboardHardware.matrix_columns; ++i) { - if (change & _BV(i)) { - KeyboardHardware.debounce_matrix_[row][i] = debounce; - } - } -} - -} -} - -#endif diff --git a/src/kaleidoscope/hardware/ATMegaKeyboard.h b/src/kaleidoscope/hardware/ATMegaKeyboard.h index 54cc51dda5..e7b4dc83f2 100644 --- a/src/kaleidoscope/hardware/ATMegaKeyboard.h +++ b/src/kaleidoscope/hardware/ATMegaKeyboard.h @@ -23,6 +23,9 @@ #include #include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h" #include "kaleidoscope/MatrixAddr.h" +#include "kaleidoscope/key_defs.h" +#include "kaleidoscope/key_events.h" +#include "kaleidoscope/hardware/key_indexes.h" #include "kaleidoscope/macro_helpers.h" #include "kaleidoscope/hardware/avr/pins_and_ports.h" @@ -67,59 +70,202 @@ struct cRGB { uint8_t BOARD::debounce_matrix_[matrix_rows][matrix_columns]; \ \ ISR(TIMER1_OVF_vect) { \ - BOARD::do_scan_ = true; \ + KeyboardHardware.do_scan_ = true; \ } namespace kaleidoscope { namespace hardware { +template class ATMegaKeyboard : public kaleidoscope::Hardware { public: ATMegaKeyboard(void) {} - static uint8_t debounce; + void setup(void) { + wdt_disable(); - void setup(void); - void readMatrix(void); - void actOnMatrixScan(); - void scanMatrix(); + for (uint8_t i = 0; i < derivedKeyboard_().matrix_columns; i++) { + DDR_INPUT(derivedKeyboard_().matrix_col_pins[i]); + ENABLE_PULLUP(derivedKeyboard_().matrix_col_pins[i]); + } - uint8_t pressedKeyswitchCount(); - bool isKeyswitchPressed(KeyAddr key_addr); + for (uint8_t i = 0; i < derivedKeyboard_().matrix_rows; i++) { + DDR_OUTPUT(derivedKeyboard_().matrix_row_pins[i]); + OUTPUT_HIGH(derivedKeyboard_().matrix_row_pins[i]); + } + + /* Set up Timer1 for 1700usec */ + TCCR1B = _BV(WGM13); + TCCR1A = 0; + + const uint32_t cycles = (F_CPU / 2000000) * 1700; + + ICR1 = cycles; + TCCR1B = _BV(WGM13) | _BV(CS10); + TIMSK1 = _BV(TOIE1); + } + + void __attribute__((optimize(3))) readMatrix(void) { + for (uint8_t current_row = 0; current_row < derivedKeyboard_().matrix_rows; current_row++) { + uint16_t mask, cols; + + mask = derivedKeyboard_().debounceMaskForRow(current_row); + + OUTPUT_TOGGLE(derivedKeyboard_().matrix_row_pins[current_row]); + cols = (derivedKeyboard_().readCols() & mask) | (derivedKeyboard_().keyState_[current_row] & ~mask); + OUTPUT_TOGGLE(derivedKeyboard_().matrix_row_pins[current_row]); + derivedKeyboard_().debounceRow(cols ^ derivedKeyboard_().keyState_[current_row], current_row); + derivedKeyboard_().keyState_[current_row] = cols; + } + } + + void __attribute__((optimize(3))) actOnMatrixScan() { + for (byte row = 0; row < derivedKeyboard_().matrix_rows; row++) { + for (byte col = 0; col < derivedKeyboard_().matrix_columns; col++) { + uint8_t keyState = (bitRead(derivedKeyboard_().previousKeyState_[row], col) << 0) | + (bitRead(derivedKeyboard_().keyState_[row], col) << 1); + if (keyState) { + handleKeyswitchEvent(Key_NoKey, KeyAddr(row, col), keyState); + } + } + derivedKeyboard_().previousKeyState_[row] = derivedKeyboard_().keyState_[row]; + } + } + + void scanMatrix() { + if (do_scan_) { + do_scan_ = false; + // We only want to update our matrix if the timer has expired. + derivedKeyboard_().readMatrix(); + } + // We ALWAYS want to tell Kaleidoscope about the state of the matrix + derivedKeyboard_().actOnMatrixScan(); + } + + uint8_t pressedKeyswitchCount() { + uint8_t count = 0; + + for (int8_t r = 0; r < derivedKeyboard_().matrix_rows; r++) { + count += __builtin_popcount(derivedKeyboard_().keyState_[r]); + } + return count; + } + bool isKeyswitchPressed(KeyAddr key_addr) { + return (bitRead(derivedKeyboard_().keyState_[key_addr.row()], key_addr.col()) != 0); + } DEPRECATED(ROW_COL_FUNC) bool isKeyswitchPressed(uint8_t row, byte col) { return isKeyswitchPressed(KeyAddr(row, col)); } - bool isKeyswitchPressed(uint8_t keyIndex); + bool isKeyswitchPressed(uint8_t keyIndex) { + keyIndex--; + return isKeyswitchPressed(KeyAddr(keyIndex)); + } - uint8_t previousPressedKeyswitchCount(); - bool wasKeyswitchPressed(KeyAddr key_addr); + uint8_t previousPressedKeyswitchCount() { + uint8_t count = 0; + + for (int8_t r = 0; r < derivedKeyboard_().matrix_rows; r++) { + count += __builtin_popcount(derivedKeyboard_().previousKeyState_[r]); + } + return count; + } + bool wasKeyswitchPressed(KeyAddr key_addr) { + return (bitRead(derivedKeyboard_().previousKeyState_[key_addr.row()], key_addr.col()) != 0); + } DEPRECATED(ROW_COL_FUNC) bool wasKeyswitchPressed(uint8_t row, byte col) { return wasKeyswitchPressed(KeyAddr(row, col)); } - bool wasKeyswitchPressed(uint8_t keyIndex); + bool wasKeyswitchPressed(uint8_t keyIndex) { + keyIndex--; + return wasKeyswitchPressed(KeyAddr(keyIndex)); + } + + void maskKey(KeyAddr key_addr) { + if (!key_addr.isValid()) + return; - void maskKey(KeyAddr key_addr); + bitWrite(derivedKeyboard_().masks_[key_addr.row()], key_addr.col(), 1); + } DEPRECATED(ROW_COL_FUNC) void maskKey(byte row, byte col) { maskKey(KeyAddr(row, col)); } - void unMaskKey(KeyAddr key_addr); + void unMaskKey(KeyAddr key_addr) { + if (!key_addr.isValid()) + return; + + bitWrite(derivedKeyboard_().masks_[key_addr.row()], key_addr.col(), 0); + } DEPRECATED(ROW_COL_FUNC) void unMaskKey(byte row, byte col) { unMaskKey(KeyAddr(row, col)); } - bool isKeyMasked(KeyAddr key_addr); + bool isKeyMasked(KeyAddr key_addr) { + if (!key_addr.isValid()) + return false; + + return bitRead(derivedKeyboard_().masks_[key_addr.row()], key_addr.col()); + } DEPRECATED(ROW_COL_FUNC) bool isKeyMasked(byte row, byte col) { return isKeyMasked(KeyAddr(row, col)); } - static bool do_scan_; + void resetDevice() { + derivedKeyboard_().bootloader_.resetDevice(); + } + + uint8_t debounce; + bool do_scan_; protected: kaleidoscope::driver::mcu::ATMega32U4 mcu_; + DerivedKeyboard__ &derivedKeyboard_() { + return static_cast(*this); + } private: - uint16_t readCols(); - uint16_t debounceMaskForRow(uint8_t row); - void debounceRow(uint16_t change, uint8_t row); + /* + * This function has loop unrolling disabled on purpose: we want to give the + * hardware enough time to produce stable PIN reads for us. If we unroll the + * loop, we will not have that, because even with the NOP, the codepath is too + * fast. If we don't have stable reads, then entire rows or columns will behave + * erratically. + * + * For this reason, we ask the compiler to not unroll our loop, which in turn, + * gives hardware enough time to produce stable reads, at the cost of a little + * bit of speed. + * + * Do not remove the attribute! + */ + __attribute__((optimize("no-unroll-loops"))) + uint16_t readCols() { + uint16_t results = 0x00 ; + for (uint8_t i = 0; i < derivedKeyboard_().matrix_columns; i++) { + asm("NOP"); // We need to pause a beat before reading or we may read before the pin is hot + results |= (!READ_PIN(derivedKeyboard_().matrix_col_pins[i]) << i); + } + return results; + } + + uint16_t debounceMaskForRow(uint8_t row) { + uint16_t result = 0; + + for (uint16_t c = 0; c < derivedKeyboard_().matrix_columns; ++c) { + if (derivedKeyboard_().debounce_matrix_[row][c]) { + --derivedKeyboard_().debounce_matrix_[row][c]; + } else { + result |= _BV(c); + } + } + return result; + } + + void debounceRow(uint16_t change, uint8_t row) { + for (uint16_t i = 0; i < derivedKeyboard_().matrix_columns; ++i) { + if (change & _BV(i)) { + derivedKeyboard_().debounce_matrix_[row][i] = debounce; + } + } + } + }; } } diff --git a/src/kaleidoscope/hardware/ez/ErgoDox.cpp b/src/kaleidoscope/hardware/ez/ErgoDox.cpp index 77852f36c0..e74399f787 100644 --- a/src/kaleidoscope/hardware/ez/ErgoDox.cpp +++ b/src/kaleidoscope/hardware/ez/ErgoDox.cpp @@ -168,40 +168,6 @@ void ErgoDox::setStatusLEDBrightness(uint8_t led, uint8_t brightness) { (OCR1C = brightness); } -void ErgoDox::resetDevice() { - cli(); - UDCON = 1; - USBCON = (1 << FRZCLK); - UCSR1B = 0; - _delay_ms(5); - - EIMSK = 0; - PCICR = 0; - SPCR = 0; - ACSR = 0; - EECR = 0; - ADCSRA = 0; - TIMSK0 = 0; - TIMSK1 = 0; - TIMSK3 = 0; - TIMSK4 = 0; - UCSR1B = 0; - TWCR = 0; - DDRB = 0; - DDRC = 0; - DDRD = 0; - DDRE = 0; - DDRF = 0; - TWCR = 0; - PORTB = 0; - PORTC = 0; - PORTD = 0; - PORTE = 0; - PORTF = 0; - asm volatile("jmp 0x7E00"); -} - - uint8_t ErgoDox::debounceMaskForRow(uint8_t row) { uint8_t result = 0; diff --git a/src/kaleidoscope/hardware/ez/ErgoDox.h b/src/kaleidoscope/hardware/ez/ErgoDox.h index 5e315d1893..2bc6066ed9 100644 --- a/src/kaleidoscope/hardware/ez/ErgoDox.h +++ b/src/kaleidoscope/hardware/ez/ErgoDox.h @@ -44,6 +44,7 @@ struct cRGB { #include "kaleidoscope/Hardware.h" #include "kaleidoscope/MatrixAddr.h" +#include "kaleidoscope/driver/bootloader/avr/HalfKay.h" namespace kaleidoscope { namespace hardware { @@ -98,11 +99,14 @@ class ErgoDox : public kaleidoscope::Hardware { void setStatusLED(uint8_t led, bool state = true); void setStatusLEDBrightness(uint8_t led, uint8_t brightness); - void resetDevice(); + void resetDevice() { + bootloader_.resetDevice(); + } static uint8_t debounce; private: + kaleidoscope::driver::bootloader::avr::HalfKay bootloader_; static ErgoDoxScanner scanner_; static uint8_t previousKeyState_[matrix_rows]; static uint8_t keyState_[matrix_rows]; diff --git a/src/kaleidoscope/hardware/kbdfans/KBD4x.cpp b/src/kaleidoscope/hardware/kbdfans/KBD4x.cpp index c6bf050706..ca6aaf1db9 100644 --- a/src/kaleidoscope/hardware/kbdfans/KBD4x.cpp +++ b/src/kaleidoscope/hardware/kbdfans/KBD4x.cpp @@ -29,29 +29,6 @@ namespace kbdfans { ATMEGA_KEYBOARD_DATA(KBD4x); constexpr int8_t KBD4x::led_count; -#define BOOTLOADER_RESET_KEY 0xB007B007 -uint32_t reset_key __attribute__((section(".noinit"))); - -/* - * This function runs before main(), and jumps to the bootloader after a reset - * initiated by .resetDevice(). - */ -void _bootloader_jump_after_watchdog_reset() -__attribute__((used, naked, section(".init3"))); -void _bootloader_jump_after_watchdog_reset() { - if ((MCUSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { - reset_key = 0; - - ((void (*)(void))(((FLASHEND + 1L) - 4096) >> 1))(); - } -} - -void KBD4x::resetDevice() { - reset_key = BOOTLOADER_RESET_KEY; - wdt_enable(WDTO_250MS); - for (;;); -} - } } } diff --git a/src/kaleidoscope/hardware/kbdfans/KBD4x.h b/src/kaleidoscope/hardware/kbdfans/KBD4x.h index b1c4a13c40..4acfd30a2d 100644 --- a/src/kaleidoscope/hardware/kbdfans/KBD4x.h +++ b/src/kaleidoscope/hardware/kbdfans/KBD4x.h @@ -27,11 +27,14 @@ #include "kaleidoscope/hardware/avr/pins_and_ports.h" #include "kaleidoscope/hardware/ATMegaKeyboard.h" +#define KALEIDOSCOPE_BOOTLOADER_FLIP 1 +#include "kaleidoscope/driver/bootloader/avr/FLIP.h" namespace kaleidoscope { namespace hardware { namespace kbdfans { -class KBD4x: public kaleidoscope::hardware::ATMegaKeyboard { +class KBD4x: public kaleidoscope::hardware::ATMegaKeyboard { + friend class ATMegaKeyboard; public: KBD4x(void) { mcu_.disableJTAG(); @@ -50,7 +53,8 @@ class KBD4x: public kaleidoscope::hardware::ATMegaKeyboard { return matrix_columns * matrix_rows; } - void resetDevice(); + protected: + kaleidoscope::driver::bootloader::avr::FLIP bootloader_; }; #define PER_KEY_DATA(dflt, \ diff --git a/src/kaleidoscope/hardware/keyboardio/Model01.cpp b/src/kaleidoscope/hardware/keyboardio/Model01.cpp index 68bc970de3..e863ecd282 100644 --- a/src/kaleidoscope/hardware/keyboardio/Model01.cpp +++ b/src/kaleidoscope/hardware/keyboardio/Model01.cpp @@ -207,27 +207,6 @@ void Model01::scanMatrix() { actOnMatrixScan(); } -void Model01::rebootBootloader() { - // Set the magic bits to get a Caterina-based device - // to reboot into the bootloader and stay there, rather - // than run move onward - // - // These values are the same as those defined in - // Caterina.c - - uint16_t bootKey = 0x7777; - uint16_t *const bootKeyPtr = reinterpret_cast(0x0800); - - // Stash the magic key - *bootKeyPtr = bootKey; - - // Set a watchdog timer - wdt_enable(WDTO_120MS); - - while (1) {} // This infinite loop ensures nothing else - // happens before the watchdog reboots us -} - // In the maskKey(), unMaskKey(), and isKeyMasked() functions, we read and write bits in // two bitfields -- one for each half of the keyboard. The fourth bit of the column number // tells us which bitfield (right or left) to access, thus the "8" (B00001000). The row diff --git a/src/kaleidoscope/hardware/keyboardio/Model01.h b/src/kaleidoscope/hardware/keyboardio/Model01.h index 6ffeb7a2bc..65be0d4a54 100644 --- a/src/kaleidoscope/hardware/keyboardio/Model01.h +++ b/src/kaleidoscope/hardware/keyboardio/Model01.h @@ -26,11 +26,17 @@ #include "KeyboardioScanner.h" #include "kaleidoscope/macro_helpers.h" +#include "kaleidoscope_internal/deprecations.h" #define CRGB(r,g,b) (cRGB){b, g, r} #include "kaleidoscope/Hardware.h" #include "kaleidoscope/MatrixAddr.h" +#include "kaleidoscope/driver/bootloader/avr/Caterina.h" + +#define _DEPRECATED_MESSAGE_MODEL01_REBOOT_BOOTLOADER \ + "Model01.rebootBootloader() is deprecated.\n" \ + "Please use KeyboardHardware.resetDevice() instead." namespace kaleidoscope { namespace hardware { @@ -65,7 +71,12 @@ class Model01 : public kaleidoscope::Hardware { void readMatrix(void); void actOnMatrixScan(void); void setup(); - void rebootBootloader(); + void rebootBootloader() DEPRECATED(MODEL01_REBOOT_BOOTLOADER) { + resetDevice(); + } + void resetDevice() { + bootloader_.resetDevice(); + } /* These public functions are things supported by the Model 01, but * aren't necessarily part of the Kaleidoscope API @@ -111,6 +122,7 @@ class Model01 : public kaleidoscope::Hardware { keydata_t previousRightHandState; private: + kaleidoscope::driver::bootloader::avr::Caterina bootloader_; static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos); static bool isLEDChanged; diff --git a/src/kaleidoscope/hardware/olkb/Planck.h b/src/kaleidoscope/hardware/olkb/Planck.h index 475402446b..04822f4220 100644 --- a/src/kaleidoscope/hardware/olkb/Planck.h +++ b/src/kaleidoscope/hardware/olkb/Planck.h @@ -27,11 +27,14 @@ #include "kaleidoscope/hardware/avr/pins_and_ports.h" #include "kaleidoscope/hardware/ATMegaKeyboard.h" +#define KALEIDOSCOPE_BOOTLOADER_FLIP 1 +#include "kaleidoscope/driver/bootloader/avr/FLIP.h" namespace kaleidoscope { namespace hardware { namespace olkb { -class Planck: public kaleidoscope::hardware::ATMegaKeyboard { +class Planck: public kaleidoscope::hardware::ATMegaKeyboard { + friend class ATMegaKeyboard; public: Planck(void) {} @@ -46,6 +49,8 @@ class Planck: public kaleidoscope::hardware::ATMegaKeyboard { static constexpr int8_t numKeys() { return matrix_columns * matrix_rows; } + protected: + kaleidoscope::driver::bootloader::avr::FLIP bootloader_; }; #define PER_KEY_DATA(dflt, \ diff --git a/src/kaleidoscope/hardware/softhruf/Splitography.h b/src/kaleidoscope/hardware/softhruf/Splitography.h index 1078a8a33d..54bc03326c 100644 --- a/src/kaleidoscope/hardware/softhruf/Splitography.h +++ b/src/kaleidoscope/hardware/softhruf/Splitography.h @@ -34,11 +34,14 @@ #include "kaleidoscope/hardware/avr/pins_and_ports.h" #include "kaleidoscope/hardware/ATMegaKeyboard.h" +#define KALEIDOSCOPE_BOOTLOADER_FLIP 1 +#include "kaleidoscope/driver/bootloader/avr/FLIP.h" namespace kaleidoscope { namespace hardware { namespace softhruf { -class Splitography: public kaleidoscope::hardware::ATMegaKeyboard { +class Splitography: public kaleidoscope::hardware::ATMegaKeyboard { + friend class ATMegaKeyboard; public: Splitography(void) { mcu_.disableJTAG(); @@ -55,6 +58,8 @@ class Splitography: public kaleidoscope::hardware::ATMegaKeyboard { static constexpr int8_t numKeys() { return matrix_columns * matrix_rows; } + protected: + kaleidoscope::driver::bootloader::avr::FLIP bootloader_; }; #define PER_KEY_DATA(dflt, \ diff --git a/src/kaleidoscope/hardware/technomancy/Atreus.cpp b/src/kaleidoscope/hardware/technomancy/Atreus.cpp index 61a7c375c2..520e59aa3d 100644 --- a/src/kaleidoscope/hardware/technomancy/Atreus.cpp +++ b/src/kaleidoscope/hardware/technomancy/Atreus.cpp @@ -36,42 +36,6 @@ namespace technomancy { ATMEGA_KEYBOARD_DATA(Atreus); constexpr int8_t Atreus::led_count; -// Atreus-specific stuff - -void Atreus::resetDevice() { - cli(); - UDCON = 1; - USBCON = (1 << FRZCLK); - UCSR1B = 0; - _delay_ms(5); - - EIMSK = 0; - PCICR = 0; - SPCR = 0; - ACSR = 0; - EECR = 0; - ADCSRA = 0; - TIMSK0 = 0; - TIMSK1 = 0; - TIMSK3 = 0; - TIMSK4 = 0; - UCSR1B = 0; - TWCR = 0; - DDRB = 0; - DDRC = 0; - DDRD = 0; - DDRE = 0; - DDRF = 0; - TWCR = 0; - PORTB = 0; - PORTC = 0; - PORTD = 0; - PORTE = 0; - PORTF = 0; - asm volatile("jmp 0x7E00"); -} - - } } } diff --git a/src/kaleidoscope/hardware/technomancy/Atreus.h b/src/kaleidoscope/hardware/technomancy/Atreus.h index 4e5fb4777e..d044800881 100644 --- a/src/kaleidoscope/hardware/technomancy/Atreus.h +++ b/src/kaleidoscope/hardware/technomancy/Atreus.h @@ -33,12 +33,13 @@ #include "kaleidoscope/macro_helpers.h" #include "kaleidoscope/hardware/ATMegaKeyboard.h" +#include "kaleidoscope/driver/bootloader/avr/HalfKay.h" namespace kaleidoscope { namespace hardware { namespace technomancy { -class Atreus: public kaleidoscope::hardware::ATMegaKeyboard { - friend class ATMegaKeyboard; +class Atreus: public kaleidoscope::hardware::ATMegaKeyboard { + friend class ATMegaKeyboard; public: Atreus(void) {} @@ -70,9 +71,8 @@ class Atreus: public kaleidoscope::hardware::ATMegaKeyboard { return matrix_columns * matrix_rows; } - void resetDevice(); - protected: + kaleidoscope::driver::bootloader::avr::HalfKay bootloader_; }; #define PER_KEY_DATA(dflt, \ From 1d22c9993fe6daf0d6063c3c9127a4b96893097f Mon Sep 17 00:00:00 2001 From: JD Lien Date: Sat, 20 Jul 2019 00:50:39 -0600 Subject: [PATCH 2/3] Added keygroups.h Keygroups.h has been added to offer functions that allow determining if a given key is in a certain group. Signed-off-by: JD Lien --- src/kaleidoscope/keygroups.h | 192 +++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 src/kaleidoscope/keygroups.h diff --git a/src/kaleidoscope/keygroups.h b/src/kaleidoscope/keygroups.h new file mode 100644 index 0000000000..beb4e6a907 --- /dev/null +++ b/src/kaleidoscope/keygroups.h @@ -0,0 +1,192 @@ +#include "Kaleidoscope-MouseKeys.h" +/* + * keygroups.h provides functions that can be used at compile-time to evaluate whether a + * Key constant is in a certain major grouping. This is used by plugins like FunctionalColor + * to color keys by the group that they are in. + */ + +//Alphabetical keys A-Z +inline constexpr bool isAlpha(const Key& k) { + return ( k.flags == KEY_FLAGS && (k.keyCode >= (Key_A).keyCode) && (k.keyCode <= (Key_Z).keyCode) )?true:false; +} + +//Number keys 1-9, 0 +inline constexpr bool isNumber(const Key& k) { + return ( k.flags == KEY_FLAGS && (k.keyCode >= (Key_1).keyCode) && (k.keyCode <= (Key_0).keyCode) )?true:false; +} + +// enter, escape, delete, tab, spacebar, all have no group + +//minus, equals, brackets, backslash, pound, semicolon, quote, grave accent, comma, period, slash +inline constexpr bool isPunctuation(const Key& k) { + return ( (k.keyCode == (Key_LeftCurlyBracket).keyCode && k.flags == (Key_LeftCurlyBracket).flags) || + (k.keyCode == (Key_RightCurlyBracket).keyCode && k.flags == (Key_RightCurlyBracket).flags) || + (k.keyCode == (Key_LeftParen).keyCode && k.flags == (Key_LeftParen).flags) || + (k.keyCode == (Key_RightParen).keyCode && k.flags == (Key_RightParen).flags) || + (k.keyCode == (Key_Pipe).keyCode && k.flags == (Key_Pipe).flags) || + (k.flags == KEY_FLAGS && + (k.keyCode == (Key_International1).keyCode || //Brazilian forward-slash (/) and question-mark (?) key + k.keyCode == (Key_NonUsBackslashAndPipe).keyCode || + ((k.keyCode >= (Key_Minus).keyCode) && (k.keyCode <= (Key_Slash).keyCode))) ) + )?true:false; +} + +// capslock has no group +//F1 through F24, which are split into two groups +inline constexpr bool isFunction(const Key& k) { + return ( k.flags == KEY_FLAGS && + (((k.keyCode >= (Key_F1).keyCode) && (k.keyCode <= (Key_F12).keyCode)) || + ((k.keyCode >= (Key_F13).keyCode) && (k.keyCode <= (Key_F24).keyCode))) + )?true:false; +} + +// printscreen, scrolllock, pause, insert + +//nav cluster: insert, home, end, delete_forward, pageup, pagedown +// I don't know if insert and delete "fit" here, but they do get clustered together on traditional keyboards +inline constexpr bool isNavigation(const Key& k) { + return (k.flags == KEY_FLAGS && (k.keyCode >= (Key_Insert).keyCode) && (k.keyCode <= (Key_PageDown).keyCode))?true:false; +} + +//right, left, down, up +inline constexpr bool isArrow(const Key& k) { + return (k.flags == KEY_FLAGS && (k.keyCode >= (Key_RightArrow).keyCode) && (k.keyCode <= (Key_UpArrow).keyCode))?true:false; +} + +//All keypad keys including numbers, and mathemetical operators. +//There's another group of more obscure keypad keys that are unused so they don't interfere with consumer keys +// ((k.keyCode >= (Key_Keypad00).keyCode) && (k.keyCode <= (Key_KeypadHexadecimal).keyCode)) +inline constexpr bool isKeypad(const Key& k) { + return ( k.flags == KEY_FLAGS && ( + k.keyCode == (Key_KeypadEquals).keyCode || + k.keyCode == (Key_KeypadComma).keyCode || + k.keyCode == (Key_KeypadEqualSign).keyCode || + ((k.keyCode >= (Key_KeypadNumLock).keyCode) && (k.keyCode <= (Key_KeypadDot).keyCode)) || + ((k.keyCode >= (Key_Keypad00).keyCode) && (k.keyCode <= (Key_KeypadHexadecimal).keyCode)) + ) + )?true:false; +} + +// System keys like Pause/Break, Print Screen, and scroll lock +inline constexpr bool isSystem(const Key& k) { + return ( k.flags == KEY_FLAGS && ( + k.keyCode == (Key_PrintScreen).keyCode || + k.keyCode == (Key_ScrollLock).keyCode || + k.keyCode == (Key_Pause).keyCode + ) + )?true:false; +} + +//Media keys used on some keyboards with extra buttons, as well as all the consumer control keys +//includes, execute, help, menu, select, stop, again, undo, cut, copy, paste, find, mute, volup, voldn +// #define HID_CONSUMER_PLAY 0xB0 // HID type OOC +// #define HID_CONSUMER_PAUSE 0xB1 // HID type OOC +// #define HID_CONSUMER_RECORD 0xB2 // HID type OOC +// #define HID_CONSUMER_FAST_FORWARD 0xB3 // HID type OOC +// #define HID_CONSUMER_REWIND 0xB4 // HID type OOC +// #define HID_CONSUMER_SCAN_NEXT_TRACK 0xB5 // HID type OSC +// #define HID_CONSUMER_SCAN_PREVIOUS_TRACK 0xB6 // HID type OSC +// #define HID_CONSUMER_STOP 0xB7 // HID type OSC +// #define HID_CONSUMER_EJECT 0xB8 // HID type OSC +// #define HID_CONSUMER_RANDOM_PLAY 0xB9 // HID type OOC + +// #define HID_CONSUMER_PLAY_SLASH_PAUSE 0xCD // HID type OSC + +// //Mute happens to be the same code as left alt. Hmm. +// #define HID_CONSUMER_MUTE 0xE2 // HID type OOC + +// #define HID_CONSUMER_VOLUME_INCREMENT 0xE9 // HID type RTC +// #define HID_CONSUMER_VOLUME_DECREMENT 0xEA // HID type RTC +inline constexpr bool isMedia(const Key& k) { + return ( + (k.flags == KEY_FLAGS && (k.keyCode >= (Key_Execute).keyCode) && (k.keyCode <= (Key_VolumeDown).keyCode)) || + (k.keyCode == (Consumer_ScanPreviousTrack).keyCode && k.flags == (Consumer_ScanPreviousTrack).flags)|| + (k.keyCode == (Consumer_ScanNextTrack).keyCode && k.flags == (Consumer_ScanNextTrack).flags)|| + (k.keyCode == (Consumer_PlaySlashPause).keyCode && k.flags == (Consumer_PlaySlashPause).flags)|| + (k.keyCode == (Consumer_Play).keyCode && k.flags == (Consumer_Play).flags)|| + (k.keyCode == (Consumer_Pause).keyCode && k.flags == (Consumer_Pause).flags)|| + (k.keyCode == (Consumer_Stop).keyCode && k.flags == (Consumer_Stop).flags)|| + (k.flags == (Consumer_VolumeIncrement).flags && k.keyCode == (Consumer_VolumeIncrement).keyCode) || + (k.flags == (Consumer_VolumeDecrement).flags && k.keyCode == (Consumer_VolumeDecrement).keyCode) || + (k.keyCode == (Consumer_Mute).keyCode && k.flags == (Consumer_Mute).flags) + )?true:false; +} + +// Lang keys used primarily for Asian language character set switching +inline constexpr bool isLang(const Key& k) { + return (k.flags == KEY_FLAGS && + (k.keyCode >= (Key_Lang1).keyCode) && (k.keyCode <= (Key_Lang9).keyCode) )?true:false; +} + +//Here I will have some groups that have subgroups... +//Control, shift, alt, gui (windows/command), and application (menu) key +inline constexpr bool isModifier(const Key& k) { + return ( k.flags == KEY_FLAGS && + (k.keyCode == (Key_PcApplication).keyCode || + ((k.keyCode >= (Key_LeftControl).keyCode) && (k.keyCode <= (Key_RightGui).keyCode))) )?true:false; +} + +//Keys that are subgroups of Modifier keys +inline constexpr bool isShift(const Key& k) { + return ( k.flags == KEY_FLAGS && + (k.keyCode == (Key_LeftShift).keyCode || (k.keyCode == (Key_RightShift).keyCode) ) )?true:false; +} + +inline constexpr bool isControl(const Key& k) { + return ( k.flags == KEY_FLAGS && + (k.keyCode == (Key_LeftControl).keyCode || (k.keyCode == (Key_RightControl).keyCode) ) )?true:false; +} + +inline constexpr bool isGui(const Key& k) { + return ( k.flags == KEY_FLAGS && + (k.keyCode == (Key_LeftGui).keyCode || (k.keyCode == (Key_RightGui).keyCode) ) )?true:false; +} + +inline constexpr bool isAlt(const Key& k) { + return ( k.flags == KEY_FLAGS && + (k.keyCode == (Key_LeftAlt).keyCode || (k.keyCode == (Key_RightAlt).keyCode) ) )?true:false; +} + +// The groups below require Kaleidoscope-MouseKeys.h. Perhaps compiler flags could be used +// to skip this final section if MouseKeys was not included as many users may not need this. +// All mouse keys. This technique seems to get some false positives (prog & led keys) +inline constexpr bool isMouseMove(const Key& k) { + return ( ((Key_mouseUpL).flags == k.flags && (Key_mouseUpL).keyCode == k.keyCode) || + ((Key_mouseUp).flags == k.flags && (Key_mouseUp).keyCode == k.keyCode) || + ((Key_mouseUpR).flags == k.flags && (Key_mouseUpR).keyCode == k.keyCode) || + ((Key_mouseL).flags == k.flags && (Key_mouseL).keyCode == k.keyCode) || + ((Key_mouseR).flags == k.flags && (Key_mouseR).keyCode == k.keyCode) || + ((Key_mouseDnL).flags == k.flags && (Key_mouseDnL).keyCode == k.keyCode) || + ((Key_mouseDn).flags == k.flags && (Key_mouseDn).keyCode == k.keyCode) || + ((Key_mouseDnR).flags == k.flags && (Key_mouseDnR).keyCode == k.keyCode) + )?true:false; +} + +// Mouse keys that are for the mouse wheel. L & R scroll wheel don't seem to work. +inline constexpr bool isMouseWheel(const Key& k) { + return ( ((Key_mouseScrollUp).flags == k.flags && (Key_mouseScrollUp).keyCode == k.keyCode) || + ((Key_mouseScrollDn).flags == k.flags && (Key_mouseScrollDn).keyCode == k.keyCode) + )?true:false; +} + +// Mouse keys that are for the mouse buttons +inline constexpr bool isMouseButton(const Key& k) { + return ( ((Key_mouseBtnL).flags == k.flags && (Key_mouseBtnL).keyCode == k.keyCode) || + ((Key_mouseBtnM).flags == k.flags && (Key_mouseBtnM).keyCode == k.keyCode) || + ((Key_mouseBtnR).flags == k.flags && (Key_mouseBtnR).keyCode == k.keyCode) + )?true:false; +} + +// Mouse keys that warp the mouse pointer +inline constexpr bool isMouseWarp(const Key& k) { + return ( ((Key_mouseWarpNW).flags == k.flags && (Key_mouseWarpNW).keyCode == k.keyCode) || + ((Key_mouseWarpNE).flags == k.flags && (Key_mouseWarpNE).keyCode == k.keyCode) || + ((Key_mouseWarpSW).flags == k.flags && (Key_mouseWarpSW).keyCode == k.keyCode) || + ((Key_mouseWarpSE).flags == k.flags && (Key_mouseWarpSE).keyCode == k.keyCode) || + ((Key_mouseWarpEnd).flags == k.flags && (Key_mouseWarpEnd).keyCode == k.keyCode) + )?true:false; +} + +inline constexpr bool isMouse(const Key& k) { + return (isMouseMove(k) || isMouseWheel(k) || isMouseButton(k) || isMouseWarp(k)); +} From b0a9e00c9682ad4936cd12d9322b9aee81d81c78 Mon Sep 17 00:00:00 2001 From: JD Lien Date: Sat, 20 Jul 2019 09:17:48 -0600 Subject: [PATCH 3/3] Added to kaleidoscope namespace Signed-off-by: JD Lien --- src/kaleidoscope/keygroups.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kaleidoscope/keygroups.h b/src/kaleidoscope/keygroups.h index beb4e6a907..9c599b6b91 100644 --- a/src/kaleidoscope/keygroups.h +++ b/src/kaleidoscope/keygroups.h @@ -5,6 +5,8 @@ * to color keys by the group that they are in. */ +namespace kaleidoscope { + //Alphabetical keys A-Z inline constexpr bool isAlpha(const Key& k) { return ( k.flags == KEY_FLAGS && (k.keyCode >= (Key_A).keyCode) && (k.keyCode <= (Key_Z).keyCode) )?true:false; @@ -190,3 +192,5 @@ inline constexpr bool isMouseWarp(const Key& k) { inline constexpr bool isMouse(const Key& k) { return (isMouseMove(k) || isMouseWheel(k) || isMouseButton(k) || isMouseWarp(k)); } + +}//namespace kaleidoscope