From 0e984b6e7e216a62df0b5d53f6a8f0d4bc13dca3 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Mon, 1 Mar 2021 08:57:02 -0800 Subject: Add ability to toggle One Shot functionality (#4198) Co-authored-by: Nick Brassel Co-authored-by: Ryan --- tmk_core/common/action_util.c | 58 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 9 deletions(-) (limited to 'tmk_core/common/action_util.c') diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c index 000503b082..a57c8bf66a 100644 --- a/tmk_core/common/action_util.c +++ b/tmk_core/common/action_util.c @@ -147,12 +147,16 @@ void clear_oneshot_swaphands(void) { * FIXME: needs doc */ void set_oneshot_layer(uint8_t layer, uint8_t state) { - oneshot_layer_data = layer << 3 | state; - layer_on(layer); + if (!keymap_config.oneshot_disable) { + oneshot_layer_data = layer << 3 | state; + layer_on(layer); # if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_layer_time = timer_read(); + oneshot_layer_time = timer_read(); # endif - oneshot_layer_changed_kb(get_oneshot_layer()); + oneshot_layer_changed_kb(get_oneshot_layer()); + } else { + layer_on(layer); + } } /** \brief Reset oneshot layer * @@ -172,7 +176,7 @@ void reset_oneshot_layer(void) { void clear_oneshot_layer_state(oneshot_fullfillment_t state) { uint8_t start_state = oneshot_layer_data; oneshot_layer_data &= ~state; - if (!get_oneshot_layer_state() && start_state != oneshot_layer_data) { + if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) || keymap_config.oneshot_disable) { layer_off(get_oneshot_layer()); reset_oneshot_layer(); } @@ -182,6 +186,39 @@ void clear_oneshot_layer_state(oneshot_fullfillment_t state) { * FIXME: needs doc */ bool is_oneshot_layer_active(void) { return get_oneshot_layer_state(); } + +/** \brief set oneshot + * + * FIXME: needs doc + */ +void oneshot_set(bool active) { + if (keymap_config.oneshot_disable != active) { + keymap_config.oneshot_disable = active; + eeconfig_update_keymap(keymap_config.raw); + dprintf("Oneshot: active: %d\n", active); + } +} + +/** \brief toggle oneshot + * + * FIXME: needs doc + */ +void oneshot_toggle(void) { oneshot_set(!keymap_config.oneshot_disable); } + +/** \brief enable oneshot + * + * FIXME: needs doc + */ +void oneshot_enable(void) { oneshot_set(true); } + +/** \brief disable oneshot + * + * FIXME: needs doc + */ +void oneshot_disable(void) { oneshot_set(false); } + +bool is_oneshot_enabled(void) { return keymap_config.oneshot_disable; } + #endif /** \brief Send keyboard report @@ -321,14 +358,17 @@ void del_oneshot_mods(uint8_t mods) { * FIXME: needs doc */ void set_oneshot_mods(uint8_t mods) { - if (oneshot_mods != mods) { + if (!keymap_config.oneshot_disable) { + if (oneshot_mods != mods) { # if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_time = timer_read(); + oneshot_time = timer_read(); # endif - oneshot_mods = mods; - oneshot_mods_changed_kb(mods); + oneshot_mods = mods; + oneshot_mods_changed_kb(mods); + } } } + /** \brief clear oneshot mods * * FIXME: needs doc -- cgit v1.2.3 From 52cfc9259b58a3a11a244fbe35c49c7dd1a9cae0 Mon Sep 17 00:00:00 2001 From: Jonas Gessner Date: Tue, 13 Jul 2021 19:13:51 +0200 Subject: [Feature] Key Overrides (#11422) --- common_features.mk | 5 + docs/_summary.md | 1 + docs/config_options.md | 4 + docs/feature_key_overrides.md | 229 +++++++++ docs/syllabus.md | 1 + docs/understanding_qmk.md | 1 + quantum/process_keycode/process_key_override.c | 518 +++++++++++++++++++++ quantum/process_keycode/process_key_override.h | 147 ++++++ .../process_keycode/process_key_override_private.h | 24 + quantum/quantum.c | 19 +- quantum/quantum.h | 4 + quantum/quantum_keycodes.h | 5 + show_options.mk | 1 + tmk_core/common/action_util.c | 28 ++ 14 files changed, 984 insertions(+), 3 deletions(-) create mode 100644 docs/feature_key_overrides.md create mode 100644 quantum/process_keycode/process_key_override.c create mode 100644 quantum/process_keycode/process_key_override.h create mode 100644 quantum/process_keycode/process_key_override_private.h (limited to 'tmk_core/common/action_util.c') diff --git a/common_features.mk b/common_features.mk index 8080113efd..74b94ecd77 100644 --- a/common_features.mk +++ b/common_features.mk @@ -335,6 +335,11 @@ ifeq ($(strip $(PRINTING_ENABLE)), yes) SRC += $(TMK_DIR)/protocol/serial_uart.c endif +ifeq ($(strip $(KEY_OVERRIDE_ENABLE)), yes) + OPT_DEFS += -DKEY_OVERRIDE_ENABLE + SRC += $(QUANTUM_DIR)/process_keycode/process_key_override.c +endif + ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes) SERIAL_SRC := $(wildcard $(SERIAL_PATH)/protocol/*.c) SERIAL_SRC += $(wildcard $(SERIAL_PATH)/system/*.c) diff --git a/docs/_summary.md b/docs/_summary.md index 4141e01e77..6c39aeda09 100644 --- a/docs/_summary.md +++ b/docs/_summary.md @@ -77,6 +77,7 @@ * [Combos](feature_combo.md) * [Debounce API](feature_debounce_type.md) * [Key Lock](feature_key_lock.md) + * [Key Overrides](feature_key_overrides.md) * [Layers](feature_layers.md) * [One Shot Keys](one_shot_keys.md) * [Pointing Device](feature_pointing_device.md) diff --git a/docs/config_options.md b/docs/config_options.md index 980195ac68..0c98b31010 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -195,6 +195,8 @@ If you define these options you will enable the associated feature, which may in * Sets the delay between `register_code` and `unregister_code`, if you're having issues with it registering properly (common on VUSB boards). The value is in milliseconds. * `#define TAP_HOLD_CAPS_DELAY 80` * Sets the delay for Tap Hold keys (`LT`, `MT`) when using `KC_CAPSLOCK` keycode, as this has some special handling on MacOS. The value is in milliseconds, and defaults to 80 ms if not defined. For macOS, you may want to set this to 200 or higher. +* `#define KEY_OVERRIDE_REPEAT_DELAY 500` + * Sets the key repeat interval for [key overrides](feature_key_overrides.md). ## RGB Light Configuration @@ -400,6 +402,8 @@ Use these to enable or disable building certain features. The more you have enab * USB N-Key Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work * `AUDIO_ENABLE` * Enable the audio subsystem. +* `KEY_OVERRIDE_ENABLE` + * Enable the key override feature * `RGBLIGHT_ENABLE` * Enable keyboard underlight functionality * `LEADER_ENABLE` diff --git a/docs/feature_key_overrides.md b/docs/feature_key_overrides.md new file mode 100644 index 0000000000..861c4bef5d --- /dev/null +++ b/docs/feature_key_overrides.md @@ -0,0 +1,229 @@ +# Key Overrides + +Key overrides allow you to override modifier-key combinations to send a different modifier-key combination or perform completely custom actions. Don't want `shift` + `1` to type `!` on your computer? Use a key override to make your keyboard type something different when you press `shift` + `1`. The general behavior is like this: If `modifiers w` + `key x` are pressed, replace these keys with `modifiers y` + `key z` in the keyboard report. + +You can use key overrides in a similar way to momentary layer/fn keys to activate custom keycodes/shortcuts, with a number of benefits: You completely keep the original use of the modifier keys, while being able to save space by removing fn keys from your keyboard. You can also easily configure _combinations of modifiers_ to trigger different actions than individual modifiers, and much more. The possibilities are quite vast and this documentation contains a few examples for inspiration throughout. + +##### A few more examples to get started: You could use key overrides to... +- Send `brightness up/down` when pressing `ctrl` + `volume up/down`. +- Send `delete` when pressing `shift` + `backspace`. +- Create custom shortcuts or change existing ones: E.g. Send `ctrl`+`shift`+`z` when `ctrl`+`y` is pressed. +- Run custom code when `ctrl` + `alt` + `esc` is pressed. + +## Setup + +To enable this feature, you need to add `KEY_OVERRIDE_ENABLE = yes` to your `rules.mk`. + +Then, in your `keymap.c` file, you'll need to define the array `key_overrides`, which defines all key overrides to be used. Each override is a value of type `key_override_t`. The array `key_overrides` is `NULL`-terminated and contains pointers to `key_override_t` values (`const key_override_t **`). + +## Creating Key Overrides + +The `key_override_t` struct has many options that allow you to precisely tune your overrides. The full reference is shown below. Instead of manually creating a `key_override_t` value, it is recommended to use these dedicated initializers: + +#### `ko_make_basic(modifiers, key, replacement)` +Returns a `key_override_t`, which sends `replacement` (can be a key-modifer combination), when `key` and `modifiers` are all pressed down. This override still activates if any additional modifiers not specified in `modifiers` are also pressed down. See `ko_make_with_layers_and_negmods` to customize this behavior. + +#### `ko_make_with_layers(modifiers, key, replacement, layers)` +Additionally takes a bitmask `layers` that defines on which layers the override is used. + +#### `ko_make_with_layers_and_negmods(modifiers, key, replacement, layers, negative_mods)` +Additionally takes a bitmask `negative_mods` that defines which modifiers may not be pressed for this override to activate. + +#### `ko_make_with_layers_negmods_and_options(modifiers, key, replacement, layers, negative_mods, options)` +Additionally takes a bitmask `options` that specifies additional options. See `ko_option_t` for available options. + +For more customization possibilities, you may directly create a `key_override_t`, which allows you to customize even more behavior. Read further below for details and examples. + +## Simple Example + +This shows how the mentioned example of sending `delete` when `shift` + `backspace` are pressed is realized: + +```c +const key_override_t delete_key_override = ko_make_basic(MOD_MASK_SHIFT, KC_BSPACE, KC_DELETE); + +// This globally defines all key overrides to be used +const key_override_t **key_overrides = (const key_override_t *[]){ + &delete_key_override, + NULL // Null terminate the array of overrides! +}; +``` + +## Intermediate Difficulty Examples + +### Media Controls & Screen Brightness + +In this example a single key is configured to control media, volume and screen brightness by using key overrides. + +- The key is set to send `play/pause` in the keymap. + +The following key overrides will be configured: + +- `Ctrl` + `play/pause` will send `next track`. +- `Ctrl` + `Shift` + `play/pause` will send `previous track`. +- `Alt` + `play/pause` will send `volume up`. +- `Alt` + `Shift` + `play/pause` will send `volume down`. +- `Ctrl` + `Alt` + `play/pause` will send `brightness up`. +- `Ctrl` + `Alt` + `Shift` + `play/pause` will send `brightness down`. + + +```c +const key_override_t next_track_override = + ko_make_with_layers_negmods_and_options( + MOD_MASK_CTRL, // Trigger modifiers: ctrl + KC_MPLY, // Trigger key: play/pause + KC_MNXT, // Replacement key + ~0, // Activate on all layers + MOD_MASK_SA, // Do not activate when shift or alt are pressed + ko_option_no_reregister_trigger); // Specifies that the play key is not registered again after lifting ctrl + +const key_override_t prev_track_override = ko_make_with_layers_negmods_and_options(MOD_MASK_CS, KC_MPLY, + KC_MPRV, ~0, MOD_MASK_ALT, ko_option_no_reregister_trigger); + +const key_override_t vol_up_override = ko_make_with_layers_negmods_and_options(MOD_MASK_ALT, KC_MPLY, + KC_VOLU, ~0, MOD_MASK_CS, ko_option_no_reregister_trigger); + +const key_override_t vol_down_override = ko_make_with_layers_negmods_and_options(MOD_MASK_SA, KC_MPLY, + KC_VOLD, ~0, MOD_MASK_CTRL, ko_option_no_reregister_trigger); + +const key_override_t brightness_up_override = ko_make_with_layers_negmods_and_options(MOD_MASK_CA, KC_MPLY, + KC_BRIU, ~0, MOD_MASK_SHIFT, ko_option_no_reregister_trigger); + +const key_override_t brightness_down_override = ko_make_basic(MOD_MASK_CSA, KC_MPLY, KC_BRID); + +// This globally defines all key overrides to be used +const key_override_t **key_overrides = (const key_override_t *[]){ + &next_track_override, + &prev_track_override, + &vol_up_override, + &vol_down_override, + &brightness_up_override, + &brightness_down_override, + NULL +}; +``` + +### Flexible macOS-friendly Grave Escape +The [Grave Escape feature](https://docs.qmk.fm/using-qmk/advanced-keycodes/feature_grave_esc) is limited in its configurability and has [bugs when used on macOS](https://docs.qmk.fm/using-qmk/advanced-keycodes/feature_grave_esc#caveats). Key overrides can be used to achieve a similar functionality as Grave Escape, but with more customization and without bugs on macOS. + +```c +// Shift + esc = ~ +const key_override_t tilde_esc_override = ko_make_basic(MOD_MASK_SHIFT, KC_ESC, S(KC_GRAVE)); + +// GUI + esc = ` +const key_override_t grave_esc_override = ko_make_basic(MOD_MASK_GUI, KC_ESC, KC_GRAVE); + +const key_override_t **key_overrides = (const key_override_t *[]){ + &tilde_esc_override, + &grave_esc_override, + NULL +}; +``` + +In addition to not encountering unexpected bugs on macOS, you can also change the behavior as you wish. Instead setting `GUI` + `ESC` = `` ` `` you may change it to an arbitrary other modifier, for example `Ctrl` + `ESC` = `` ` ``. + +## Advanced Examples +### Modifiers as Layer Keys + +Do you really need a dedicated key to toggle your fn layer? With key overrides, perhaps not. This example shows how you can configure to use `rGUI` + `rAlt` (right GUI and right alt) to access a momentary layer like an fn layer. With this you completely eliminate the need to use a dedicated layer key. Of course the choice of modifier keys can be changed as needed, `rGUI` + `rAlt` is just an example here. + +```c +// This is called when the override activates and deactivates. Enable the fn layer on activation and disable on deactivation +bool momentary_layer(bool key_down, void *layer) { + if (key_down) { + layer_on((uint8_t)(uintptr_t)layer); + } else { + layer_off((uint8_t)(uintptr_t)layer); + } + + return false; +} + +const key_override_t fn_override = {.trigger_mods = MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTL), // + .layers = ~(1 << LAYER_FN), // + .suppressed_mods = MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTL), // + .options = ko_option_no_unregister_on_other_key_down, // + .negative_mod_mask = (uint8_t) ~(MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTL)), // + .custom_action = momentary_layer, // + .context = (void *)LAYER_FN, // + .trigger = KC_NO, // + .replacement = KC_NO, // + .enabled = NULL}; +``` + +## Keycodes + +You can enable, disable and toggle all key overrides on the fly. + +|Keycode |Description |Function Equivalent| +|----------|---------------------------------|--------| +|`KEY_OVERRIDE_ON` |Turns on Key Override feature | `key_override_on(void)`| +|`KEY_OVERRIDE_OFF` |Turns off Key Override feature |`key_override_off(void)`| +|`KEY_OVERRIDE_TOGGLE` |Toggles Key Override feature on and off |`key_override_toggle(void)`| + +## Reference for `key_override_t` + +Advanced users may need more customization than what is offered by the simple `ko_make` initializers. For this, directly create a `key_override_t` value and set all members. Below is a reference for all members of `key_override_t`. + +| Member | Description | +|--------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `uint16_t trigger` | The non-modifier keycode that triggers the override. This keycode, and the necessary modifiers (`trigger_mods`) must be pressed to activate this override. Set this to the keycode of the key that should activate the override. Set to `KC_NO` to require only the necessary modifiers to be pressed and no non-modifier. | +| `uint8_t trigger_mods` | Which mods need to be down for activation. If both sides of a modifier are set (e.g. left ctrl and right ctrl) then only one is required to be pressed (e.g. left ctrl suffices). Use the `MOD_MASK_XXX` and `MOD_BIT()` macros for this. | +| `layer_state_t layers` | This is a BITMASK (!), defining which layers this override applies to. To use this override on layer i set the ith bit `(1 << i)`. | +| `uint8_t negative_mod_mask` | Which modifiers cannot be down. It must hold that `(active_modifiers & negative_mod_mask) == 0`, otherwise the key override will not be activated. An active override will be deactivated once this is no longer true. | +| `uint8_t suppressed_mods` | Modifiers to 'suppress' while the override is active. To suppress a modifier means that even though the modifier key is held down, the host OS sees the modifier as not pressed. Can be used to suppress the trigger modifiers, as a trivial example. | +| `uint16_t replacement` | The complex keycode to send as replacement when this override is triggered. This can be a simple keycode, a key-modifier combination (e.g. `C(KC_A)`), or `KC_NO` (to register no replacement keycode). Use in combination with suppressed_mods to get the correct modifiers to be sent. | +| `ko_option_t options` | Options controlling the behavior of the override, such as what actions are allowed to activate the override. | +| `bool (*custom_action)(bool activated, void *context)` | If not NULL, this function will be called right before the replacement key is registered, along with the provided context and a flag indicating whether the override was activated or deactivated. This function allows you to run some custom actions for specific key overrides. If you return `false`, the replacement key is not registered/unregistered as it would normally. Return `true` to register and unregister the override normally. | +| `void *context` | A context that will be passed to the custom action function. | +| `bool *enabled` | If this points to false this override will not be used. Set to NULL to always have this override enabled. | + +### Reference for `ko_option_t` + +Bitfield with various options controlling the behavior of a key override. + +| Value | Description | +|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `ko_option_activation_trigger_down` | Allow activating when the trigger key is pressed down. | +| `ko_option_activation_required_mod_down` | Allow activating when a necessary modifier is pressed down. | +| `ko_option_activation_negative_mod_up` | Allow activating when a negative modifier is released. | +| `ko_option_one_mod` | If set, any of the modifiers in `trigger_mods` will be enough to activate the override (logical OR of modifiers). If not set, all the modifiers in `trigger_mods` have to be pressed (logical AND of modifiers). | +| `ko_option_no_unregister_on_other_key_down` | If set, the override will not deactivate when another key is pressed down. Use only if you really know you need this. | +| `ko_option_no_reregister_trigger` | If set, the trigger key will never be registered again after the override is deactivated. | +| `ko_options_default` | The default options used by the `ko_make_xxx` functions | + +## For Advanced Users: Inner Workings + +This section explains how a key override works in detail, explaining where each member of `key_override_t` comes into play. Understanding this is essential to be able to take full advantage of all the options offered by key overrides. + +#### Activation + +When the necessary keys are pressed (`trigger_mods` + `trigger`), the override is 'activated' and the replacement key is registered in the keyboard report (`replacement`), while the `trigger` key is removed from the keyboard report. The trigger modifiers may also be removed from the keyboard report upon activation of an override (`suppressed_mods`). The override will not activate if any of the `negative_modifiers` are pressed. + +Overrides can activate in three different cases: + +1. The trigger key is pressed down and necessary modifiers are already down. +2. A necessary modifier is pressed down, while the trigger key and other necessary modifiers are already down. +3. A negative modifier is released, while all necessary modifiers and the trigger key are already down. + +Use the `option` member to customize which of these events are allowed to activate your overrides (default: all three). + +In any case, a key override can only activate if the `trigger` key is the _last_ non-modifier key that was pressed down. This emulates the behavior of how standard OSes (macOS, Windows, Linux) handle normal key input (to understand: Hold down `a`, then also hold down `b`, then hold down `shift`; `B` will be typed but not `A`). + +#### Deactivation + +An override is 'deactivated' when one of the trigger keys (`trigger_mods`, `trigger`) is lifted, another non-modifier key is pressed down, or one of the `negative_modifiers` is pressed down. When an override deactivates, the `replacement` key is removed from the keyboard report, while the `suppressed_mods` that are still held down are re-added to the keyboard report. By default, the `trigger` key is re-added to the keyboard report if it is still held down and no other non-modifier key has been pressed since. This again emulates the behavior of how standard OSes handle normal key input (To understand: hold down `a`, then also hold down `b`, then also `shift`, then release `b`; `A` will not be typed even though you are holding the `a` and `shift` keys). Use the `option` field `ko_option_no_reregister_trigger` to prevent re-registering the trigger key in all cases. + +#### Key Repeat Delay + +A third way in which standard OS-handling of modifier-key input is emulated in key overrides is with a ['key repeat delay'](https://www.dummies.com/computers/pcs/set-your-keyboards-repeat-delay-and-repeat-rate/). To explain what this is, let's look at how normal keyboard input is handled by mainstream OSes again: If you hold down `a`, followed by `shift`, you will see the letter `a` is first typed, then for a short moment nothing is typed and then repeating `A`s are typed. Take note that, although shift is pressed down just after `a` is pressed, it takes a moment until `A` is typed. This is caused by the aforementioned key repeat delay, and it is a feature that prevents unwanted repeated characters from being typed. + +This applies equally to releasing a modifier: When you hold `shift`, then press `a`, the letter `A` is typed. Now if you release `shift` first, followed by `a` shortly after, you will not see the letter `a` being typed, even though for a short moment of time you were just holding down the key `a`. This is because no modified characters are typed until the key repeat delay has passed. + + This exact behavior is implemented in key overrides as well: If a key override for `shift` + `a` = `b` exists, and `a` is pressed and held, followed by `shift`, you will not immediately see the letter `b` being typed. Instead, this event is deferred for a short moment, until the key repeat delay has passed, measured from the moment when the trigger key (`a`) was pressed down. + +The duration of the key repeat delay is controlled with the `KEY_OVERRIDE_REPEAT_DELAY` macro. Define this value in your `config.h` file to change it. It is 500ms by default. + + +## Difference to Combos + +Note that key overrides are very different from [combos](https://docs.qmk.fm/#/feature_combo). Combos require that you press down several keys almost _at the same time_ and can work with any combination of non-modifier keys. Key overrides work like keyboard shortcuts (e.g. `ctrl` + `z`): They take combinations of _multiple_ modifiers and _one_ non-modifier key to then perform some custom action. Key overrides are implemented with much care to behave just like normal keyboard shortcuts would in regards to the order of pressed keys, timing, and interacton with other pressed keys. There are a number of optional settings that can be used to really fine-tune the behavior of each key override as well. Using key overrides also does not delay key input for regular key presses, which inherently happens in combos and may be undesirable. diff --git a/docs/syllabus.md b/docs/syllabus.md index ec7f66ba78..b33bd9e727 100644 --- a/docs/syllabus.md +++ b/docs/syllabus.md @@ -40,6 +40,7 @@ These topics start to dig into some of the features that QMK supports. You don't * [Tap Dance](feature_tap_dance.md) * [Combos](feature_combo.md) * [Userspace](feature_userspace.md) + * [Key Overrides](feature_key_overrides.md) # Advanced Topics diff --git a/docs/understanding_qmk.md b/docs/understanding_qmk.md index 331b1c893c..e3dd5cb780 100644 --- a/docs/understanding_qmk.md +++ b/docs/understanding_qmk.md @@ -146,6 +146,7 @@ The `process_record()` function itself is deceptively simple, but hidden within * [`bool process_audio(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_audio.c#L19) * [`bool process_steno(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_steno.c#L160) * [`bool process_music(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_music.c#L114) + * [`bool process_key_override(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/5a1b857dea45a17698f6baa7dd1b7a7ea907fb0a/quantum/process_keycode/process_key_override.c#L397) * [`bool process_tap_dance(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_tap_dance.c#L141) * [`bool process_unicode_common(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_unicode_common.c#L169) calls one of: diff --git a/quantum/process_keycode/process_key_override.c b/quantum/process_keycode/process_key_override.c new file mode 100644 index 0000000000..fe43eacc40 --- /dev/null +++ b/quantum/process_keycode/process_key_override.c @@ -0,0 +1,518 @@ +/* + * Copyright 2021 Jonas Gessner + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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 "quantum.h" +#include "report.h" +#include "timer.h" +#include "process_key_override_private.h" + +#include + +#ifndef KEY_OVERRIDE_REPEAT_DELAY +# define KEY_OVERRIDE_REPEAT_DELAY 500 +#endif + +// For benchmarking the time it takes to call process_key_override on every key press (needs keyboard debugging enabled as well) +// #define BENCH_KEY_OVERRIDE + +// For debug output (needs keyboard debugging enabled as well) +// #define DEBUG_KEY_OVERRIDE + +#ifdef DEBUG_KEY_OVERRIDE +# define key_override_printf dprintf +#else +# define key_override_printf(str, ...) \ + {} +#endif + +// Helpers + +// Private functions implemented elsewhere in qmk/tmk +extern uint8_t extract_mod_bits(uint16_t code); +extern void set_weak_override_mods(uint8_t mods); +extern void clear_weak_override_mods(void); +extern void set_suppressed_override_mods(uint8_t mods); +extern void clear_suppressed_override_mods(void); + +static uint16_t clear_mods_from(uint16_t keycode) { + switch (keycode) { + case QK_MODS ... QK_MODS_MAX: + break; + default: + return keycode; + } + + static const uint16_t all_mods = QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI | QK_RCTL | QK_RSFT | QK_RALT | QK_RGUI; + + return (keycode & ~(all_mods)); +} + +// Internal variables +static const key_override_t *active_override = NULL; +static bool active_override_trigger_is_down = false; + +// Used to keep track of what non-modifier key was last pressed down. We never want to activate an override for a trigger key that is not the last non-mod key that was pressed down. OSes internally completely unregister a key that is held when a different key is held down after. We want to respect this here. +static uint16_t last_key_down = 0; +// When was the last key pressed down? +static uint32_t last_key_down_time = 0; + +// What timestamp are we comparing to when waiting to register a deferred key? +static uint32_t defer_reference_time = 0; +// What delay should pass until deferred key is registered? +static uint32_t defer_delay = 0; + +// Holds the keycode that should be registered at a later time, in order to not get false key presses +static uint16_t deferred_register = 0; + +// TODO: in future maybe save in EEPROM? +static bool enabled = true; + +// Public variables +__attribute__((weak)) const key_override_t **key_overrides = NULL; + +// Forward decls +static const key_override_t *clear_active_override(const bool allow_reregister); + +void key_override_on(void) { + enabled = true; + key_override_printf("Key override ON\n"); +} + +void key_override_off(void) { + enabled = false; + clear_active_override(false); + key_override_printf("Key override OFF\n"); +} + +void key_override_toggle(void) { + if (key_override_is_enabled()) { + key_override_off(); + } else { + key_override_on(); + } +} + +bool key_override_is_enabled(void) { return enabled; } + +// Returns whether the modifiers that are pressed are such that the override should activate +static bool key_override_matches_active_modifiers(const key_override_t *override, const uint8_t mods) { + // Check that negative keys pass + if ((override->negative_mod_mask & mods) != 0) { + return false; + } + + // Immediately return true if the override requires no mods down + if (override->trigger_mods == 0) { + return true; + } + + if ((override->options & ko_option_one_mod) != 0) { + // At least one of the trigger modifiers must be down + return (override->trigger_mods & mods) != 0; + } else { + // All trigger modifiers must be down, but each mod can be active on either side (if both sides are specified). + + // Which mods, regardless of side, are required? + uint8_t one_sided_required_mods = (override->trigger_mods & 0b1111) | (override->trigger_mods >> 4); + + // Which of the required modifiers are active? + uint8_t active_required_mods = override->trigger_mods & mods; + + // Move the active requird mods to one side + uint8_t one_sided_active_required_mods = (active_required_mods & 0b1111) | (active_required_mods >> 4); + + // Check that there is a full match between the required one-sided mods and active required one sided mods + return one_sided_active_required_mods == one_sided_required_mods; + } + + return false; +} + +static void schedule_deferred_register(const uint16_t keycode) { + if (timer_elapsed32(last_key_down_time) < KEY_OVERRIDE_REPEAT_DELAY) { + // Defer until KEY_OVERRIDE_REPEAT_DELAY has passed since the trigger key was pressed down. This emulates the behavior as holding down a key x, then holding down shift shortly after. Usually the shifted key X is not immediately produced, but rather a 'key repeat delay' passes before any repeated character is output. + defer_reference_time = last_key_down_time; + defer_delay = KEY_OVERRIDE_REPEAT_DELAY; + } else { + // Wait a very short time when a modifier event triggers the override to avoid false activations when e.g. a modifier is pressed just before a key is released (with the intention of pairing the modifier with a different key), or a modifier is lifted shortly before the trigger key is lifted. Operating systems by default reject modifier-events that happen very close to a non-modifier event. + defer_reference_time = timer_read32(); + defer_delay = 50; // 50ms + } + deferred_register = keycode; +} + +const key_override_t *clear_active_override(const bool allow_reregister) { + if (active_override == NULL) { + return NULL; + } + + key_override_printf("Deactivating override\n"); + + deferred_register = 0; + + // Clear the suppressed mods + clear_suppressed_override_mods(); + + // Unregister the replacement. First remove the weak override mods + clear_weak_override_mods(); + + const key_override_t *const old = active_override; + + const uint8_t mod_free_replacement = clear_mods_from(active_override->replacement); + + bool unregister_replacement = mod_free_replacement != KC_NO && // KC_NO is never registered + mod_free_replacement < SAFE_RANGE; // Custom keycodes are never registered + + // Try firing the custom handler + if (active_override->custom_action != NULL) { + unregister_replacement &= active_override->custom_action(false, active_override->context); + } + + // Then unregister the mod-free replacement key if desired + if (unregister_replacement) { + if (IS_KEY(mod_free_replacement)) { + del_key(mod_free_replacement); + } else { + key_override_printf("NOT KEY 1\n"); + send_keyboard_report(); + unregister_code(mod_free_replacement); + } + } + + const uint16_t trigger = active_override->trigger; + + const bool reregister_trigger = allow_reregister && // Check if allowed from caller + (active_override->options & ko_option_no_reregister_trigger) == 0 && // Check if override allows + active_override_trigger_is_down && // Check if trigger is even down + trigger != KC_NO && // KC_NO is never registered + trigger < SAFE_RANGE; // A custom keycode should not be registered + + // Optionally re-register the trigger if it is still down + if (reregister_trigger) { + key_override_printf("Re-registering trigger deferred: %u\n", trigger); + + // This will always be a modifier event, so defer always + schedule_deferred_register(trigger); + } + + send_keyboard_report(); + + active_override = NULL; + active_override_trigger_is_down = false; + + return old; +} + +/** Checks if the key event is an allowed activation event for the provided override. Does not check things like whether the correct mods or correct trigger key is down. */ +static bool check_activation_event(const key_override_t *override, const bool key_down, const bool is_mod) { + ko_option_t options = override->options; + + if ((options & ko_options_all_activations) == 0) { + // No activation option provided at all. This is wrong, but let's assume the default activations (ko_options_all_activations) were meant... + options = ko_options_all_activations; + } + + if (is_mod) { + if (key_down) { + return (options & ko_option_activation_required_mod_down) != 0; + } else { + return (options & ko_option_activation_negative_mod_up) != 0; + } + } else { + if (key_down) { + return (options & ko_option_activation_trigger_down) != 0; + } else { + return false; + } + } +} + +/** Iterates through the list of key overrides and tries activating each, until it finds one that activates or reaches the end of overrides. Returns true if the key action for `keycode` should be sent */ +static bool try_activating_override(const uint16_t keycode, const uint8_t layer, const bool key_down, const bool is_mod, const uint8_t active_mods, bool *activated) { + if (key_overrides == NULL) { + return true; + } + + for (uint8_t i = 0;; i++) { + const key_override_t *const override = key_overrides[i]; + + // End of array + if (override == NULL) { + break; + } + + // Fast, but not full mods check. Most key presses will not have any mods down, and most overrides will require mods. Hence here we filter overrides that require mods to be down while no mods are down + if (active_mods == 0 && override->trigger_mods != 0) { + key_override_printf("Not activating override: Modifiers don't match\n"); + continue; + } + + // Check layer + if ((override->layers & (1 << layer)) == 0) { + key_override_printf("Not activating override: Not set to activate on pressed layer\n"); + continue; + } + + // Check allowed activation events + if (!check_activation_event(override, key_down, is_mod)) { + key_override_printf("Not activating override: Activation event not allowed\n"); + continue; + } + + const bool is_trigger = override->trigger == keycode; + + // Check if trigger lifted. This is a small optimization in order to skip the remaining checks + if (is_trigger && !key_down) { + key_override_printf("Not activating override: Trigger lifted\n"); + continue; + } + + // If the trigger is KC_NO it means 'no key', so only the required modifiers need to be down. + const bool no_trigger = override->trigger == KC_NO; + + // Check if aleady active + if (override == active_override) { + key_override_printf("Not activating override: Alerady actived\n"); + continue; + } + + // Check if enabled + if (override->enabled != NULL && !((*(override->enabled) & 1))) { + key_override_printf("Not activating override: Not enabled\n"); + continue; + } + + // Check mods precisely + if (!key_override_matches_active_modifiers(override, active_mods)) { + key_override_printf("Not activating override: Modifiers don't match\n"); + continue; + } + + // Check if trigger key is down. + const bool trigger_down = is_trigger && key_down; + + // At this point, all requirements for activation are checked, except whether the trigger key is pressed. Now we check if the required trigger is down + // If no trigger key is required, yes. + // If the trigger was just pressed, yes. + // If the last non-mod key that was pressed down is the trigger key, yes. + bool should_activate = no_trigger || trigger_down || last_key_down == override->trigger; + + if (!should_activate) { + key_override_printf("Not activating override. Trigger not down\n"); + continue; + } + + key_override_printf("Activating override\n"); + + clear_active_override(false); + + active_override = override; + active_override_trigger_is_down = true; + + set_suppressed_override_mods(override->suppressed_mods); + + if (!trigger_down && !no_trigger) { + // When activating a key override the trigger is is always unregistered. In the case where the key that newly pressed is not the trigger key, we have to explicitly remove the trigger key from the keyboard report. If the trigger was just pressed down we simply suppress the event which also has the effect of the trigger key not being registered in the keyboard report. + if (IS_KEY(override->trigger)) { + del_key(override->trigger); + } else { + unregister_code(override->trigger); + } + } + + const uint16_t mod_free_replacement = clear_mods_from(override->replacement); + + bool register_replacement = mod_free_replacement != KC_NO && // KC_NO is never registered + mod_free_replacement < SAFE_RANGE; // Custom keycodes are never registered + + // Try firing the custom handler + if (override->custom_action != NULL) { + register_replacement &= override->custom_action(true, override->context); + } + + if (register_replacement) { + const uint8_t override_mods = extract_mod_bits(override->replacement); + set_weak_override_mods(override_mods); + + // If this is a modifier event that activates the key override we _always_ defer the actual full activation of the override + if (is_mod) { + key_override_printf("Deferring register replacement key\n"); + schedule_deferred_register(mod_free_replacement); + send_keyboard_report(); + } else { + if (IS_KEY(mod_free_replacement)) { + add_key(mod_free_replacement); + } else { + key_override_printf("NOT KEY 2\n"); + send_keyboard_report(); + // On macOS there seems to be a race condition when it comes to the keyboard report and consumer keycodes. It seems the OS may recognize a consumer keycode before an updated keyboard report, even if the keyboard report is actually sent before the consumer key. I assume it is some sort of race condition because it happens infrequently and very irregularly. Waiting for about at least 10ms between sending the keyboard report and sending the consumer code has shown to fix this. + wait_ms(10); + register_code(mod_free_replacement); + } + } + } else { + // If not registering the replacement key send keyboard report to update the unregistered keys. + send_keyboard_report(); + } + + *activated = true; + + // If the trigger is down, suppress the event so that it does not get added to the keyboard report. + return !trigger_down; + } + + *activated = false; + + return true; +} + +void matrix_scan_key_override(void) { + if (deferred_register == 0) { + return; + } + + if (timer_elapsed32(defer_reference_time) >= defer_delay) { + key_override_printf("Registering deferred key\n"); + register_code16(deferred_register); + deferred_register = 0; + defer_reference_time = 0; + defer_delay = 0; + } +} + +bool process_key_override(const uint16_t keycode, const keyrecord_t *const record) { +#ifdef BENCH_KEY_OVERRIDE + uint16_t start = timer_read(); +#endif + + const bool key_down = record->event.pressed; + const bool is_mod = IS_MOD(keycode); + + if (key_down) { + switch (keycode) { + case KEY_OVERRIDE_TOGGLE: + key_override_toggle(); + return false; + + case KEY_OVERRIDE_ON: + key_override_on(); + return false; + + case KEY_OVERRIDE_OFF: + key_override_off(); + return false; + + default: + break; + } + } + + if (!enabled) { + return true; + } + + uint8_t effective_mods = get_mods(); + +#ifdef KEY_OVERRIDE_INCLUDE_WEAK_MODS + effective_mods |= get_weak_mods(); +#endif + +#ifndef NO_ACTION_ONESHOT + // Locked one shot mods are added to get_mods(), I think (why??) while oneshot mods are in get_oneshot_mods(). Still OR with get_locked_oneshot_mods because that's where those mods _should_ be saved. + effective_mods |= get_oneshot_locked_mods() | get_oneshot_mods(); +#endif + + if (is_mod) { + // The mods returned from get_mods() will be updated with this new event _after_ this code runs. Hence we manually update the effective mods here to really know the effective mods. + if (key_down) { + effective_mods |= MOD_BIT(keycode); + } else { + effective_mods &= ~MOD_BIT(keycode); + } + } else { + if (key_down) { + last_key_down = keycode; + last_key_down_time = timer_read32(); + deferred_register = 0; + } + + // The last key that was pressed was just released. No more keys are therefore sending input + if (!key_down && keycode == last_key_down) { + last_key_down = 0; + last_key_down_time = 0; + // We also cancel any deferred registers because, again, no keys are sending any input. Only the last key that is pressed creates an input – this key was just lifted. + deferred_register = 0; + } + } + + key_override_printf("key down: %u keycode: %u is mod: %u effective mods: %u\n", key_down, keycode, is_mod, effective_mods); + + bool send_key_action = true; + bool activated = false; + + // Non-mod key up events never activate a key override + if (is_mod || key_down) { + // Get the exact layer that was hit. It will be cached at this point + const uint8_t layer = read_source_layers_cache(record->event.key); + + // Use blocked to ensure the same override is not activated again immediately after it is deactivated + send_key_action = try_activating_override(keycode, layer, key_down, is_mod, effective_mods, &activated); + + if (!send_key_action) { + send_keyboard_report(); + } + } + + if (!activated && active_override != NULL) { + if (is_mod) { + // Check if necessary modifier of current override goes up or a negative mod goes down + if (!key_override_matches_active_modifiers(active_override, effective_mods)) { + key_override_printf("Deactivating override because necessary modifier lifted or negative mod pressed\n"); + clear_active_override(true); + } + } else { + // Check if trigger of current override goes up or if override does not allow additional keys to be down and another key goes down + const bool is_trigger = keycode == active_override->trigger; + bool should_deactivate = false; + + // Check if trigger key lifted + if (is_trigger && !key_down) { + should_deactivate = true; + active_override_trigger_is_down = false; + key_override_printf("Deactivating override because trigger key up\n"); + } + + // Check if another key was pressed + if (key_down && (active_override->options & ko_option_no_unregister_on_other_key_down) == 0) { + should_deactivate = true; + key_override_printf("Deactivating override because another key was pressed\n"); + } + + if (should_deactivate) { + clear_active_override(false); + } + } + } + +#ifdef BENCH_KEY_OVERRIDE + uint16_t elapsed = timer_elapsed(start); + + dprintf("Processing key overrides took: %u ms\n", elapsed); +#endif + + return send_key_action; +} diff --git a/quantum/process_keycode/process_key_override.h b/quantum/process_keycode/process_key_override.h new file mode 100644 index 0000000000..9ba59e4e9b --- /dev/null +++ b/quantum/process_keycode/process_key_override.h @@ -0,0 +1,147 @@ +/* + * Copyright 2021 Jonas Gessner + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include + +#include "action_layer.h" + +/** + * Key overrides allow you to send a different key-modifier combination or perform a custom action when a certain modifier-key combination is pressed. + * + * For example, you may configure a key override to send the delete key when shift + backspace are pressed together, or that your volume keys become screen brightness keys when holding ctrl. The possibilities are quite vast and the documentation contains a few examples for inspiration. + * + * See the documentation and examples here: https://docs.qmk.fm/#/feature_key_overrides + */ + +/** Bitfield with various options controlling the behavior of a key override. */ +typedef enum { + /** Allow activating when the trigger key is pressed down. */ + ko_option_activation_trigger_down = (1 << 0), + /** Allow activating when a necessary modifier is pressed down. */ + ko_option_activation_required_mod_down = (1 << 1), + /** Allow activating when a negative modifier is released. */ + ko_option_activation_negative_mod_up = (1 << 2), + + ko_options_all_activations = ko_option_activation_negative_mod_up | ko_option_activation_required_mod_down | ko_option_activation_trigger_down, + + /** If set, any of the modifiers in trigger_mods will be enough to activate the override (logical OR of modifiers). If not set, all the modifiers in trigger_mods have to be pressed (logical AND of modifiers). */ + ko_option_one_mod = (1 << 3), + + /** If set, the trigger key will never be registered again after the override is deactivated. */ + ko_option_no_reregister_trigger = (1 << 4), + + /** If set, the override will not deactivate when another key is pressed down. Use only if you really know you need this. */ + ko_option_no_unregister_on_other_key_down = (1 << 5), + + /** The default options used by the ko_make_xxx functions. */ + ko_options_default = ko_options_all_activations, +} ko_option_t; + +/** Defines a single key override */ +typedef struct { + // The non-modifier keycode that triggers the override. This keycode, and the necessary modifiers (trigger_mods) must be pressed to activate this override. Set this to the keycode of the key that should activate the override. Set to KC_NO to require only the necessary modifiers to be pressed and no non-modifier. + uint16_t trigger; + + // Which mods need to be down for activation. If both sides of a modifier are set (e.g. left ctrl and right ctrl) then only one is required to be pressed (e.g. left ctrl suffices). Use the MOD_MASK_XXX and MOD_BIT() macros for this. + uint8_t trigger_mods; + + // This is a BITMASK (!), defining which layers this override applies to. To use this override on layer i set the ith bit (1 << i). + layer_state_t layers; + + // Which modifiers cannot be down. It must hold that (active_mods & negative_mod_mask) == 0, otherwise the key override will not be activated. An active override will be deactivated once this is no longer true. + uint8_t negative_mod_mask; + + // Modifiers to 'suppress' while the override is active. To suppress a modifier means that even though the modifier key is held down, the host OS sees the modifier as not pressed. Can be used to suppress the trigger modifiers, as a trivial example. + uint8_t suppressed_mods; + + // The complex keycode to send as replacement when this override is triggered. This can be a simple keycode, a key-modifier combination (e.g. C(KC_A)), or KC_NO (to register no replacement keycode). Use in combination with suppressed_mods to get the correct modifiers to be sent. + uint16_t replacement; + + // Options controlling the behavior of the override, such as what actions are allowed to activate the override. + ko_option_t options; + + // If not NULL, this function will be called right before the replacement key is registered, along with the provided context and a flag indicating whether the override was activated or deactivated. This function allows you to run some custom actions for specific key overrides. If you return `false`, the replacement key is not registered/unregistered as it would normally. Return `true` to register and unregister the override normally. + bool (*custom_action)(bool activated, void *context); + + // A context that will be passed to the custom action function. + void *context; + + // If this points to false this override will not be used. Set to NULL to always have this override enabled. + bool *enabled; +} key_override_t; + +/** Define this as a null-terminated array of pointers to key overrides. These key overrides will be used by qmk. */ +extern const key_override_t **key_overrides; + +/** Turns key overrides on */ +extern void key_override_on(void); + +/** Turns key overrides off */ +extern void key_override_off(void); + +/** Toggles key overrides on */ +extern void key_override_toggle(void); + +/** Returns whether key overrides are enabled */ +extern bool key_override_is_enabled(void); + +/** + * Preferrably use these macros to create key overrides. They fix many of the options to a standard setting that should satisfy most basic use-cases. Only directly create a key_override_t struct when you really need to. + */ + +// clang-format off + +/** + * Convenience initializer to create a basic key override. Activates the override on all layers. + */ +#define ko_make_basic(trigger_mods, trigger_key, replacement_key) \ + ko_make_with_layers(trigger_mods, trigger_key, replacement_key, ~0) + +/** + * Convenience initializer to create a basic key override. Provide a bitmap (of type layer_state_t) with the bits set for each layer on which the override should activate. + */ +#define ko_make_with_layers(trigger_mods, trigger_key, replacement_key, layers) \ + ko_make_with_layers_and_negmods(trigger_mods, trigger_key, replacement_key, layers, 0) + +/** + * Convenience initializer to create a basic key override. Provide a bitmap with the bits set for each layer on which the override should activate. Also provide a negative modifier mask, that is used to define which modifiers may not be pressed. + */ +#define ko_make_with_layers_and_negmods(trigger_mods, trigger_key, replacement_key, layers, negative_mask) \ + ko_make_with_layers_negmods_and_options(trigger_mods, trigger_key, replacement_key, layers, negative_mask, ko_options_default) + + /** + * Convenience initializer to create a basic key override. Provide a bitmap with the bits set for each layer on which the override should activate. Also provide a negative modifier mask, that is used to define which modifiers may not be pressed. Provide options for additional control of the behavior of the override. + */ +#define ko_make_with_layers_negmods_and_options(trigger_mods_, trigger_key, replacement_key, layer_mask, negative_mask, options_) \ + ((const key_override_t){ \ + .trigger_mods = (trigger_mods_), \ + .layers = (layer_mask), \ + .suppressed_mods = (trigger_mods_), \ + .options = (options_), \ + .negative_mod_mask = (negative_mask), \ + .custom_action = NULL, \ + .context = NULL, \ + .trigger = (trigger_key), \ + .replacement = (replacement_key), \ + .enabled = NULL \ + }) + +// clang-format on diff --git a/quantum/process_keycode/process_key_override_private.h b/quantum/process_keycode/process_key_override_private.h new file mode 100644 index 0000000000..1d0e134a19 --- /dev/null +++ b/quantum/process_keycode/process_key_override_private.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Jonas Gessner + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include "action.h" + +bool process_key_override(const uint16_t keycode, const keyrecord_t *const record); +void matrix_scan_key_override(void); diff --git a/quantum/quantum.c b/quantum/quantum.c index b4cfa28d7d..9cfffd9317 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -58,12 +58,16 @@ float bell_song[][2] = SONG(TERMINAL_SOUND); # include "process_auto_shift.h" #endif -static void do_code16(uint16_t code, void (*f)(uint8_t)) { +#ifdef KEY_OVERRIDE_ENABLE +# include "process_key_override_private.h" +#endif + +uint8_t extract_mod_bits(uint16_t code) { switch (code) { case QK_MODS ... QK_MODS_MAX: break; default: - return; + return 0; } uint8_t mods_to_send = 0; @@ -80,9 +84,11 @@ static void do_code16(uint16_t code, void (*f)(uint8_t)) { if (code & QK_LGUI) mods_to_send |= MOD_BIT(KC_LGUI); } - f(mods_to_send); + return mods_to_send; } +static void do_code16(uint16_t code, void (*f)(uint8_t)) { f(extract_mod_bits(code)); } + void register_code16(uint16_t code) { if (IS_MOD(code) || code == KC_NO) { do_code16(code, register_mods); @@ -243,6 +249,9 @@ bool process_record_quantum(keyrecord_t *record) { #if (defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))) && !defined(NO_MUSIC_MODE) process_music(keycode, record) && #endif +#ifdef KEY_OVERRIDE_ENABLE + process_key_override(keycode, record) && +#endif #ifdef TAP_DANCE_ENABLE process_tap_dance(keycode, record) && #endif @@ -408,6 +417,10 @@ void matrix_scan_quantum() { matrix_scan_music(); #endif +#ifdef KEY_OVERRIDE_ENABLE + matrix_scan_key_override(); +#endif + #ifdef SEQUENCER_ENABLE matrix_scan_sequencer(); #endif diff --git a/quantum/quantum.h b/quantum/quantum.h index 66ba96fde8..673796e6b1 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -118,6 +118,10 @@ extern layer_state_t layer_state; # include "process_unicodemap.h" #endif +#ifdef KEY_OVERRIDE_ENABLE +# include "process_key_override.h" +#endif + #ifdef TAP_DANCE_ENABLE # include "process_tap_dance.h" #endif diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index c361dd670e..3d2dbde922 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -514,6 +514,11 @@ enum quantum_keycodes { // RGB underglow/matrix (continued) RGB_MODE_TWINKLE, + // Key Overrides + KEY_OVERRIDE_TOGGLE, + KEY_OVERRIDE_ON, + KEY_OVERRIDE_OFF, + // Start of custom keycode range for keyboards and keymaps - always leave at the end SAFE_RANGE }; diff --git a/show_options.mk b/show_options.mk index af38bcb24b..dd1ad5171f 100644 --- a/show_options.mk +++ b/show_options.mk @@ -44,6 +44,7 @@ OTHER_OPTION_NAMES = \ AUTO_SHIFT_MODIFIERS \ COMBO_ENABLE \ KEY_LOCK_ENABLE \ + KEY_OVERRIDE_ENABLE \ LEADER_ENABLE \ PRINTING_ENABLE \ STENO_ENABLE \ diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c index a57c8bf66a..2b3c00cba0 100644 --- a/tmk_core/common/action_util.c +++ b/tmk_core/common/action_util.c @@ -27,6 +27,10 @@ extern keymap_config_t keymap_config; static uint8_t real_mods = 0; static uint8_t weak_mods = 0; static uint8_t macro_mods = 0; +#ifdef KEY_OVERRIDE_ENABLE +static uint8_t weak_override_mods = 0; +static uint8_t suppressed_mods = 0; +#endif #ifdef USB_6KRO_ENABLE # define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS) @@ -229,6 +233,7 @@ void send_keyboard_report(void) { keyboard_report->mods = real_mods; keyboard_report->mods |= weak_mods; keyboard_report->mods |= macro_mods; + #ifndef NO_ACTION_ONESHOT if (oneshot_mods) { # if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) @@ -244,6 +249,13 @@ void send_keyboard_report(void) { } #endif + +#ifdef KEY_OVERRIDE_ENABLE + // These need to be last to be able to properly control key overrides + keyboard_report->mods &= ~suppressed_mods; + keyboard_report->mods |= weak_override_mods; +#endif + host_keyboard_send(keyboard_report); } @@ -299,6 +311,22 @@ void set_weak_mods(uint8_t mods) { weak_mods = mods; } */ void clear_weak_mods(void) { weak_mods = 0; } +#ifdef KEY_OVERRIDE_ENABLE +/** \brief set weak mods used by key overrides. DO not call this manually + */ +void set_weak_override_mods(uint8_t mods) { weak_override_mods = mods; } +/** \brief clear weak mods used by key overrides. DO not call this manually + */ +void clear_weak_override_mods(void) { weak_override_mods = 0; } + +/** \brief set suppressed mods used by key overrides. DO not call this manually + */ +void set_suppressed_override_mods(uint8_t mods) { suppressed_mods = mods; } +/** \brief clear suppressed mods used by key overrides. DO not call this manually + */ +void clear_suppressed_override_mods(void) { suppressed_mods = 0; } +#endif + /* macro modifier */ /** \brief get macro mods * -- cgit v1.2.3 From b8e913c8db73ebf890e4604ee41991a34354a600 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Wed, 18 Aug 2021 00:18:58 +0100 Subject: Migrate platform independent code from tmk_core -> quantum (#13673) * Migrate action|keyboard|keycode|eeconfig from tmk_core -> quantum --- common_features.mk | 7 + quantum/action.c | 1126 ++++++++++++++++++++++++++++++++++++++ quantum/action.h | 132 +++++ quantum/action_code.h | 308 +++++++++++ quantum/action_layer.c | 279 ++++++++++ quantum/action_layer.h | 147 +++++ quantum/action_macro.c | 93 ++++ quantum/action_macro.h | 123 +++++ quantum/action_tapping.c | 456 +++++++++++++++ quantum/action_tapping.h | 42 ++ quantum/action_util.c | 455 +++++++++++++++ quantum/action_util.h | 105 ++++ quantum/eeconfig.c | 211 +++++++ quantum/eeconfig.h | 113 ++++ quantum/keyboard.c | 569 +++++++++++++++++++ quantum/keyboard.h | 90 +++ quantum/keycode.h | 560 +++++++++++++++++++ quantum/via.h | 2 +- tmk_core/common.mk | 10 +- tmk_core/common/action.c | 1126 -------------------------------------- tmk_core/common/action.h | 132 ----- tmk_core/common/action_code.h | 308 ----------- tmk_core/common/action_layer.c | 279 ---------- tmk_core/common/action_layer.h | 147 ----- tmk_core/common/action_macro.c | 93 ---- tmk_core/common/action_macro.h | 123 ----- tmk_core/common/action_tapping.c | 456 --------------- tmk_core/common/action_tapping.h | 42 -- tmk_core/common/action_util.c | 455 --------------- tmk_core/common/action_util.h | 105 ---- tmk_core/common/eeconfig.c | 211 ------- tmk_core/common/eeconfig.h | 113 ---- tmk_core/common/keyboard.c | 565 ------------------- tmk_core/common/keyboard.h | 90 --- tmk_core/common/keycode.h | 560 ------------------- 35 files changed, 4819 insertions(+), 4814 deletions(-) create mode 100644 quantum/action.c create mode 100644 quantum/action.h create mode 100644 quantum/action_code.h create mode 100644 quantum/action_layer.c create mode 100644 quantum/action_layer.h create mode 100644 quantum/action_macro.c create mode 100644 quantum/action_macro.h create mode 100644 quantum/action_tapping.c create mode 100644 quantum/action_tapping.h create mode 100644 quantum/action_util.c create mode 100644 quantum/action_util.h create mode 100644 quantum/eeconfig.c create mode 100644 quantum/eeconfig.h create mode 100644 quantum/keyboard.c create mode 100644 quantum/keyboard.h create mode 100644 quantum/keycode.h delete mode 100644 tmk_core/common/action.c delete mode 100644 tmk_core/common/action.h delete mode 100644 tmk_core/common/action_code.h delete mode 100644 tmk_core/common/action_layer.c delete mode 100644 tmk_core/common/action_layer.h delete mode 100644 tmk_core/common/action_macro.c delete mode 100644 tmk_core/common/action_macro.h delete mode 100644 tmk_core/common/action_tapping.c delete mode 100644 tmk_core/common/action_tapping.h delete mode 100644 tmk_core/common/action_util.c delete mode 100644 tmk_core/common/action_util.h delete mode 100644 tmk_core/common/eeconfig.c delete mode 100644 tmk_core/common/eeconfig.h delete mode 100644 tmk_core/common/keyboard.c delete mode 100644 tmk_core/common/keyboard.h delete mode 100644 tmk_core/common/keycode.h (limited to 'tmk_core/common/action_util.c') diff --git a/common_features.mk b/common_features.mk index 1eece0242e..d09d4f1eff 100644 --- a/common_features.mk +++ b/common_features.mk @@ -20,6 +20,13 @@ QUANTUM_SRC += \ $(QUANTUM_DIR)/send_string.c \ $(QUANTUM_DIR)/bitwise.c \ $(QUANTUM_DIR)/led.c \ + $(QUANTUM_DIR)/action.c \ + $(QUANTUM_DIR)/action_layer.c \ + $(QUANTUM_DIR)/action_macro.c \ + $(QUANTUM_DIR)/action_tapping.c \ + $(QUANTUM_DIR)/action_util.c \ + $(QUANTUM_DIR)/eeconfig.c \ + $(QUANTUM_DIR)/keyboard.c \ $(QUANTUM_DIR)/keymap_common.c \ $(QUANTUM_DIR)/keycode_config.c \ $(QUANTUM_DIR)/logging/debug.c \ diff --git a/quantum/action.c b/quantum/action.c new file mode 100644 index 0000000000..d19fd2a045 --- /dev/null +++ b/quantum/action.c @@ -0,0 +1,1126 @@ +/* +Copyright 2012,2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 "host.h" +#include "keycode.h" +#include "keyboard.h" +#include "mousekey.h" +#include "command.h" +#include "led.h" +#include "action_layer.h" +#include "action_tapping.h" +#include "action_macro.h" +#include "action_util.h" +#include "action.h" +#include "wait.h" + +#ifdef BACKLIGHT_ENABLE +# include "backlight.h" +#endif + +#ifdef DEBUG_ACTION +# include "debug.h" +#else +# include "nodebug.h" +#endif + +#ifdef POINTING_DEVICE_ENABLE +# include "pointing_device.h" +#endif + +int tp_buttons; + +#if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) +int retro_tapping_counter = 0; +#endif + +#ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY +__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) { return false; } +#endif + +#ifdef RETRO_TAPPING_PER_KEY +__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) { return false; } +#endif + +__attribute__((weak)) bool pre_process_record_quantum(keyrecord_t *record) { return true; } + +#ifndef TAP_CODE_DELAY +# define TAP_CODE_DELAY 0 +#endif +#ifndef TAP_HOLD_CAPS_DELAY +# define TAP_HOLD_CAPS_DELAY 80 +#endif +/** \brief Called to execute an action. + * + * FIXME: Needs documentation. + */ +void action_exec(keyevent_t event) { + if (!IS_NOEVENT(event)) { + dprint("\n---- action_exec: start -----\n"); + dprint("EVENT: "); + debug_event(event); + dprintln(); +#if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) + retro_tapping_counter++; +#endif + } + + if (event.pressed) { + // clear the potential weak mods left by previously pressed keys + clear_weak_mods(); + } + +#ifdef SWAP_HANDS_ENABLE + if (!IS_NOEVENT(event)) { + process_hand_swap(&event); + } +#endif + + keyrecord_t record = {.event = event}; + +#ifndef NO_ACTION_ONESHOT +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + if (has_oneshot_layer_timed_out()) { + clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); + } + if (has_oneshot_mods_timed_out()) { + clear_oneshot_mods(); + } +# ifdef SWAP_HANDS_ENABLE + if (has_oneshot_swaphands_timed_out()) { + clear_oneshot_swaphands(); + } +# endif +# endif +#endif + +#ifndef NO_ACTION_TAPPING + if (IS_NOEVENT(record.event) || pre_process_record_quantum(&record)) { + action_tapping_process(record); + } +#else + if (IS_NOEVENT(record.event) || pre_process_record_quantum(&record)) { + process_record(&record); + } + if (!IS_NOEVENT(record.event)) { + dprint("processed: "); + debug_record(record); + dprintln(); + } +#endif +} + +#ifdef SWAP_HANDS_ENABLE +bool swap_hands = false; +bool swap_held = false; + +/** \brief Process Hand Swap + * + * FIXME: Needs documentation. + */ +void process_hand_swap(keyevent_t *event) { + static swap_state_row_t swap_state[MATRIX_ROWS]; + + keypos_t pos = event->key; + swap_state_row_t col_bit = (swap_state_row_t)1 << pos.col; + bool do_swap = event->pressed ? swap_hands : swap_state[pos.row] & (col_bit); + + if (do_swap) { + event->key.row = pgm_read_byte(&hand_swap_config[pos.row][pos.col].row); + event->key.col = pgm_read_byte(&hand_swap_config[pos.row][pos.col].col); + swap_state[pos.row] |= col_bit; + } else { + swap_state[pos.row] &= ~(col_bit); + } +} +#endif + +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) +bool disable_action_cache = false; + +void process_record_nocache(keyrecord_t *record) { + disable_action_cache = true; + process_record(record); + disable_action_cache = false; +} +#else +void process_record_nocache(keyrecord_t *record) { process_record(record); } +#endif + +__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; } + +__attribute__((weak)) void post_process_record_quantum(keyrecord_t *record) {} + +#ifndef NO_ACTION_TAPPING +/** \brief Allows for handling tap-hold actions immediately instead of waiting for TAPPING_TERM or another keypress. + * + * FIXME: Needs documentation. + */ +void process_record_tap_hint(keyrecord_t *record) { + action_t action = layer_switch_get_action(record->event.key); + + switch (action.kind.id) { +# ifdef SWAP_HANDS_ENABLE + case ACT_SWAP_HANDS: + switch (action.swap.code) { + case OP_SH_ONESHOT: + break; + case OP_SH_TAP_TOGGLE: + default: + swap_hands = !swap_hands; + swap_held = true; + } + break; +# endif + } +} +#endif + +/** \brief Take a key event (key press or key release) and processes it. + * + * FIXME: Needs documentation. + */ +void process_record(keyrecord_t *record) { + if (IS_NOEVENT(record->event)) { + return; + } + + if (!process_record_quantum(record)) { +#ifndef NO_ACTION_ONESHOT + if (is_oneshot_layer_active() && record->event.pressed) { + clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); + } +#endif + return; + } + + process_record_handler(record); + post_process_record_quantum(record); +} + +void process_record_handler(keyrecord_t *record) { +#ifdef COMBO_ENABLE + action_t action; + if (record->keycode) { + action = action_for_keycode(record->keycode); + } else { + action = store_or_get_action(record->event.pressed, record->event.key); + } +#else + action_t action = store_or_get_action(record->event.pressed, record->event.key); +#endif + dprint("ACTION: "); + debug_action(action); +#ifndef NO_ACTION_LAYER + dprint(" layer_state: "); + layer_debug(); + dprint(" default_layer_state: "); + default_layer_debug(); +#endif + dprintln(); + + process_action(record, action); +} + +#if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE) +void register_button(bool pressed, enum mouse_buttons button) { +# ifdef PS2_MOUSE_ENABLE + tp_buttons = pressed ? tp_buttons | button : tp_buttons & ~button; +# endif +# ifdef POINTING_DEVICE_ENABLE + report_mouse_t currentReport = pointing_device_get_report(); + currentReport.buttons = pressed ? currentReport.buttons | button : currentReport.buttons & ~button; + pointing_device_set_report(currentReport); +# endif +} +#endif + +/** \brief Take an action and processes it. + * + * FIXME: Needs documentation. + */ +void process_action(keyrecord_t *record, action_t action) { + keyevent_t event = record->event; +#ifndef NO_ACTION_TAPPING + uint8_t tap_count = record->tap.count; +#endif + +#ifndef NO_ACTION_ONESHOT + bool do_release_oneshot = false; + // notice we only clear the one shot layer if the pressed key is not a modifier. + if (is_oneshot_layer_active() && event.pressed && (action.kind.id == ACT_USAGE || !IS_MOD(action.key.code)) +# ifdef SWAP_HANDS_ENABLE + && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT) +# endif + ) { + clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); + do_release_oneshot = !is_oneshot_layer_active(); + } +#endif + + switch (action.kind.id) { + /* Key and Mods */ + case ACT_LMODS: + case ACT_RMODS: { + uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods : action.key.mods << 4; + if (event.pressed) { + if (mods) { + if (IS_MOD(action.key.code) || action.key.code == KC_NO) { + // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless. + // This also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT). + // Same applies for some keys like KC_MEH which are declared as MEH(KC_NO). + add_mods(mods); + } else { + add_weak_mods(mods); + } + send_keyboard_report(); + } + register_code(action.key.code); + } else { + unregister_code(action.key.code); + if (mods) { + if (IS_MOD(action.key.code) || action.key.code == KC_NO) { + del_mods(mods); + } else { + del_weak_mods(mods); + } + send_keyboard_report(); + } + } + } break; +#ifndef NO_ACTION_TAPPING + case ACT_LMODS_TAP: + case ACT_RMODS_TAP: { + uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods : action.key.mods << 4; + switch (action.layer_tap.code) { +# ifndef NO_ACTION_ONESHOT + case MODS_ONESHOT: + // Oneshot modifier + if (event.pressed) { + if (tap_count == 0) { + dprint("MODS_TAP: Oneshot: 0\n"); + register_mods(mods | get_oneshot_mods()); + } else if (tap_count == 1) { + dprint("MODS_TAP: Oneshot: start\n"); + set_oneshot_mods(mods | get_oneshot_mods()); +# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 + } else if (tap_count == ONESHOT_TAP_TOGGLE) { + dprint("MODS_TAP: Toggling oneshot"); + clear_oneshot_mods(); + set_oneshot_locked_mods(mods); + register_mods(mods); +# endif + } else { + register_mods(mods | get_oneshot_mods()); + } + } else { + if (tap_count == 0) { + clear_oneshot_mods(); + unregister_mods(mods); + } else if (tap_count == 1) { + // Retain Oneshot mods +# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 + if (mods & get_mods()) { + clear_oneshot_locked_mods(); + clear_oneshot_mods(); + unregister_mods(mods); + } + } else if (tap_count == ONESHOT_TAP_TOGGLE) { + // Toggle Oneshot Layer +# endif + } else { + clear_oneshot_mods(); + unregister_mods(mods); + } + } + break; +# endif + case MODS_TAP_TOGGLE: + if (event.pressed) { + if (tap_count <= TAPPING_TOGGLE) { + register_mods(mods); + } + } else { + if (tap_count < TAPPING_TOGGLE) { + unregister_mods(mods); + } + } + break; + default: + if (event.pressed) { + if (tap_count > 0) { +# if !defined(IGNORE_MOD_TAP_INTERRUPT) || defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY) + if ( +# ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY + !get_ignore_mod_tap_interrupt(get_event_keycode(record->event, false), record) && +# endif + record->tap.interrupted) { + dprint("mods_tap: tap: cancel: add_mods\n"); + // ad hoc: set 0 to cancel tap + record->tap.count = 0; + register_mods(mods); + } else +# endif + { + dprint("MODS_TAP: Tap: register_code\n"); + register_code(action.key.code); + } + } else { + dprint("MODS_TAP: No tap: add_mods\n"); + register_mods(mods); + } + } else { + if (tap_count > 0) { + dprint("MODS_TAP: Tap: unregister_code\n"); + if (action.layer_tap.code == KC_CAPS) { + wait_ms(TAP_HOLD_CAPS_DELAY); + } else { + wait_ms(TAP_CODE_DELAY); + } + unregister_code(action.key.code); + } else { + dprint("MODS_TAP: No tap: add_mods\n"); + unregister_mods(mods); + } + } + break; + } + } break; +#endif +#ifdef EXTRAKEY_ENABLE + /* other HID usage */ + case ACT_USAGE: + switch (action.usage.page) { + case PAGE_SYSTEM: + if (event.pressed) { + host_system_send(action.usage.code); + } else { + host_system_send(0); + } + break; + case PAGE_CONSUMER: + if (event.pressed) { + host_consumer_send(action.usage.code); + } else { + host_consumer_send(0); + } + break; + } + break; +#endif +#ifdef MOUSEKEY_ENABLE + /* Mouse key */ + case ACT_MOUSEKEY: + if (event.pressed) { + mousekey_on(action.key.code); + } else { + mousekey_off(action.key.code); + } + switch (action.key.code) { +# if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE) +# ifdef POINTING_DEVICE_ENABLE + case KC_MS_BTN1 ... KC_MS_BTN8: +# else + case KC_MS_BTN1 ... KC_MS_BTN3: +# endif + register_button(event.pressed, MOUSE_BTN_MASK(action.key.code - KC_MS_BTN1)); + break; +# endif + default: + mousekey_send(); + break; + } + break; +#endif +#ifndef NO_ACTION_LAYER + case ACT_LAYER: + if (action.layer_bitop.on == 0) { + /* Default Layer Bitwise Operation */ + if (!event.pressed) { + uint8_t shift = action.layer_bitop.part * 4; + layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift; + layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0; + switch (action.layer_bitop.op) { + case OP_BIT_AND: + default_layer_and(bits | mask); + break; + case OP_BIT_OR: + default_layer_or(bits | mask); + break; + case OP_BIT_XOR: + default_layer_xor(bits | mask); + break; + case OP_BIT_SET: + default_layer_set(bits | mask); + break; + } + } + } else { + /* Layer Bitwise Operation */ + if (event.pressed ? (action.layer_bitop.on & ON_PRESS) : (action.layer_bitop.on & ON_RELEASE)) { + uint8_t shift = action.layer_bitop.part * 4; + layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift; + layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0; + switch (action.layer_bitop.op) { + case OP_BIT_AND: + layer_and(bits | mask); + break; + case OP_BIT_OR: + layer_or(bits | mask); + break; + case OP_BIT_XOR: + layer_xor(bits | mask); + break; + case OP_BIT_SET: + layer_state_set(bits | mask); + break; + } + } + } + break; + case ACT_LAYER_MODS: + if (event.pressed) { + layer_on(action.layer_mods.layer); + register_mods(action.layer_mods.mods); + } else { + unregister_mods(action.layer_mods.mods); + layer_off(action.layer_mods.layer); + } + break; +# ifndef NO_ACTION_TAPPING + case ACT_LAYER_TAP: + case ACT_LAYER_TAP_EXT: + switch (action.layer_tap.code) { + case OP_TAP_TOGGLE: + /* tap toggle */ + if (event.pressed) { + if (tap_count < TAPPING_TOGGLE) { + layer_invert(action.layer_tap.val); + } + } else { + if (tap_count <= TAPPING_TOGGLE) { + layer_invert(action.layer_tap.val); + } + } + break; + case OP_ON_OFF: + event.pressed ? layer_on(action.layer_tap.val) : layer_off(action.layer_tap.val); + break; + case OP_OFF_ON: + event.pressed ? layer_off(action.layer_tap.val) : layer_on(action.layer_tap.val); + break; + case OP_SET_CLEAR: + event.pressed ? layer_move(action.layer_tap.val) : layer_clear(); + break; +# ifndef NO_ACTION_ONESHOT + case OP_ONESHOT: + // Oneshot modifier +# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 + do_release_oneshot = false; + if (event.pressed) { + del_mods(get_oneshot_locked_mods()); + if (get_oneshot_layer_state() == ONESHOT_TOGGLED) { + reset_oneshot_layer(); + layer_off(action.layer_tap.val); + break; + } else if (tap_count < ONESHOT_TAP_TOGGLE) { + layer_on(action.layer_tap.val); + set_oneshot_layer(action.layer_tap.val, ONESHOT_START); + } + } else { + add_mods(get_oneshot_locked_mods()); + if (tap_count >= ONESHOT_TAP_TOGGLE) { + reset_oneshot_layer(); + clear_oneshot_locked_mods(); + set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED); + } else { + clear_oneshot_layer_state(ONESHOT_PRESSED); + } + } +# else + if (event.pressed) { + layer_on(action.layer_tap.val); + set_oneshot_layer(action.layer_tap.val, ONESHOT_START); + } else { + clear_oneshot_layer_state(ONESHOT_PRESSED); + if (tap_count > 1) { + clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); + } + } +# endif + break; +# endif + default: + /* tap key */ + if (event.pressed) { + if (tap_count > 0) { + dprint("KEYMAP_TAP_KEY: Tap: register_code\n"); + register_code(action.layer_tap.code); + } else { + dprint("KEYMAP_TAP_KEY: No tap: On on press\n"); + layer_on(action.layer_tap.val); + } + } else { + if (tap_count > 0) { + dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n"); + if (action.layer_tap.code == KC_CAPS) { + wait_ms(TAP_HOLD_CAPS_DELAY); + } else { + wait_ms(TAP_CODE_DELAY); + } + unregister_code(action.layer_tap.code); + } else { + dprint("KEYMAP_TAP_KEY: No tap: Off on release\n"); + layer_off(action.layer_tap.val); + } + } + break; + } + break; +# endif +#endif + /* Extentions */ +#ifndef NO_ACTION_MACRO + case ACT_MACRO: + action_macro_play(action_get_macro(record, action.func.id, action.func.opt)); + break; +#endif +#ifdef SWAP_HANDS_ENABLE + case ACT_SWAP_HANDS: + switch (action.swap.code) { + case OP_SH_TOGGLE: + if (event.pressed) { + swap_hands = !swap_hands; + } + break; + case OP_SH_ON_OFF: + swap_hands = event.pressed; + break; + case OP_SH_OFF_ON: + swap_hands = !event.pressed; + break; + case OP_SH_ON: + if (!event.pressed) { + swap_hands = true; + } + break; + case OP_SH_OFF: + if (!event.pressed) { + swap_hands = false; + } + break; +# ifndef NO_ACTION_ONESHOT + case OP_SH_ONESHOT: + if (event.pressed) { + set_oneshot_swaphands(); + } else { + release_oneshot_swaphands(); + } + break; +# endif + +# ifndef NO_ACTION_TAPPING + case OP_SH_TAP_TOGGLE: + /* tap toggle */ + + if (event.pressed) { + if (swap_held) { + swap_held = false; + } else { + swap_hands = !swap_hands; + } + } else { + if (tap_count < TAPPING_TOGGLE) { + swap_hands = !swap_hands; + } + } + break; + default: + /* tap key */ + if (tap_count > 0) { + if (swap_held) { + swap_hands = !swap_hands; // undo hold set up in _tap_hint + swap_held = false; + } + if (event.pressed) { + register_code(action.swap.code); + } else { + wait_ms(TAP_CODE_DELAY); + unregister_code(action.swap.code); + *record = (keyrecord_t){}; // hack: reset tap mode + } + } else { + if (swap_held && !event.pressed) { + swap_hands = !swap_hands; // undo hold set up in _tap_hint + swap_held = false; + } + } +# endif + } +#endif +#ifndef NO_ACTION_FUNCTION + case ACT_FUNCTION: + action_function(record, action.func.id, action.func.opt); + break; +#endif + default: + break; + } + +#ifndef NO_ACTION_LAYER + // if this event is a layer action, update the leds + switch (action.kind.id) { + case ACT_LAYER: + case ACT_LAYER_MODS: +# ifndef NO_ACTION_TAPPING + case ACT_LAYER_TAP: + case ACT_LAYER_TAP_EXT: +# endif + led_set(host_keyboard_leds()); + break; + default: + break; + } +#endif + +#ifndef NO_ACTION_TAPPING +# if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) + if (!is_tap_action(action)) { + retro_tapping_counter = 0; + } else { + if (event.pressed) { + if (tap_count > 0) { + retro_tapping_counter = 0; + } + } else { + if (tap_count > 0) { + retro_tapping_counter = 0; + } else { + if ( +# ifdef RETRO_TAPPING_PER_KEY + get_retro_tapping(get_event_keycode(record->event, false), record) && +# endif + retro_tapping_counter == 2) { + tap_code(action.layer_tap.code); + } + retro_tapping_counter = 0; + } + } + } +# endif +#endif + +#ifdef SWAP_HANDS_ENABLE +# ifndef NO_ACTION_ONESHOT + if (event.pressed && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)) { + use_oneshot_swaphands(); + } +# endif +#endif + +#ifndef NO_ACTION_ONESHOT + /* Because we switch layers after a oneshot event, we need to release the + * key before we leave the layer or no key up event will be generated. + */ + if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED)) { + record->event.pressed = false; + layer_on(get_oneshot_layer()); + process_record(record); + layer_off(get_oneshot_layer()); + } +#endif +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void register_code(uint8_t code) { + if (code == KC_NO) { + return; + } +#ifdef LOCKING_SUPPORT_ENABLE + else if (KC_LOCKING_CAPS == code) { +# ifdef LOCKING_RESYNC_ENABLE + // Resync: ignore if caps lock already is on + if (host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK)) return; +# endif + add_key(KC_CAPSLOCK); + send_keyboard_report(); + wait_ms(100); + del_key(KC_CAPSLOCK); + send_keyboard_report(); + } + + else if (KC_LOCKING_NUM == code) { +# ifdef LOCKING_RESYNC_ENABLE + if (host_keyboard_leds() & (1 << USB_LED_NUM_LOCK)) return; +# endif + add_key(KC_NUMLOCK); + send_keyboard_report(); + wait_ms(100); + del_key(KC_NUMLOCK); + send_keyboard_report(); + } + + else if (KC_LOCKING_SCROLL == code) { +# ifdef LOCKING_RESYNC_ENABLE + if (host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK)) return; +# endif + add_key(KC_SCROLLLOCK); + send_keyboard_report(); + wait_ms(100); + del_key(KC_SCROLLLOCK); + send_keyboard_report(); + } +#endif + + else if IS_KEY (code) { + // TODO: should push command_proc out of this block? + if (command_proc(code)) return; + +#ifndef NO_ACTION_ONESHOT +/* TODO: remove + if (oneshot_state.mods && !oneshot_state.disabled) { + uint8_t tmp_mods = get_mods(); + add_mods(oneshot_state.mods); + + add_key(code); + send_keyboard_report(); + + set_mods(tmp_mods); + send_keyboard_report(); + oneshot_cancel(); + } else +*/ +#endif + { + // Force a new key press if the key is already pressed + // without this, keys with the same keycode, but different + // modifiers will be reported incorrectly, see issue #1708 + if (is_key_pressed(keyboard_report, code)) { + del_key(code); + send_keyboard_report(); + } + add_key(code); + send_keyboard_report(); + } + } else if IS_MOD (code) { + add_mods(MOD_BIT(code)); + send_keyboard_report(); + } +#ifdef EXTRAKEY_ENABLE + else if IS_SYSTEM (code) { + host_system_send(KEYCODE2SYSTEM(code)); + } else if IS_CONSUMER (code) { + host_consumer_send(KEYCODE2CONSUMER(code)); + } +#endif +#ifdef MOUSEKEY_ENABLE + else if IS_MOUSEKEY (code) { + mousekey_on(code); + mousekey_send(); + } +#endif +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void unregister_code(uint8_t code) { + if (code == KC_NO) { + return; + } +#ifdef LOCKING_SUPPORT_ENABLE + else if (KC_LOCKING_CAPS == code) { +# ifdef LOCKING_RESYNC_ENABLE + // Resync: ignore if caps lock already is off + if (!(host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK))) return; +# endif + add_key(KC_CAPSLOCK); + send_keyboard_report(); + del_key(KC_CAPSLOCK); + send_keyboard_report(); + } + + else if (KC_LOCKING_NUM == code) { +# ifdef LOCKING_RESYNC_ENABLE + if (!(host_keyboard_leds() & (1 << USB_LED_NUM_LOCK))) return; +# endif + add_key(KC_NUMLOCK); + send_keyboard_report(); + del_key(KC_NUMLOCK); + send_keyboard_report(); + } + + else if (KC_LOCKING_SCROLL == code) { +# ifdef LOCKING_RESYNC_ENABLE + if (!(host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK))) return; +# endif + add_key(KC_SCROLLLOCK); + send_keyboard_report(); + del_key(KC_SCROLLLOCK); + send_keyboard_report(); + } +#endif + + else if IS_KEY (code) { + del_key(code); + send_keyboard_report(); + } else if IS_MOD (code) { + del_mods(MOD_BIT(code)); + send_keyboard_report(); + } else if IS_SYSTEM (code) { + host_system_send(0); + } else if IS_CONSUMER (code) { + host_consumer_send(0); + } +#ifdef MOUSEKEY_ENABLE + else if IS_MOUSEKEY (code) { + mousekey_off(code); + mousekey_send(); + } +#endif +} + +/** \brief Tap a keycode with a delay. + * + * \param code The basic keycode to tap. + * \param delay The amount of time in milliseconds to leave the keycode registered, before unregistering it. + */ +void tap_code_delay(uint8_t code, uint16_t delay) { + register_code(code); + for (uint16_t i = delay; i > 0; i--) { + wait_ms(1); + } + unregister_code(code); +} + +/** \brief Tap a keycode with the default delay. + * + * \param code The basic keycode to tap. If `code` is `KC_CAPS`, the delay will be `TAP_HOLD_CAPS_DELAY`, otherwise `TAP_CODE_DELAY`, if defined. + */ +void tap_code(uint8_t code) { tap_code_delay(code, code == KC_CAPS ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY); } + +/** \brief Adds the given physically pressed modifiers and sends a keyboard report immediately. + * + * \param mods A bitfield of modifiers to register. + */ +void register_mods(uint8_t mods) { + if (mods) { + add_mods(mods); + send_keyboard_report(); + } +} + +/** \brief Removes the given physically pressed modifiers and sends a keyboard report immediately. + * + * \param mods A bitfield of modifiers to unregister. + */ +void unregister_mods(uint8_t mods) { + if (mods) { + del_mods(mods); + send_keyboard_report(); + } +} + +/** \brief Adds the given weak modifiers and sends a keyboard report immediately. + * + * \param mods A bitfield of modifiers to register. + */ +void register_weak_mods(uint8_t mods) { + if (mods) { + add_weak_mods(mods); + send_keyboard_report(); + } +} + +/** \brief Removes the given weak modifiers and sends a keyboard report immediately. + * + * \param mods A bitfield of modifiers to unregister. + */ +void unregister_weak_mods(uint8_t mods) { + if (mods) { + del_weak_mods(mods); + send_keyboard_report(); + } +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void clear_keyboard(void) { + clear_mods(); + clear_keyboard_but_mods(); +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void clear_keyboard_but_mods(void) { + clear_keys(); + clear_keyboard_but_mods_and_keys(); +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void clear_keyboard_but_mods_and_keys() { +#ifdef EXTRAKEY_ENABLE + host_system_send(0); + host_consumer_send(0); +#endif + clear_weak_mods(); + clear_macro_mods(); + send_keyboard_report(); +#ifdef MOUSEKEY_ENABLE + mousekey_clear(); + mousekey_send(); +#endif +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +bool is_tap_key(keypos_t key) { + action_t action = layer_switch_get_action(key); + return is_tap_action(action); +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +bool is_tap_record(keyrecord_t *record) { +#ifdef COMBO_ENABLE + action_t action; + if (record->keycode) { + action = action_for_keycode(record->keycode); + } else { + action = layer_switch_get_action(record->event.key); + } +#else + action_t action = layer_switch_get_action(record->event.key); +#endif + return is_tap_action(action); +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +bool is_tap_action(action_t action) { + switch (action.kind.id) { + case ACT_LMODS_TAP: + case ACT_RMODS_TAP: + case ACT_LAYER_TAP: + case ACT_LAYER_TAP_EXT: + switch (action.layer_tap.code) { + case KC_NO ... KC_RGUI: + case OP_TAP_TOGGLE: + case OP_ONESHOT: + return true; + } + return false; + case ACT_SWAP_HANDS: + switch (action.swap.code) { + case KC_NO ... KC_RGUI: + case OP_SH_TAP_TOGGLE: + return true; + } + return false; + case ACT_MACRO: + case ACT_FUNCTION: + if (action.func.opt & FUNC_TAP) { + return true; + } + return false; + } + return false; +} + +/** \brief Debug print (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); } +/** \brief Debug print (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void debug_record(keyrecord_t record) { + debug_event(record.event); +#ifndef NO_ACTION_TAPPING + dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' ')); +#endif +} + +/** \brief Debug print (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void debug_action(action_t action) { + switch (action.kind.id) { + case ACT_LMODS: + dprint("ACT_LMODS"); + break; + case ACT_RMODS: + dprint("ACT_RMODS"); + break; + case ACT_LMODS_TAP: + dprint("ACT_LMODS_TAP"); + break; + case ACT_RMODS_TAP: + dprint("ACT_RMODS_TAP"); + break; + case ACT_USAGE: + dprint("ACT_USAGE"); + break; + case ACT_MOUSEKEY: + dprint("ACT_MOUSEKEY"); + break; + case ACT_LAYER: + dprint("ACT_LAYER"); + break; + case ACT_LAYER_MODS: + dprint("ACT_LAYER_MODS"); + break; + case ACT_LAYER_TAP: + dprint("ACT_LAYER_TAP"); + break; + case ACT_LAYER_TAP_EXT: + dprint("ACT_LAYER_TAP_EXT"); + break; + case ACT_MACRO: + dprint("ACT_MACRO"); + break; + case ACT_FUNCTION: + dprint("ACT_FUNCTION"); + break; + case ACT_SWAP_HANDS: + dprint("ACT_SWAP_HANDS"); + break; + default: + dprint("UNKNOWN"); + break; + } + dprintf("[%X:%02X]", action.kind.param >> 8, action.kind.param & 0xff); +} diff --git a/quantum/action.h b/quantum/action.h new file mode 100644 index 0000000000..3d357b33b8 --- /dev/null +++ b/quantum/action.h @@ -0,0 +1,132 @@ +/* +Copyright 2012,2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include +#include "keyboard.h" +#include "keycode.h" +#include "action_code.h" +#include "action_macro.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable macro and function features when LTO is enabled, since they break */ +#ifdef LTO_ENABLE +# ifndef NO_ACTION_MACRO +# define NO_ACTION_MACRO +# endif +# ifndef NO_ACTION_FUNCTION +# define NO_ACTION_FUNCTION +# endif +#endif + +/* tapping count and state */ +typedef struct { + bool interrupted : 1; + bool reserved2 : 1; + bool reserved1 : 1; + bool reserved0 : 1; + uint8_t count : 4; +} tap_t; + +/* Key event container for recording */ +typedef struct { + keyevent_t event; +#ifndef NO_ACTION_TAPPING + tap_t tap; +#endif +#ifdef COMBO_ENABLE + uint16_t keycode; +#endif +} keyrecord_t; + +/* Execute action per keyevent */ +void action_exec(keyevent_t event); + +/* action for key */ +action_t action_for_key(uint8_t layer, keypos_t key); +action_t action_for_keycode(uint16_t keycode); + +/* macro */ +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt); + +/* user defined special function */ +void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); + +/* keyboard-specific key event (pre)processing */ +bool process_record_quantum(keyrecord_t *record); + +/* Utilities for actions. */ +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) +extern bool disable_action_cache; +#endif + +/* Code for handling one-handed key modifiers. */ +#ifdef SWAP_HANDS_ENABLE +extern bool swap_hands; +extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS]; +# if (MATRIX_COLS <= 8) +typedef uint8_t swap_state_row_t; +# elif (MATRIX_COLS <= 16) +typedef uint16_t swap_state_row_t; +# elif (MATRIX_COLS <= 32) +typedef uint32_t swap_state_row_t; +# else +# error "MATRIX_COLS: invalid value" +# endif + +void process_hand_swap(keyevent_t *record); +#endif + +void process_record_nocache(keyrecord_t *record); +void process_record(keyrecord_t *record); +void process_record_handler(keyrecord_t *record); +void post_process_record_quantum(keyrecord_t *record); +void process_action(keyrecord_t *record, action_t action); +void register_code(uint8_t code); +void unregister_code(uint8_t code); +void tap_code(uint8_t code); +void tap_code_delay(uint8_t code, uint16_t delay); +void register_mods(uint8_t mods); +void unregister_mods(uint8_t mods); +void register_weak_mods(uint8_t mods); +void unregister_weak_mods(uint8_t mods); +// void set_mods(uint8_t mods); +void clear_keyboard(void); +void clear_keyboard_but_mods(void); +void clear_keyboard_but_mods_and_keys(void); +void layer_switch(uint8_t new_layer); +bool is_tap_key(keypos_t key); +bool is_tap_record(keyrecord_t *record); +bool is_tap_action(action_t action); + +#ifndef NO_ACTION_TAPPING +void process_record_tap_hint(keyrecord_t *record); +#endif + +/* debug */ +void debug_event(keyevent_t event); +void debug_record(keyrecord_t record); +void debug_action(action_t action); + +#ifdef __cplusplus +} +#endif diff --git a/quantum/action_code.h b/quantum/action_code.h new file mode 100644 index 0000000000..eb18c36ae8 --- /dev/null +++ b/quantum/action_code.h @@ -0,0 +1,308 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 + +/** \brief Action codes + * + * 16bit code: action_kind(4bit) + action_parameter(12bit) + * + * Key Actions(00xx) + * ----------------- + * ACT_MODS(000r): + * 000r|0000|0000 0000 No action code + * 000r|0000|0000 0001 Transparent code + * 000r|0000| keycode Key + * 000r|mods|0000 0000 Modifiers + * 000r|mods| keycode Modifiers+Key(Modified key) + * r: Left/Right flag(Left:0, Right:1) + * + * ACT_MODS_TAP(001r): + * 001r|mods|0000 0000 Modifiers with OneShot + * 001r|mods|0000 0001 Modifiers with tap toggle + * 001r|mods|0000 00xx (reserved) + * 001r|mods| keycode Modifiers with Tap Key(Dual role) + * + * Other Keys(01xx) + * ---------------- + * ACT_USAGE(0100): TODO: Not needed? + * 0100|00| usage(10) System control(0x80) - General Desktop page(0x01) + * 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C) + * 0100|10| usage(10) (reserved) + * 0100|11| usage(10) (reserved) + * + * ACT_MOUSEKEY(0101): TODO: Merge these two actions to conserve space? + * 0101|xxxx| keycode Mouse key + * + * ACT_SWAP_HANDS(0110): + * 0110|xxxx| keycode Swap hands (keycode on tap, or options) + * + * 0111|xxxx xxxx xxxx (reserved) + * + * Layer Actions(10xx) + * ------------------- + * ACT_LAYER(1000): + * 1000|oo00|pppE BBBB Default Layer Bitwise operation + * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET) + * ppp: 4-bit chunk part(0-7) + * EBBBB: bits and extra bit + * 1000|ooee|pppE BBBB Layer Bitwise Operation + * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET) + * ppp: 4-bit chunk part(0-7) + * EBBBB: bits and extra bit + * ee: on event(01:press, 10:release, 11:both) + * + * ACT_LAYER_MODS(1001): + * 1001|LLLL| mods Layer with modifiers held + * + * ACT_LAYER_TAP(101x): + * 101E|LLLL| keycode On/Off with tap key (0x00-DF)[TAP] + * 101E|LLLL|1110 mods On/Off with modifiers (0xE0-EF)[NOT TAP] + * 101E|LLLL|1111 0000 Invert with tap toggle (0xF0) [TAP] + * 101E|LLLL|1111 0001 On/Off (0xF1) [NOT TAP] + * 101E|LLLL|1111 0010 Off/On (0xF2) [NOT TAP] + * 101E|LLLL|1111 0011 Set/Clear (0xF3) [NOT TAP] + * 101E|LLLL|1111 0100 One Shot Layer (0xF4) [TAP] + * 101E|LLLL|1111 xxxx Reserved (0xF5-FF) + * ELLLL: layer 0-31(E: extra bit for layer 16-31) + * + * Extensions(11xx) + * ---------------- + * ACT_MACRO(1100): + * 1100|opt | id(8) Macro play? + * 1100|1111| id(8) Macro record? + * + * 1101|xxxx xxxx xxxx (reserved) + * 1110|xxxx xxxx xxxx (reserved) + * + * ACT_FUNCTION(1111): + * 1111| address(12) Function? + * 1111|opt | id(8) Function? + */ +enum action_kind_id { + /* Key Actions */ + ACT_MODS = 0b0000, + ACT_LMODS = 0b0000, + ACT_RMODS = 0b0001, + ACT_MODS_TAP = 0b0010, + ACT_LMODS_TAP = 0b0010, + ACT_RMODS_TAP = 0b0011, + /* Other Keys */ + ACT_USAGE = 0b0100, + ACT_MOUSEKEY = 0b0101, + /* One-hand Support */ + ACT_SWAP_HANDS = 0b0110, + /* Layer Actions */ + ACT_LAYER = 0b1000, + ACT_LAYER_MODS = 0b1001, + ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */ + ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */ + /* Extensions */ + ACT_MACRO = 0b1100, + ACT_FUNCTION = 0b1111 +}; + +/** \brief Action Code Struct + * + * NOTE: + * In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15). + * AVR looks like a little endian in avr-gcc. + * Not portable across compiler/endianness? + * + * Byte order and bit order of 0x1234: + * Big endian: Little endian: + * -------------------- -------------------- + * FEDC BA98 7654 3210 0123 4567 89AB CDEF + * 0001 0010 0011 0100 0010 1100 0100 1000 + * 0x12 0x34 0x34 0x12 + */ +typedef union { + uint16_t code; + struct action_kind { + uint16_t param : 12; + uint8_t id : 4; + } kind; + struct action_key { + uint8_t code : 8; + uint8_t mods : 4; + uint8_t kind : 4; + } key; + struct action_layer_bitop { + uint8_t bits : 4; + uint8_t xbit : 1; + uint8_t part : 3; + uint8_t on : 2; + uint8_t op : 2; + uint8_t kind : 4; + } layer_bitop; + struct action_layer_mods { + uint8_t mods : 8; + uint8_t layer : 4; + uint8_t kind : 4; + } layer_mods; + struct action_layer_tap { + uint8_t code : 8; + uint8_t val : 5; + uint8_t kind : 3; + } layer_tap; + struct action_usage { + uint16_t code : 10; + uint8_t page : 2; + uint8_t kind : 4; + } usage; + struct action_function { + uint8_t id : 8; + uint8_t opt : 4; + uint8_t kind : 4; + } func; + struct action_swap { + uint8_t code : 8; + uint8_t opt : 4; + uint8_t kind : 4; + } swap; +} action_t; + +/* action utility */ +#define ACTION_NO 0 +#define ACTION_TRANSPARENT 1 +#define ACTION(kind, param) ((kind) << 12 | (param)) + +/** \brief Key Actions + * + * Mod bits: 43210 + * bit 0 ||||+- Control + * bit 1 |||+-- Shift + * bit 2 ||+--- Alt + * bit 3 |+---- Gui + * bit 4 +----- LR flag(Left:0, Right:1) + */ +enum mods_bit { + MOD_LCTL = 0x01, + MOD_LSFT = 0x02, + MOD_LALT = 0x04, + MOD_LGUI = 0x08, + MOD_RCTL = 0x11, + MOD_RSFT = 0x12, + MOD_RALT = 0x14, + MOD_RGUI = 0x18, +}; +enum mods_codes { + MODS_ONESHOT = 0x00, + MODS_TAP_TOGGLE = 0x01, +}; +#define ACTION_KEY(key) ACTION(ACT_MODS, (key)) +#define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f) << 8 | 0) +#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f) << 8 | (key)) +#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | (key)) +#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | MODS_ONESHOT) +#define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | MODS_TAP_TOGGLE) + +/** \brief Other Keys + */ +enum usage_pages { PAGE_SYSTEM, PAGE_CONSUMER }; +#define ACTION_USAGE_SYSTEM(id) ACTION(ACT_USAGE, PAGE_SYSTEM << 10 | (id)) +#define ACTION_USAGE_CONSUMER(id) ACTION(ACT_USAGE, PAGE_CONSUMER << 10 | (id)) +#define ACTION_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key) + +/** \brief Layer Actions + */ +enum layer_param_on { + ON_PRESS = 1, + ON_RELEASE = 2, + ON_BOTH = 3, +}; + +/** \brief Layer Actions + */ +enum layer_param_bit_op { + OP_BIT_AND = 0, + OP_BIT_OR = 1, + OP_BIT_XOR = 2, + OP_BIT_SET = 3, +}; + +/** \brief Layer Actions + */ +enum layer_param_tap_op { + OP_TAP_TOGGLE = 0xF0, + OP_ON_OFF, + OP_OFF_ON, + OP_SET_CLEAR, + OP_ONESHOT, +}; +#define ACTION_LAYER_BITOP(op, part, bits, on) ACTION(ACT_LAYER, (op) << 10 | (on) << 8 | (part) << 5 | ((bits)&0x1f)) +#define ACTION_LAYER_TAP(layer, key) ACTION(ACT_LAYER_TAP, (layer) << 8 | (key)) +/* Default Layer */ +#define ACTION_DEFAULT_LAYER_SET(layer) ACTION_DEFAULT_LAYER_BIT_SET((layer) / 4, 1 << ((layer) % 4)) +/* Layer Operation */ +#define ACTION_LAYER_CLEAR(on) ACTION_LAYER_BIT_AND(0, 0, (on)) +#define ACTION_LAYER_MOMENTARY(layer) ACTION_LAYER_ON_OFF(layer) +#define ACTION_LAYER_TOGGLE(layer) ACTION_LAYER_INVERT(layer, ON_RELEASE) +#define ACTION_LAYER_INVERT(layer, on) ACTION_LAYER_BIT_XOR((layer) / 4, 1 << ((layer) % 4), (on)) +#define ACTION_LAYER_ON(layer, on) ACTION_LAYER_BIT_OR((layer) / 4, 1 << ((layer) % 4), (on)) +#define ACTION_LAYER_OFF(layer, on) ACTION_LAYER_BIT_AND((layer) / 4, ~(1 << ((layer) % 4)), (on)) +#define ACTION_LAYER_SET(layer, on) ACTION_LAYER_BIT_SET((layer) / 4, 1 << ((layer) % 4), (on)) +#define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF) +#define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON) +#define ACTION_LAYER_SET_CLEAR(layer) ACTION_LAYER_TAP((layer), OP_SET_CLEAR) +#define ACTION_LAYER_ONESHOT(layer) ACTION_LAYER_TAP((layer), OP_ONESHOT) +#define ACTION_LAYER_MODS(layer, mods) ACTION(ACT_LAYER_MODS, (layer) << 8 | (mods)) +/* With Tapping */ +#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key)) +#define ACTION_LAYER_TAP_TOGGLE(layer) ACTION_LAYER_TAP((layer), OP_TAP_TOGGLE) +/* Bitwise Operation */ +#define ACTION_LAYER_BIT_AND(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), (on)) +#define ACTION_LAYER_BIT_OR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), (on)) +#define ACTION_LAYER_BIT_XOR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), (on)) +#define ACTION_LAYER_BIT_SET(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), (on)) +/* Default Layer Bitwise Operation */ +#define ACTION_DEFAULT_LAYER_BIT_AND(part, bits) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), 0) +#define ACTION_DEFAULT_LAYER_BIT_OR(part, bits) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), 0) +#define ACTION_DEFAULT_LAYER_BIT_XOR(part, bits) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), 0) +#define ACTION_DEFAULT_LAYER_BIT_SET(part, bits) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), 0) + +/* Macro */ +#define ACTION_MACRO(id) ACTION(ACT_MACRO, (id)) +#define ACTION_MACRO_TAP(id) ACTION(ACT_MACRO, FUNC_TAP << 8 | (id)) +#define ACTION_MACRO_OPT(id, opt) ACTION(ACT_MACRO, (opt) << 8 | (id)) +/* Function */ +enum function_opts { + FUNC_TAP = 0x8, /* indciates function is tappable */ +}; +#define ACTION_FUNCTION(id) ACTION(ACT_FUNCTION, (id)) +#define ACTION_FUNCTION_TAP(id) ACTION(ACT_FUNCTION, FUNC_TAP << 8 | (id)) +#define ACTION_FUNCTION_OPT(id, opt) ACTION(ACT_FUNCTION, (opt) << 8 | (id)) +/* OneHand Support */ +enum swap_hands_param_tap_op { + OP_SH_TOGGLE = 0xF0, + OP_SH_TAP_TOGGLE, + OP_SH_ON_OFF, + OP_SH_OFF_ON, + OP_SH_OFF, + OP_SH_ON, + OP_SH_ONESHOT, +}; + +#define ACTION_SWAP_HANDS() ACTION_SWAP_HANDS_ON_OFF() +#define ACTION_SWAP_HANDS_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TOGGLE) +#define ACTION_SWAP_HANDS_TAP_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TAP_TOGGLE) +#define ACTION_SWAP_HANDS_ONESHOT() ACTION(ACT_SWAP_HANDS, OP_SH_ONESHOT) +#define ACTION_SWAP_HANDS_TAP_KEY(key) ACTION(ACT_SWAP_HANDS, key) +#define ACTION_SWAP_HANDS_ON_OFF() ACTION(ACT_SWAP_HANDS, OP_SH_ON_OFF) +#define ACTION_SWAP_HANDS_OFF_ON() ACTION(ACT_SWAP_HANDS, OP_SH_OFF_ON) +#define ACTION_SWAP_HANDS_ON() ACTION(ACT_SWAP_HANDS, OP_SH_ON) +#define ACTION_SWAP_HANDS_OFF() ACTION(ACT_SWAP_HANDS, OP_SH_OFF) diff --git a/quantum/action_layer.c b/quantum/action_layer.c new file mode 100644 index 0000000000..ed1a4bd20d --- /dev/null +++ b/quantum/action_layer.c @@ -0,0 +1,279 @@ +#include +#include "keyboard.h" +#include "action.h" +#include "util.h" +#include "action_layer.h" + +#ifdef DEBUG_ACTION +# include "debug.h" +#else +# include "nodebug.h" +#endif + +/** \brief Default Layer State + */ +layer_state_t default_layer_state = 0; + +/** \brief Default Layer State Set At user Level + * + * Run user code on default layer state change + */ +__attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state) { return state; } + +/** \brief Default Layer State Set At Keyboard Level + * + * Run keyboard code on default layer state change + */ +__attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state) { return default_layer_state_set_user(state); } + +/** \brief Default Layer State Set + * + * Static function to set the default layer state, prints debug info and clears keys + */ +static void default_layer_state_set(layer_state_t state) { + state = default_layer_state_set_kb(state); + debug("default_layer_state: "); + default_layer_debug(); + debug(" to "); + default_layer_state = state; + default_layer_debug(); + debug("\n"); +#ifdef STRICT_LAYER_RELEASE + clear_keyboard_but_mods(); // To avoid stuck keys +#else + clear_keyboard_but_mods_and_keys(); // Don't reset held keys +#endif +} + +/** \brief Default Layer Print + * + * Print out the hex value of the 32-bit default layer state, as well as the value of the highest bit. + */ +void default_layer_debug(void) { dprintf("%08lX(%u)", default_layer_state, get_highest_layer(default_layer_state)); } + +/** \brief Default Layer Set + * + * Sets the default layer state. + */ +void default_layer_set(layer_state_t state) { default_layer_state_set(state); } + +#ifndef NO_ACTION_LAYER +/** \brief Default Layer Or + * + * Turns on the default layer based on matching bits between specifed layer and existing layer state + */ +void default_layer_or(layer_state_t state) { default_layer_state_set(default_layer_state | state); } +/** \brief Default Layer And + * + * Turns on default layer based on matching enabled bits between specifed layer and existing layer state + */ +void default_layer_and(layer_state_t state) { default_layer_state_set(default_layer_state & state); } +/** \brief Default Layer Xor + * + * Turns on default layer based on non-matching bits between specifed layer and existing layer state + */ +void default_layer_xor(layer_state_t state) { default_layer_state_set(default_layer_state ^ state); } +#endif + +#ifndef NO_ACTION_LAYER +/** \brief Keymap Layer State + */ +layer_state_t layer_state = 0; + +/** \brief Layer state set user + * + * Runs user code on layer state change + */ +__attribute__((weak)) layer_state_t layer_state_set_user(layer_state_t state) { return state; } + +/** \brief Layer state set keyboard + * + * Runs keyboard code on layer state change + */ +__attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) { return layer_state_set_user(state); } + +/** \brief Layer state set + * + * Sets the layer to match the specifed state (a bitmask) + */ +void layer_state_set(layer_state_t state) { + state = layer_state_set_kb(state); + dprint("layer_state: "); + layer_debug(); + dprint(" to "); + layer_state = state; + layer_debug(); + dprintln(); +# ifdef STRICT_LAYER_RELEASE + clear_keyboard_but_mods(); // To avoid stuck keys +# else + clear_keyboard_but_mods_and_keys(); // Don't reset held keys +# endif +} + +/** \brief Layer clear + * + * Turn off all layers + */ +void layer_clear(void) { layer_state_set(0); } + +/** \brief Layer state is + * + * Return whether the given state is on (it might still be shadowed by a higher state, though) + */ +bool layer_state_is(uint8_t layer) { return layer_state_cmp(layer_state, layer); } + +/** \brief Layer state compare + * + * Used for comparing layers {mostly used for unit testing} + */ +bool layer_state_cmp(layer_state_t cmp_layer_state, uint8_t layer) { + if (!cmp_layer_state) { + return layer == 0; + } + return (cmp_layer_state & ((layer_state_t)1 << layer)) != 0; +} + +/** \brief Layer move + * + * Turns on the given layer and turn off all other layers + */ +void layer_move(uint8_t layer) { layer_state_set((layer_state_t)1 << layer); } + +/** \brief Layer on + * + * Turns on given layer + */ +void layer_on(uint8_t layer) { layer_state_set(layer_state | ((layer_state_t)1 << layer)); } + +/** \brief Layer off + * + * Turns off given layer + */ +void layer_off(uint8_t layer) { layer_state_set(layer_state & ~((layer_state_t)1 << layer)); } + +/** \brief Layer invert + * + * Toggle the given layer (set it if it's unset, or unset it if it's set) + */ +void layer_invert(uint8_t layer) { layer_state_set(layer_state ^ ((layer_state_t)1 << layer)); } + +/** \brief Layer or + * + * Turns on layers based on matching bits between specifed layer and existing layer state + */ +void layer_or(layer_state_t state) { layer_state_set(layer_state | state); } +/** \brief Layer and + * + * Turns on layers based on matching enabled bits between specifed layer and existing layer state + */ +void layer_and(layer_state_t state) { layer_state_set(layer_state & state); } +/** \brief Layer xor + * + * Turns on layers based on non-matching bits between specifed layer and existing layer state + */ +void layer_xor(layer_state_t state) { layer_state_set(layer_state ^ state); } + +/** \brief Layer debug printing + * + * Print out the hex value of the 32-bit layer state, as well as the value of the highest bit. + */ +void layer_debug(void) { dprintf("%08lX(%u)", layer_state, get_highest_layer(layer_state)); } +#endif + +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) +/** \brief source layer cache + */ + +uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}}; + +/** \brief update source layers cache + * + * Updates the cached keys when changing layers + */ +void update_source_layers_cache(keypos_t key, uint8_t layer) { + const uint8_t key_number = key.col + (key.row * MATRIX_COLS); + const uint8_t storage_row = key_number / 8; + const uint8_t storage_bit = key_number % 8; + + for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { + source_layers_cache[storage_row][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ source_layers_cache[storage_row][bit_number]) & (1U << storage_bit); + } +} + +/** \brief read source layers cache + * + * reads the cached keys stored when the layer was changed + */ +uint8_t read_source_layers_cache(keypos_t key) { + const uint8_t key_number = key.col + (key.row * MATRIX_COLS); + const uint8_t storage_row = key_number / 8; + const uint8_t storage_bit = key_number % 8; + uint8_t layer = 0; + + for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { + layer |= ((source_layers_cache[storage_row][bit_number] & (1U << storage_bit)) != 0) << bit_number; + } + + return layer; +} +#endif + +/** \brief Store or get action (FIXME: Needs better summary) + * + * Make sure the action triggered when the key is released is the same + * one as the one triggered on press. It's important for the mod keys + * when the layer is switched after the down event but before the up + * event as they may get stuck otherwise. + */ +action_t store_or_get_action(bool pressed, keypos_t key) { +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) + if (disable_action_cache) { + return layer_switch_get_action(key); + } + + uint8_t layer; + + if (pressed) { + layer = layer_switch_get_layer(key); + update_source_layers_cache(key, layer); + } else { + layer = read_source_layers_cache(key); + } + return action_for_key(layer, key); +#else + return layer_switch_get_action(key); +#endif +} + +/** \brief Layer switch get layer + * + * Gets the layer based on key info + */ +uint8_t layer_switch_get_layer(keypos_t key) { +#ifndef NO_ACTION_LAYER + action_t action; + action.code = ACTION_TRANSPARENT; + + layer_state_t layers = layer_state | default_layer_state; + /* check top layer first */ + for (int8_t i = MAX_LAYER - 1; i >= 0; i--) { + if (layers & ((layer_state_t)1 << i)) { + action = action_for_key(i, key); + if (action.code != ACTION_TRANSPARENT) { + return i; + } + } + } + /* fall back to layer 0 */ + return 0; +#else + return get_highest_layer(default_layer_state); +#endif +} + +/** \brief Layer switch get layer + * + * Gets action code based on key position + */ +action_t layer_switch_get_action(keypos_t key) { return action_for_key(layer_switch_get_layer(key), key); } diff --git a/quantum/action_layer.h b/quantum/action_layer.h new file mode 100644 index 0000000000..b87d096eed --- /dev/null +++ b/quantum/action_layer.h @@ -0,0 +1,147 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include "keyboard.h" +#include "action.h" + +#ifdef DYNAMIC_KEYMAP_ENABLE +# ifndef DYNAMIC_KEYMAP_LAYER_COUNT +# define DYNAMIC_KEYMAP_LAYER_COUNT 4 +# endif +# if DYNAMIC_KEYMAP_LAYER_COUNT <= 8 +# ifndef LAYER_STATE_8BIT +# define LAYER_STATE_8BIT +# endif +# elif DYNAMIC_KEYMAP_LAYER_COUNT <= 16 +# ifndef LAYER_STATE_16BIT +# define LAYER_STATE_16BIT +# endif +# else +# ifndef LAYER_STATE_32BIT +# define LAYER_STATE_32BIT +# endif +# endif +#endif + +#if !defined(LAYER_STATE_8BIT) && !defined(LAYER_STATE_16BIT) && !defined(LAYER_STATE_32BIT) +# define LAYER_STATE_32BIT +#endif + +#if defined(LAYER_STATE_8BIT) +typedef uint8_t layer_state_t; +# define MAX_LAYER_BITS 3 +# ifndef MAX_LAYER +# define MAX_LAYER 8 +# endif +# define get_highest_layer(state) biton(state) +#elif defined(LAYER_STATE_16BIT) +typedef uint16_t layer_state_t; +# define MAX_LAYER_BITS 4 +# ifndef MAX_LAYER +# define MAX_LAYER 16 +# endif +# define get_highest_layer(state) biton16(state) +#elif defined(LAYER_STATE_32BIT) +typedef uint32_t layer_state_t; +# define MAX_LAYER_BITS 5 +# ifndef MAX_LAYER +# define MAX_LAYER 32 +# endif +# define get_highest_layer(state) biton32(state) +#else +# error Layer Mask size not specified. HOW?! +#endif + +/* + * Default Layer + */ +extern layer_state_t default_layer_state; +void default_layer_debug(void); +void default_layer_set(layer_state_t state); + +__attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state); +__attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state); + +#ifndef NO_ACTION_LAYER +/* bitwise operation */ +void default_layer_or(layer_state_t state); +void default_layer_and(layer_state_t state); +void default_layer_xor(layer_state_t state); +#else +# define default_layer_or(state) +# define default_layer_and(state) +# define default_layer_xor(state) +#endif + +/* + * Keymap Layer + */ +#ifndef NO_ACTION_LAYER +extern layer_state_t layer_state; + +void layer_state_set(layer_state_t state); +bool layer_state_is(uint8_t layer); +bool layer_state_cmp(layer_state_t layer1, uint8_t layer2); + +void layer_debug(void); +void layer_clear(void); +void layer_move(uint8_t layer); +void layer_on(uint8_t layer); +void layer_off(uint8_t layer); +void layer_invert(uint8_t layer); +/* bitwise operation */ +void layer_or(layer_state_t state); +void layer_and(layer_state_t state); +void layer_xor(layer_state_t state); +layer_state_t layer_state_set_user(layer_state_t state); +layer_state_t layer_state_set_kb(layer_state_t state); +#else +# define layer_state 0 + +# define layer_state_set(layer) +# define layer_state_is(layer) (layer == 0) +# define layer_state_cmp(state, layer) (state == 0 ? layer == 0 : (state & (layer_state_t)1 << layer) != 0) + +# define layer_debug() +# define layer_clear() +# define layer_move(layer) (void)layer +# define layer_on(layer) (void)layer +# define layer_off(layer) (void)layer +# define layer_invert(layer) (void)layer +# define layer_or(state) (void)state +# define layer_and(state) (void)state +# define layer_xor(state) (void)state +# define layer_state_set_kb(state) (void)state +# define layer_state_set_user(state) (void)state +#endif + +/* pressed actions cache */ +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) + +void update_source_layers_cache(keypos_t key, uint8_t layer); +uint8_t read_source_layers_cache(keypos_t key); +#endif +action_t store_or_get_action(bool pressed, keypos_t key); + +/* return the topmost non-transparent layer currently associated with key */ +uint8_t layer_switch_get_layer(keypos_t key); + +/* return action depending on current layer status */ +action_t layer_switch_get_action(keypos_t key); diff --git a/quantum/action_macro.c b/quantum/action_macro.c new file mode 100644 index 0000000000..92228c0ba8 --- /dev/null +++ b/quantum/action_macro.c @@ -0,0 +1,93 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 "action.h" +#include "action_util.h" +#include "action_macro.h" +#include "wait.h" + +#ifdef DEBUG_ACTION +# include "debug.h" +#else +# include "nodebug.h" +#endif + +#ifndef NO_ACTION_MACRO + +# define MACRO_READ() (macro = MACRO_GET(macro_p++)) +/** \brief Action Macro Play + * + * FIXME: Needs doc + */ +void action_macro_play(const macro_t *macro_p) { + macro_t macro = END; + uint8_t interval = 0; + + if (!macro_p) return; + while (true) { + switch (MACRO_READ()) { + case KEY_DOWN: + MACRO_READ(); + dprintf("KEY_DOWN(%02X)\n", macro); + if (IS_MOD(macro)) { + add_macro_mods(MOD_BIT(macro)); + send_keyboard_report(); + } else { + register_code(macro); + } + break; + case KEY_UP: + MACRO_READ(); + dprintf("KEY_UP(%02X)\n", macro); + if (IS_MOD(macro)) { + del_macro_mods(MOD_BIT(macro)); + send_keyboard_report(); + } else { + unregister_code(macro); + } + break; + case WAIT: + MACRO_READ(); + dprintf("WAIT(%u)\n", macro); + { + uint8_t ms = macro; + while (ms--) wait_ms(1); + } + break; + case INTERVAL: + interval = MACRO_READ(); + dprintf("INTERVAL(%u)\n", interval); + break; + case 0x04 ... 0x73: + dprintf("DOWN(%02X)\n", macro); + register_code(macro); + break; + case 0x84 ... 0xF3: + dprintf("UP(%02X)\n", macro); + unregister_code(macro & 0x7F); + break; + case END: + default: + return; + } + // interval + { + uint8_t ms = interval; + while (ms--) wait_ms(1); + } + } +} +#endif diff --git a/quantum/action_macro.h b/quantum/action_macro.h new file mode 100644 index 0000000000..685e2c6ffc --- /dev/null +++ b/quantum/action_macro.h @@ -0,0 +1,123 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include "progmem.h" + +typedef uint8_t macro_t; + +#define MACRO_NONE (macro_t *)0 +#define MACRO(...) \ + ({ \ + static const macro_t __m[] PROGMEM = {__VA_ARGS__}; \ + &__m[0]; \ + }) +#define MACRO_GET(p) pgm_read_byte(p) + +// Sends press when the macro key is pressed, release when release, or tap_macro when the key has been tapped +#define MACRO_TAP_HOLD(record, press, release, tap_macro) (((record)->event.pressed) ? (((record)->tap.count <= 0 || (record)->tap.interrupted) ? (press) : MACRO_NONE) : (((record)->tap.count > 0 && !((record)->tap.interrupted)) ? (tap_macro) : (release))) + +// Holds down the modifier mod when the macro key is held, or sends macro instead when tapped +#define MACRO_TAP_HOLD_MOD(record, macro, mod) MACRO_TAP_HOLD(record, (MACRO(D(mod), END)), MACRO(U(mod), END), macro) + +// Holds down the modifier mod when the macro key is held, or pressed a shifted key when tapped (eg: shift+3 for #) +#define MACRO_TAP_SHFT_KEY_HOLD_MOD(record, key, mod) MACRO_TAP_HOLD_MOD(record, (MACRO(I(10), D(LSFT), T(key), U(LSFT), END)), mod) + +// Momentary switch layer when held, sends macro if tapped +#define MACRO_TAP_HOLD_LAYER(record, macro, layer) \ + (((record)->event.pressed) ? (((record)->tap.count <= 0 || (record)->tap.interrupted) ? ({ \ + layer_on((layer)); \ + MACRO_NONE; \ + }) \ + : MACRO_NONE) \ + : (((record)->tap.count > 0 && !((record)->tap.interrupted)) ? (macro) : ({ \ + layer_off((layer)); \ + MACRO_NONE; \ + }))) + +// Momentary switch layer when held, presses a shifted key when tapped (eg: shift+3 for #) +#define MACRO_TAP_SHFT_KEY_HOLD_LAYER(record, key, layer) MACRO_TAP_HOLD_LAYER(record, MACRO(I(10), D(LSFT), T(key), U(LSFT), END), layer) + +#ifndef NO_ACTION_MACRO +void action_macro_play(const macro_t *macro_p); +#else +# define action_macro_play(macro) +#endif + +/* Macro commands + * code(0x04-73) // key down(1byte) + * code(0x04-73) | 0x80 // key up(1byte) + * { KEY_DOWN, code(0x04-0xff) } // key down(2bytes) + * { KEY_UP, code(0x04-0xff) } // key up(2bytes) + * WAIT // wait milli-seconds + * INTERVAL // set interval between macro commands + * END // stop macro execution + * + * Ideas(Not implemented): + * modifiers + * system usage + * consumer usage + * unicode usage + * function call + * conditionals + * loop + */ +enum macro_command_id { + /* 0x00 - 0x03 */ + END = 0x00, + KEY_DOWN, + KEY_UP, + + /* 0x04 - 0x73 (reserved for keycode down) */ + + /* 0x74 - 0x83 */ + WAIT = 0x74, + INTERVAL, + + /* 0x84 - 0xf3 (reserved for keycode up) */ + + /* 0xf4 - 0xff */ +}; + +/* TODO: keycode:0x04-0x73 can be handled by 1byte command else 2bytes are needed + * if keycode between 0x04 and 0x73 + * keycode / (keycode|0x80) + * else + * {KEY_DOWN, keycode} / {KEY_UP, keycode} + */ +#define DOWN(key) KEY_DOWN, (key) +#define UP(key) KEY_UP, (key) +#define TYPE(key) DOWN(key), UP(key) +#define WAIT(ms) WAIT, (ms) +#define INTERVAL(ms) INTERVAL, (ms) + +/* key down */ +#define D(key) DOWN(KC_##key) +/* key up */ +#define U(key) UP(KC_##key) +/* key type */ +#define T(key) TYPE(KC_##key) +/* wait */ +#define W(ms) WAIT(ms) +/* interval */ +#define I(ms) INTERVAL(ms) + +/* for backward comaptibility */ +#define MD(key) DOWN(KC_##key) +#define MU(key) UP(KC_##key) diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c new file mode 100644 index 0000000000..36839f9faf --- /dev/null +++ b/quantum/action_tapping.c @@ -0,0 +1,456 @@ +#include +#include +#include "action.h" +#include "action_layer.h" +#include "action_tapping.h" +#include "keycode.h" +#include "timer.h" + +#ifdef DEBUG_ACTION +# include "debug.h" +#else +# include "nodebug.h" +#endif + +#ifndef NO_ACTION_TAPPING + +# define IS_TAPPING() !IS_NOEVENT(tapping_key.event) +# define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed) +# define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed) +# define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k))) +#ifndef COMBO_ENABLE +# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key))) +#else +# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode) +#endif + +__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; } + +# ifdef TAPPING_TERM_PER_KEY +# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_record_keycode(&tapping_key, false), &tapping_key)) +# else +# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM) +# endif + +# ifdef TAPPING_FORCE_HOLD_PER_KEY +__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) { return false; } +# endif + +# ifdef PERMISSIVE_HOLD_PER_KEY +__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { return false; } +# endif + +# ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY +__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { return false; } +# endif + +static keyrecord_t tapping_key = {}; +static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {}; +static uint8_t waiting_buffer_head = 0; +static uint8_t waiting_buffer_tail = 0; + +static bool process_tapping(keyrecord_t *record); +static bool waiting_buffer_enq(keyrecord_t record); +static void waiting_buffer_clear(void); +static bool waiting_buffer_typed(keyevent_t event); +static bool waiting_buffer_has_anykey_pressed(void); +static void waiting_buffer_scan_tap(void); +static void debug_tapping_key(void); +static void debug_waiting_buffer(void); + +/** \brief Action Tapping Process + * + * FIXME: Needs doc + */ +void action_tapping_process(keyrecord_t record) { + if (process_tapping(&record)) { + if (!IS_NOEVENT(record.event)) { + debug("processed: "); + debug_record(record); + debug("\n"); + } + } else { + if (!waiting_buffer_enq(record)) { + // clear all in case of overflow. + debug("OVERFLOW: CLEAR ALL STATES\n"); + clear_keyboard(); + waiting_buffer_clear(); + tapping_key = (keyrecord_t){}; + } + } + + // process waiting_buffer + if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) { + debug("---- action_exec: process waiting_buffer -----\n"); + } + for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) { + if (process_tapping(&waiting_buffer[waiting_buffer_tail])) { + debug("processed: waiting_buffer["); + debug_dec(waiting_buffer_tail); + debug("] = "); + debug_record(waiting_buffer[waiting_buffer_tail]); + debug("\n\n"); + } else { + break; + } + } + if (!IS_NOEVENT(record.event)) { + debug("\n"); + } +} + +/** \brief Tapping + * + * Rule: Tap key is typed(pressed and released) within TAPPING_TERM. + * (without interfering by typing other key) + */ +/* return true when key event is processed or consumed. */ +bool process_tapping(keyrecord_t *keyp) { + keyevent_t event = keyp->event; + + // if tapping + if (IS_TAPPING_PRESSED()) { + if (WITHIN_TAPPING_TERM(event)) { + if (tapping_key.tap.count == 0) { + if (IS_TAPPING_RECORD(keyp) && !event.pressed) { + // first tap! + debug("Tapping: First tap(0->1).\n"); + tapping_key.tap.count = 1; + debug_tapping_key(); + process_record(&tapping_key); + + // copy tapping state + keyp->tap = tapping_key.tap; + // enqueue + return false; + } + /* Process a key typed within TAPPING_TERM + * This can register the key before settlement of tapping, + * useful for long TAPPING_TERM but may prevent fast typing. + */ +# if defined(TAPPING_TERM_PER_KEY) || (TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD) || defined(PERMISSIVE_HOLD_PER_KEY) + else if ((( +# ifdef TAPPING_TERM_PER_KEY + get_tapping_term(get_record_keycode(&tapping_key, false), keyp) +# else + TAPPING_TERM +# endif + >= 500) + +# ifdef PERMISSIVE_HOLD_PER_KEY + || get_permissive_hold(get_record_keycode(&tapping_key, false), keyp) +# elif defined(PERMISSIVE_HOLD) + || true +# endif + ) && + IS_RELEASED(event) && waiting_buffer_typed(event)) { + debug("Tapping: End. No tap. Interfered by typing key\n"); + process_record(&tapping_key); + tapping_key = (keyrecord_t){}; + debug_tapping_key(); + // enqueue + return false; + } +# endif + /* Process release event of a key pressed before tapping starts + * Without this unexpected repeating will occur with having fast repeating setting + * https://github.com/tmk/tmk_keyboard/issues/60 + */ + else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) { + // Modifier should be retained till end of this tapping. + action_t action = layer_switch_get_action(event.key); + switch (action.kind.id) { + case ACT_LMODS: + case ACT_RMODS: + if (action.key.mods && !action.key.code) return false; + if (IS_MOD(action.key.code)) return false; + break; + case ACT_LMODS_TAP: + case ACT_RMODS_TAP: + if (action.key.mods && keyp->tap.count == 0) return false; + if (IS_MOD(action.key.code)) return false; + break; + } + // Release of key should be process immediately. + debug("Tapping: release event of a key pressed before tapping\n"); + process_record(keyp); + return true; + } else { + // set interrupted flag when other key preesed during tapping + if (event.pressed) { + tapping_key.tap.interrupted = true; +# if defined(HOLD_ON_OTHER_KEY_PRESS) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) +# if defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) + if (get_hold_on_other_key_press(get_record_keycode(&tapping_key, false), keyp)) +# endif + { + debug("Tapping: End. No tap. Interfered by pressed key\n"); + process_record(&tapping_key); + tapping_key = (keyrecord_t){}; + debug_tapping_key(); + // enqueue + return false; + } +# endif + } + // enqueue + return false; + } + } + // tap_count > 0 + else { + if (IS_TAPPING_RECORD(keyp) && !event.pressed) { + debug("Tapping: Tap release("); + debug_dec(tapping_key.tap.count); + debug(")\n"); + keyp->tap = tapping_key.tap; + process_record(keyp); + tapping_key = *keyp; + debug_tapping_key(); + return true; + } else if (is_tap_record(keyp) && event.pressed) { + if (tapping_key.tap.count > 1) { + debug("Tapping: Start new tap with releasing last tap(>1).\n"); + // unregister key + process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false, +#ifdef COMBO_ENABLE + .keycode = tapping_key.keycode, +#endif + }); + } else { + debug("Tapping: Start while last tap(1).\n"); + } + tapping_key = *keyp; + waiting_buffer_scan_tap(); + debug_tapping_key(); + return true; + } else { + if (!IS_NOEVENT(event)) { + debug("Tapping: key event while last tap(>0).\n"); + } + process_record(keyp); + return true; + } + } + } + // after TAPPING_TERM + else { + if (tapping_key.tap.count == 0) { + debug("Tapping: End. Timeout. Not tap(0): "); + debug_event(event); + debug("\n"); + process_record(&tapping_key); + tapping_key = (keyrecord_t){}; + debug_tapping_key(); + return false; + } else { + if (IS_TAPPING_RECORD(keyp) && !event.pressed) { + debug("Tapping: End. last timeout tap release(>0)."); + keyp->tap = tapping_key.tap; + process_record(keyp); + tapping_key = (keyrecord_t){}; + return true; + } else if (is_tap_record(keyp) && event.pressed) { + if (tapping_key.tap.count > 1) { + debug("Tapping: Start new tap with releasing last timeout tap(>1).\n"); + // unregister key + process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false, +#ifdef COMBO_ENABLE + .keycode = tapping_key.keycode, +#endif + }); + } else { + debug("Tapping: Start while last timeout tap(1).\n"); + } + tapping_key = *keyp; + waiting_buffer_scan_tap(); + debug_tapping_key(); + return true; + } else { + if (!IS_NOEVENT(event)) { + debug("Tapping: key event while last timeout tap(>0).\n"); + } + process_record(keyp); + return true; + } + } + } + } else if (IS_TAPPING_RELEASED()) { + if (WITHIN_TAPPING_TERM(event)) { + if (event.pressed) { + if (IS_TAPPING_RECORD(keyp)) { +//# ifndef TAPPING_FORCE_HOLD +# if !defined(TAPPING_FORCE_HOLD) || defined(TAPPING_FORCE_HOLD_PER_KEY) + if ( +# ifdef TAPPING_FORCE_HOLD_PER_KEY + !get_tapping_force_hold(get_record_keycode(&tapping_key, false), keyp) && +# endif + !tapping_key.tap.interrupted && tapping_key.tap.count > 0) { + // sequential tap. + keyp->tap = tapping_key.tap; + if (keyp->tap.count < 15) keyp->tap.count += 1; + debug("Tapping: Tap press("); + debug_dec(keyp->tap.count); + debug(")\n"); + process_record(keyp); + tapping_key = *keyp; + debug_tapping_key(); + return true; + } +# endif + // FIX: start new tap again + tapping_key = *keyp; + return true; + } else if (is_tap_record(keyp)) { + // Sequential tap can be interfered with other tap key. + debug("Tapping: Start with interfering other tap.\n"); + tapping_key = *keyp; + waiting_buffer_scan_tap(); + debug_tapping_key(); + return true; + } else { + // should none in buffer + // FIX: interrupted when other key is pressed + tapping_key.tap.interrupted = true; + process_record(keyp); + return true; + } + } else { + if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n"); + process_record(keyp); + return true; + } + } else { + // FIX: process_action here? + // timeout. no sequential tap. + debug("Tapping: End(Timeout after releasing last tap): "); + debug_event(event); + debug("\n"); + tapping_key = (keyrecord_t){}; + debug_tapping_key(); + return false; + } + } + // not tapping state + else { + if (event.pressed && is_tap_record(keyp)) { + debug("Tapping: Start(Press tap key).\n"); + tapping_key = *keyp; + process_record_tap_hint(&tapping_key); + waiting_buffer_scan_tap(); + debug_tapping_key(); + return true; + } else { + process_record(keyp); + return true; + } + } +} + +/** \brief Waiting buffer enq + * + * FIXME: Needs docs + */ +bool waiting_buffer_enq(keyrecord_t record) { + if (IS_NOEVENT(record.event)) { + return true; + } + + if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) { + debug("waiting_buffer_enq: Over flow.\n"); + return false; + } + + waiting_buffer[waiting_buffer_head] = record; + waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE; + + debug("waiting_buffer_enq: "); + debug_waiting_buffer(); + return true; +} + +/** \brief Waiting buffer clear + * + * FIXME: Needs docs + */ +void waiting_buffer_clear(void) { + waiting_buffer_head = 0; + waiting_buffer_tail = 0; +} + +/** \brief Waiting buffer typed + * + * FIXME: Needs docs + */ +bool waiting_buffer_typed(keyevent_t event) { + for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { + if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) { + return true; + } + } + return false; +} + +/** \brief Waiting buffer has anykey pressed + * + * FIXME: Needs docs + */ +__attribute__((unused)) bool waiting_buffer_has_anykey_pressed(void) { + for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { + if (waiting_buffer[i].event.pressed) return true; + } + return false; +} + +/** \brief Scan buffer for tapping + * + * FIXME: Needs docs + */ +void waiting_buffer_scan_tap(void) { + // tapping already is settled + if (tapping_key.tap.count > 0) return; + // invalid state: tapping_key released && tap.count == 0 + if (!tapping_key.event.pressed) return; + + for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { + if (IS_TAPPING_KEY(waiting_buffer[i].event.key) && !waiting_buffer[i].event.pressed && WITHIN_TAPPING_TERM(waiting_buffer[i].event)) { + tapping_key.tap.count = 1; + waiting_buffer[i].tap.count = 1; + process_record(&tapping_key); + + debug("waiting_buffer_scan_tap: found at ["); + debug_dec(i); + debug("]\n"); + debug_waiting_buffer(); + return; + } + } +} + +/** \brief Tapping key debug print + * + * FIXME: Needs docs + */ +static void debug_tapping_key(void) { + debug("TAPPING_KEY="); + debug_record(tapping_key); + debug("\n"); +} + +/** \brief Waiting buffer debug print + * + * FIXME: Needs docs + */ +static void debug_waiting_buffer(void) { + debug("{ "); + for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { + debug("["); + debug_dec(i); + debug("]="); + debug_record(waiting_buffer[i]); + debug(" "); + } + debug("}\n"); +} + +#endif diff --git a/quantum/action_tapping.h b/quantum/action_tapping.h new file mode 100644 index 0000000000..7de8049c7f --- /dev/null +++ b/quantum/action_tapping.h @@ -0,0 +1,42 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 + +/* period of tapping(ms) */ +#ifndef TAPPING_TERM +# define TAPPING_TERM 200 +#endif + +/* tap count needed for toggling a feature */ +#ifndef TAPPING_TOGGLE +# define TAPPING_TOGGLE 5 +#endif + +#define WAITING_BUFFER_SIZE 8 + +#ifndef NO_ACTION_TAPPING +uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache); +uint16_t get_event_keycode(keyevent_t event, bool update_layer_cache); +void action_tapping_process(keyrecord_t record); + +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record); +bool get_permissive_hold(uint16_t keycode, keyrecord_t *record); +bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record); +bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record); +bool get_retro_tapping(uint16_t keycode, keyrecord_t *record); +#endif diff --git a/quantum/action_util.c b/quantum/action_util.c new file mode 100644 index 0000000000..2b3c00cba0 --- /dev/null +++ b/quantum/action_util.c @@ -0,0 +1,455 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 "host.h" +#include "report.h" +#include "debug.h" +#include "action_util.h" +#include "action_layer.h" +#include "timer.h" +#include "keycode_config.h" + +extern keymap_config_t keymap_config; + +static uint8_t real_mods = 0; +static uint8_t weak_mods = 0; +static uint8_t macro_mods = 0; +#ifdef KEY_OVERRIDE_ENABLE +static uint8_t weak_override_mods = 0; +static uint8_t suppressed_mods = 0; +#endif + +#ifdef USB_6KRO_ENABLE +# define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS) +# define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS) +# define RO_INC(a) RO_ADD(a, 1) +# define RO_DEC(a) RO_SUB(a, 1) +static int8_t cb_head = 0; +static int8_t cb_tail = 0; +static int8_t cb_count = 0; +#endif + +// TODO: pointer variable is not needed +// report_keyboard_t keyboard_report = {}; +report_keyboard_t *keyboard_report = &(report_keyboard_t){}; + +extern inline void add_key(uint8_t key); +extern inline void del_key(uint8_t key); +extern inline void clear_keys(void); + +#ifndef NO_ACTION_ONESHOT +static uint8_t oneshot_mods = 0; +static uint8_t oneshot_locked_mods = 0; +uint8_t get_oneshot_locked_mods(void) { return oneshot_locked_mods; } +void set_oneshot_locked_mods(uint8_t mods) { + if (mods != oneshot_locked_mods) { + oneshot_locked_mods = mods; + oneshot_locked_mods_changed_kb(oneshot_locked_mods); + } +} +void clear_oneshot_locked_mods(void) { + if (oneshot_locked_mods) { + oneshot_locked_mods = 0; + oneshot_locked_mods_changed_kb(oneshot_locked_mods); + } +} +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) +static uint16_t oneshot_time = 0; +bool has_oneshot_mods_timed_out(void) { return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT; } +# else +bool has_oneshot_mods_timed_out(void) { return false; } +# endif +#endif + +/* oneshot layer */ +#ifndef NO_ACTION_ONESHOT +/** \brief oneshot_layer_data bits + * LLLL LSSS + * where: + * L => are layer bits + * S => oneshot state bits + */ +static int8_t oneshot_layer_data = 0; + +inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; } +inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; } + +# ifdef SWAP_HANDS_ENABLE +enum { + SHO_OFF, + SHO_ACTIVE, // Swap hands button was pressed, and we didn't send any swapped keys yet + SHO_PRESSED, // Swap hands button is currently pressed + SHO_USED, // Swap hands button is still pressed, and we already sent swapped keys +} swap_hands_oneshot = SHO_OFF; +# endif + +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) +static uint16_t oneshot_layer_time = 0; +inline bool has_oneshot_layer_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT && !(get_oneshot_layer_state() & ONESHOT_TOGGLED); } +# ifdef SWAP_HANDS_ENABLE +static uint16_t oneshot_swaphands_time = 0; +inline bool has_oneshot_swaphands_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_swaphands_time) >= ONESHOT_TIMEOUT && (swap_hands_oneshot == SHO_ACTIVE); } +# endif +# endif + +# ifdef SWAP_HANDS_ENABLE + +void set_oneshot_swaphands(void) { + swap_hands_oneshot = SHO_PRESSED; + swap_hands = true; +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_swaphands_time = timer_read(); + if (oneshot_layer_time != 0) { + oneshot_layer_time = oneshot_swaphands_time; + } +# endif +} + +void release_oneshot_swaphands(void) { + if (swap_hands_oneshot == SHO_PRESSED) { + swap_hands_oneshot = SHO_ACTIVE; + } + if (swap_hands_oneshot == SHO_USED) { + clear_oneshot_swaphands(); + } +} + +void use_oneshot_swaphands(void) { + if (swap_hands_oneshot == SHO_PRESSED) { + swap_hands_oneshot = SHO_USED; + } + if (swap_hands_oneshot == SHO_ACTIVE) { + clear_oneshot_swaphands(); + } +} + +void clear_oneshot_swaphands(void) { + swap_hands_oneshot = SHO_OFF; + swap_hands = false; +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_swaphands_time = 0; +# endif +} + +# endif + +/** \brief Set oneshot layer + * + * FIXME: needs doc + */ +void set_oneshot_layer(uint8_t layer, uint8_t state) { + if (!keymap_config.oneshot_disable) { + oneshot_layer_data = layer << 3 | state; + layer_on(layer); +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_layer_time = timer_read(); +# endif + oneshot_layer_changed_kb(get_oneshot_layer()); + } else { + layer_on(layer); + } +} +/** \brief Reset oneshot layer + * + * FIXME: needs doc + */ +void reset_oneshot_layer(void) { + oneshot_layer_data = 0; +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_layer_time = 0; +# endif + oneshot_layer_changed_kb(get_oneshot_layer()); +} +/** \brief Clear oneshot layer + * + * FIXME: needs doc + */ +void clear_oneshot_layer_state(oneshot_fullfillment_t state) { + uint8_t start_state = oneshot_layer_data; + oneshot_layer_data &= ~state; + if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) || keymap_config.oneshot_disable) { + layer_off(get_oneshot_layer()); + reset_oneshot_layer(); + } +} +/** \brief Is oneshot layer active + * + * FIXME: needs doc + */ +bool is_oneshot_layer_active(void) { return get_oneshot_layer_state(); } + +/** \brief set oneshot + * + * FIXME: needs doc + */ +void oneshot_set(bool active) { + if (keymap_config.oneshot_disable != active) { + keymap_config.oneshot_disable = active; + eeconfig_update_keymap(keymap_config.raw); + dprintf("Oneshot: active: %d\n", active); + } +} + +/** \brief toggle oneshot + * + * FIXME: needs doc + */ +void oneshot_toggle(void) { oneshot_set(!keymap_config.oneshot_disable); } + +/** \brief enable oneshot + * + * FIXME: needs doc + */ +void oneshot_enable(void) { oneshot_set(true); } + +/** \brief disable oneshot + * + * FIXME: needs doc + */ +void oneshot_disable(void) { oneshot_set(false); } + +bool is_oneshot_enabled(void) { return keymap_config.oneshot_disable; } + +#endif + +/** \brief Send keyboard report + * + * FIXME: needs doc + */ +void send_keyboard_report(void) { + keyboard_report->mods = real_mods; + keyboard_report->mods |= weak_mods; + keyboard_report->mods |= macro_mods; + +#ifndef NO_ACTION_ONESHOT + if (oneshot_mods) { +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + if (has_oneshot_mods_timed_out()) { + dprintf("Oneshot: timeout\n"); + clear_oneshot_mods(); + } +# endif + keyboard_report->mods |= oneshot_mods; + if (has_anykey(keyboard_report)) { + clear_oneshot_mods(); + } + } + +#endif + +#ifdef KEY_OVERRIDE_ENABLE + // These need to be last to be able to properly control key overrides + keyboard_report->mods &= ~suppressed_mods; + keyboard_report->mods |= weak_override_mods; +#endif + + host_keyboard_send(keyboard_report); +} + +/** \brief Get mods + * + * FIXME: needs doc + */ +uint8_t get_mods(void) { return real_mods; } +/** \brief add mods + * + * FIXME: needs doc + */ +void add_mods(uint8_t mods) { real_mods |= mods; } +/** \brief del mods + * + * FIXME: needs doc + */ +void del_mods(uint8_t mods) { real_mods &= ~mods; } +/** \brief set mods + * + * FIXME: needs doc + */ +void set_mods(uint8_t mods) { real_mods = mods; } +/** \brief clear mods + * + * FIXME: needs doc + */ +void clear_mods(void) { real_mods = 0; } + +/** \brief get weak mods + * + * FIXME: needs doc + */ +uint8_t get_weak_mods(void) { return weak_mods; } +/** \brief add weak mods + * + * FIXME: needs doc + */ +void add_weak_mods(uint8_t mods) { weak_mods |= mods; } +/** \brief del weak mods + * + * FIXME: needs doc + */ +void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; } +/** \brief set weak mods + * + * FIXME: needs doc + */ +void set_weak_mods(uint8_t mods) { weak_mods = mods; } +/** \brief clear weak mods + * + * FIXME: needs doc + */ +void clear_weak_mods(void) { weak_mods = 0; } + +#ifdef KEY_OVERRIDE_ENABLE +/** \brief set weak mods used by key overrides. DO not call this manually + */ +void set_weak_override_mods(uint8_t mods) { weak_override_mods = mods; } +/** \brief clear weak mods used by key overrides. DO not call this manually + */ +void clear_weak_override_mods(void) { weak_override_mods = 0; } + +/** \brief set suppressed mods used by key overrides. DO not call this manually + */ +void set_suppressed_override_mods(uint8_t mods) { suppressed_mods = mods; } +/** \brief clear suppressed mods used by key overrides. DO not call this manually + */ +void clear_suppressed_override_mods(void) { suppressed_mods = 0; } +#endif + +/* macro modifier */ +/** \brief get macro mods + * + * FIXME: needs doc + */ +uint8_t get_macro_mods(void) { return macro_mods; } +/** \brief add macro mods + * + * FIXME: needs doc + */ +void add_macro_mods(uint8_t mods) { macro_mods |= mods; } +/** \brief del macro mods + * + * FIXME: needs doc + */ +void del_macro_mods(uint8_t mods) { macro_mods &= ~mods; } +/** \brief set macro mods + * + * FIXME: needs doc + */ +void set_macro_mods(uint8_t mods) { macro_mods = mods; } +/** \brief clear macro mods + * + * FIXME: needs doc + */ +void clear_macro_mods(void) { macro_mods = 0; } + +#ifndef NO_ACTION_ONESHOT +/** \brief get oneshot mods + * + * FIXME: needs doc + */ +uint8_t get_oneshot_mods(void) { return oneshot_mods; } + +void add_oneshot_mods(uint8_t mods) { + if ((oneshot_mods & mods) != mods) { +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_time = timer_read(); +# endif + oneshot_mods |= mods; + oneshot_mods_changed_kb(mods); + } +} + +void del_oneshot_mods(uint8_t mods) { + if (oneshot_mods & mods) { + oneshot_mods &= ~mods; +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_time = oneshot_mods ? timer_read() : 0; +# endif + oneshot_mods_changed_kb(oneshot_mods); + } +} + +/** \brief set oneshot mods + * + * FIXME: needs doc + */ +void set_oneshot_mods(uint8_t mods) { + if (!keymap_config.oneshot_disable) { + if (oneshot_mods != mods) { +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_time = timer_read(); +# endif + oneshot_mods = mods; + oneshot_mods_changed_kb(mods); + } + } +} + +/** \brief clear oneshot mods + * + * FIXME: needs doc + */ +void clear_oneshot_mods(void) { + if (oneshot_mods) { + oneshot_mods = 0; +# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) + oneshot_time = 0; +# endif + oneshot_mods_changed_kb(oneshot_mods); + } +} +#endif + +/** \brief Called when the one shot modifiers have been changed. + * + * \param mods Contains the active modifiers active after the change. + */ +__attribute__((weak)) void oneshot_locked_mods_changed_user(uint8_t mods) {} + +/** \brief Called when the locked one shot modifiers have been changed. + * + * \param mods Contains the active modifiers active after the change. + */ +__attribute__((weak)) void oneshot_locked_mods_changed_kb(uint8_t mods) { oneshot_locked_mods_changed_user(mods); } + +/** \brief Called when the one shot modifiers have been changed. + * + * \param mods Contains the active modifiers active after the change. + */ +__attribute__((weak)) void oneshot_mods_changed_user(uint8_t mods) {} + +/** \brief Called when the one shot modifiers have been changed. + * + * \param mods Contains the active modifiers active after the change. + */ +__attribute__((weak)) void oneshot_mods_changed_kb(uint8_t mods) { oneshot_mods_changed_user(mods); } + +/** \brief Called when the one shot layers have been changed. + * + * \param layer Contains the layer that is toggled on, or zero when toggled off. + */ +__attribute__((weak)) void oneshot_layer_changed_user(uint8_t layer) {} + +/** \brief Called when the one shot layers have been changed. + * + * \param layer Contains the layer that is toggled on, or zero when toggled off. + */ +__attribute__((weak)) void oneshot_layer_changed_kb(uint8_t layer) { oneshot_layer_changed_user(layer); } + +/** \brief inspect keyboard state + * + * FIXME: needs doc + */ +uint8_t has_anymod(void) { return bitpop(real_mods); } diff --git a/quantum/action_util.h b/quantum/action_util.h new file mode 100644 index 0000000000..f2b3897ae5 --- /dev/null +++ b/quantum/action_util.h @@ -0,0 +1,105 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include "report.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern report_keyboard_t *keyboard_report; + +void send_keyboard_report(void); + +/* key */ +inline void add_key(uint8_t key) { add_key_to_report(keyboard_report, key); } + +inline void del_key(uint8_t key) { del_key_from_report(keyboard_report, key); } + +inline void clear_keys(void) { clear_keys_from_report(keyboard_report); } + +/* modifier */ +uint8_t get_mods(void); +void add_mods(uint8_t mods); +void del_mods(uint8_t mods); +void set_mods(uint8_t mods); +void clear_mods(void); + +/* weak modifier */ +uint8_t get_weak_mods(void); +void add_weak_mods(uint8_t mods); +void del_weak_mods(uint8_t mods); +void set_weak_mods(uint8_t mods); +void clear_weak_mods(void); + +/* macro modifier */ +uint8_t get_macro_mods(void); +void add_macro_mods(uint8_t mods); +void del_macro_mods(uint8_t mods); +void set_macro_mods(uint8_t mods); +void clear_macro_mods(void); + +/* oneshot modifier */ +uint8_t get_oneshot_mods(void); +void add_oneshot_mods(uint8_t mods); +void del_oneshot_mods(uint8_t mods); +void set_oneshot_mods(uint8_t mods); +void clear_oneshot_mods(void); +bool has_oneshot_mods_timed_out(void); + +uint8_t get_oneshot_locked_mods(void); +void set_oneshot_locked_mods(uint8_t mods); +void clear_oneshot_locked_mods(void); + +typedef enum { ONESHOT_PRESSED = 0b01, ONESHOT_OTHER_KEY_PRESSED = 0b10, ONESHOT_START = 0b11, ONESHOT_TOGGLED = 0b100 } oneshot_fullfillment_t; +void set_oneshot_layer(uint8_t layer, uint8_t state); +uint8_t get_oneshot_layer(void); +void clear_oneshot_layer_state(oneshot_fullfillment_t state); +void reset_oneshot_layer(void); +bool is_oneshot_layer_active(void); +uint8_t get_oneshot_layer_state(void); +bool has_oneshot_layer_timed_out(void); +bool has_oneshot_swaphands_timed_out(void); + +void oneshot_locked_mods_changed_user(uint8_t mods); +void oneshot_locked_mods_changed_kb(uint8_t mods); +void oneshot_mods_changed_user(uint8_t mods); +void oneshot_mods_changed_kb(uint8_t mods); +void oneshot_layer_changed_user(uint8_t layer); +void oneshot_layer_changed_kb(uint8_t layer); + +void oneshot_toggle(void); +void oneshot_enable(void); +void oneshot_disable(void); +bool is_oneshot_enabled(void); + +/* inspect */ +uint8_t has_anymod(void); + +#ifdef SWAP_HANDS_ENABLE +void set_oneshot_swaphands(void); +void release_oneshot_swaphands(void); +void use_oneshot_swaphands(void); +void clear_oneshot_swaphands(void); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/quantum/eeconfig.c b/quantum/eeconfig.c new file mode 100644 index 0000000000..ffa56ab56d --- /dev/null +++ b/quantum/eeconfig.c @@ -0,0 +1,211 @@ +#include +#include +#include "eeprom.h" +#include "eeconfig.h" +#include "action_layer.h" + +#ifdef STM32_EEPROM_ENABLE +# include +# include "eeprom_stm32.h" +#endif + +#if defined(EEPROM_DRIVER) +# include "eeprom_driver.h" +#endif + +#if defined(HAPTIC_ENABLE) +# include "haptic.h" +#endif + +/** \brief eeconfig enable + * + * FIXME: needs doc + */ +__attribute__((weak)) void eeconfig_init_user(void) { + // Reset user EEPROM value to blank, rather than to a set value + eeconfig_update_user(0); +} + +__attribute__((weak)) void eeconfig_init_kb(void) { + // Reset Keyboard EEPROM value to blank, rather than to a set value + eeconfig_update_kb(0); + + eeconfig_init_user(); +} + +/* + * FIXME: needs doc + */ +void eeconfig_init_quantum(void) { +#ifdef STM32_EEPROM_ENABLE + EEPROM_Erase(); +#endif +#if defined(EEPROM_DRIVER) + eeprom_driver_erase(); +#endif + eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); + eeprom_update_byte(EECONFIG_DEBUG, 0); + eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0); + default_layer_state = 0; + eeprom_update_byte(EECONFIG_KEYMAP_LOWER_BYTE, 0); + eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, 0); + eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0); + eeprom_update_byte(EECONFIG_BACKLIGHT, 0); + eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default + eeprom_update_dword(EECONFIG_RGBLIGHT, 0); + eeprom_update_byte(EECONFIG_STENOMODE, 0); + eeprom_update_dword(EECONFIG_HAPTIC, 0); + eeprom_update_byte(EECONFIG_VELOCIKEY, 0); + eeprom_update_dword(EECONFIG_RGB_MATRIX, 0); + eeprom_update_word(EECONFIG_RGB_MATRIX_EXTENDED, 0); + + // TODO: Remove once ARM has a way to configure EECONFIG_HANDEDNESS + // within the emulated eeprom via dfu-util or another tool +#if defined INIT_EE_HANDS_LEFT +# pragma message "Faking EE_HANDS for left hand" + eeprom_update_byte(EECONFIG_HANDEDNESS, 1); +#elif defined INIT_EE_HANDS_RIGHT +# pragma message "Faking EE_HANDS for right hand" + eeprom_update_byte(EECONFIG_HANDEDNESS, 0); +#endif + +#if defined(HAPTIC_ENABLE) + haptic_reset(); +#else + // this is used in case haptic is disabled, but we still want sane defaults + // in the haptic configuration eeprom. All zero will trigger a haptic_reset + // when a haptic-enabled firmware is loaded onto the keyboard. + eeprom_update_dword(EECONFIG_HAPTIC, 0); +#endif + + eeconfig_init_kb(); +} + +/** \brief eeconfig initialization + * + * FIXME: needs doc + */ +void eeconfig_init(void) { eeconfig_init_quantum(); } + +/** \brief eeconfig enable + * + * FIXME: needs doc + */ +void eeconfig_enable(void) { eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); } + +/** \brief eeconfig disable + * + * FIXME: needs doc + */ +void eeconfig_disable(void) { +#ifdef STM32_EEPROM_ENABLE + EEPROM_Erase(); +#endif +#if defined(EEPROM_DRIVER) + eeprom_driver_erase(); +#endif + eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER_OFF); +} + +/** \brief eeconfig is enabled + * + * FIXME: needs doc + */ +bool eeconfig_is_enabled(void) { return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER); } + +/** \brief eeconfig is disabled + * + * FIXME: needs doc + */ +bool eeconfig_is_disabled(void) { return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER_OFF); } + +/** \brief eeconfig read debug + * + * FIXME: needs doc + */ +uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); } +/** \brief eeconfig update debug + * + * FIXME: needs doc + */ +void eeconfig_update_debug(uint8_t val) { eeprom_update_byte(EECONFIG_DEBUG, val); } + +/** \brief eeconfig read default layer + * + * FIXME: needs doc + */ +uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); } +/** \brief eeconfig update default layer + * + * FIXME: needs doc + */ +void eeconfig_update_default_layer(uint8_t val) { eeprom_update_byte(EECONFIG_DEFAULT_LAYER, val); } + +/** \brief eeconfig read keymap + * + * FIXME: needs doc + */ +uint16_t eeconfig_read_keymap(void) { return (eeprom_read_byte(EECONFIG_KEYMAP_LOWER_BYTE) | (eeprom_read_byte(EECONFIG_KEYMAP_UPPER_BYTE) << 8)); } +/** \brief eeconfig update keymap + * + * FIXME: needs doc + */ +void eeconfig_update_keymap(uint16_t val) { + eeprom_update_byte(EECONFIG_KEYMAP_LOWER_BYTE, val & 0xFF); + eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, (val >> 8) & 0xFF); +} + +/** \brief eeconfig read audio + * + * FIXME: needs doc + */ +uint8_t eeconfig_read_audio(void) { return eeprom_read_byte(EECONFIG_AUDIO); } +/** \brief eeconfig update audio + * + * FIXME: needs doc + */ +void eeconfig_update_audio(uint8_t val) { eeprom_update_byte(EECONFIG_AUDIO, val); } + +/** \brief eeconfig read kb + * + * FIXME: needs doc + */ +uint32_t eeconfig_read_kb(void) { return eeprom_read_dword(EECONFIG_KEYBOARD); } +/** \brief eeconfig update kb + * + * FIXME: needs doc + */ +void eeconfig_update_kb(uint32_t val) { eeprom_update_dword(EECONFIG_KEYBOARD, val); } + +/** \brief eeconfig read user + * + * FIXME: needs doc + */ +uint32_t eeconfig_read_user(void) { return eeprom_read_dword(EECONFIG_USER); } +/** \brief eeconfig update user + * + * FIXME: needs doc + */ +void eeconfig_update_user(uint32_t val) { eeprom_update_dword(EECONFIG_USER, val); } + +/** \brief eeconfig read haptic + * + * FIXME: needs doc + */ +uint32_t eeconfig_read_haptic(void) { return eeprom_read_dword(EECONFIG_HAPTIC); } +/** \brief eeconfig update haptic + * + * FIXME: needs doc + */ +void eeconfig_update_haptic(uint32_t val) { eeprom_update_dword(EECONFIG_HAPTIC, val); } + +/** \brief eeconfig read split handedness + * + * FIXME: needs doc + */ +bool eeconfig_read_handedness(void) { return !!eeprom_read_byte(EECONFIG_HANDEDNESS); } +/** \brief eeconfig update split handedness + * + * FIXME: needs doc + */ +void eeconfig_update_handedness(bool val) { eeprom_update_byte(EECONFIG_HANDEDNESS, !!val); } diff --git a/quantum/eeconfig.h b/quantum/eeconfig.h new file mode 100644 index 0000000000..a88071729d --- /dev/null +++ b/quantum/eeconfig.h @@ -0,0 +1,113 @@ +/* +Copyright 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include + +#ifndef EECONFIG_MAGIC_NUMBER +# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEEA // When changing, decrement this value to avoid future re-init issues +#endif +#define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF + +/* EEPROM parameter address */ +#define EECONFIG_MAGIC (uint16_t *)0 +#define EECONFIG_DEBUG (uint8_t *)2 +#define EECONFIG_DEFAULT_LAYER (uint8_t *)3 +#define EECONFIG_KEYMAP (uint8_t *)4 +#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5 +#define EECONFIG_BACKLIGHT (uint8_t *)6 +#define EECONFIG_AUDIO (uint8_t *)7 +#define EECONFIG_RGBLIGHT (uint32_t *)8 +#define EECONFIG_UNICODEMODE (uint8_t *)12 +#define EECONFIG_STENOMODE (uint8_t *)13 +// EEHANDS for two handed boards +#define EECONFIG_HANDEDNESS (uint8_t *)14 +#define EECONFIG_KEYBOARD (uint32_t *)15 +#define EECONFIG_USER (uint32_t *)19 +#define EECONFIG_VELOCIKEY (uint8_t *)23 + +#define EECONFIG_HAPTIC (uint32_t *)24 + +// Mutually exclusive +#define EECONFIG_LED_MATRIX (uint32_t *)28 +#define EECONFIG_RGB_MATRIX (uint32_t *)28 +// Speed & Flags +#define EECONFIG_LED_MATRIX_EXTENDED (uint16_t *)32 +#define EECONFIG_RGB_MATRIX_EXTENDED (uint16_t *)32 + +// TODO: Combine these into a single word and single block of EEPROM +#define EECONFIG_KEYMAP_UPPER_BYTE (uint8_t *)34 +// Size of EEPROM being used, other code can refer to this for available EEPROM +#define EECONFIG_SIZE 35 +/* debug bit */ +#define EECONFIG_DEBUG_ENABLE (1 << 0) +#define EECONFIG_DEBUG_MATRIX (1 << 1) +#define EECONFIG_DEBUG_KEYBOARD (1 << 2) +#define EECONFIG_DEBUG_MOUSE (1 << 3) + +/* keyconf bit */ +#define EECONFIG_KEYMAP_SWAP_CONTROL_CAPSLOCK (1 << 0) +#define EECONFIG_KEYMAP_CAPSLOCK_TO_CONTROL (1 << 1) +#define EECONFIG_KEYMAP_SWAP_LALT_LGUI (1 << 2) +#define EECONFIG_KEYMAP_SWAP_RALT_RGUI (1 << 3) +#define EECONFIG_KEYMAP_NO_GUI (1 << 4) +#define EECONFIG_KEYMAP_SWAP_GRAVE_ESC (1 << 5) +#define EECONFIG_KEYMAP_SWAP_BACKSLASH_BACKSPACE (1 << 6) +#define EECONFIG_KEYMAP_NKRO (1 << 7) + +#define EECONFIG_KEYMAP_LOWER_BYTE EECONFIG_KEYMAP + +bool eeconfig_is_enabled(void); +bool eeconfig_is_disabled(void); + +void eeconfig_init(void); +void eeconfig_init_quantum(void); +void eeconfig_init_kb(void); +void eeconfig_init_user(void); + +void eeconfig_enable(void); + +void eeconfig_disable(void); + +uint8_t eeconfig_read_debug(void); +void eeconfig_update_debug(uint8_t val); + +uint8_t eeconfig_read_default_layer(void); +void eeconfig_update_default_layer(uint8_t val); + +uint16_t eeconfig_read_keymap(void); +void eeconfig_update_keymap(uint16_t val); + +#ifdef AUDIO_ENABLE +uint8_t eeconfig_read_audio(void); +void eeconfig_update_audio(uint8_t val); +#endif + +uint32_t eeconfig_read_kb(void); +void eeconfig_update_kb(uint32_t val); +uint32_t eeconfig_read_user(void); +void eeconfig_update_user(uint32_t val); + +#ifdef HAPTIC_ENABLE +uint32_t eeconfig_read_haptic(void); +void eeconfig_update_haptic(uint32_t val); +#endif + +bool eeconfig_read_handedness(void); +void eeconfig_update_handedness(bool val); diff --git a/quantum/keyboard.c b/quantum/keyboard.c new file mode 100644 index 0000000000..0eb41e7d30 --- /dev/null +++ b/quantum/keyboard.c @@ -0,0 +1,569 @@ +/* +Copyright 2011, 2012, 2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include "keyboard.h" +#include "matrix.h" +#include "keymap.h" +#include "host.h" +#include "led.h" +#include "keycode.h" +#include "timer.h" +#include "sync_timer.h" +#include "print.h" +#include "debug.h" +#include "command.h" +#include "util.h" +#include "sendchar.h" +#include "eeconfig.h" +#include "action_layer.h" +#ifdef BACKLIGHT_ENABLE +# include "backlight.h" +#endif +#ifdef MOUSEKEY_ENABLE +# include "mousekey.h" +#endif +#ifdef PS2_MOUSE_ENABLE +# include "ps2_mouse.h" +#endif +#ifdef SERIAL_MOUSE_ENABLE +# include "serial_mouse.h" +#endif +#ifdef ADB_MOUSE_ENABLE +# include "adb.h" +#endif +#ifdef RGBLIGHT_ENABLE +# include "rgblight.h" +#endif +#ifdef LED_MATRIX_ENABLE +# include "led_matrix.h" +#endif +#ifdef RGB_MATRIX_ENABLE +# include "rgb_matrix.h" +#endif +#ifdef ENCODER_ENABLE +# include "encoder.h" +#endif +#ifdef STENO_ENABLE +# include "process_steno.h" +#endif +#ifdef SERIAL_LINK_ENABLE +# include "serial_link/system/serial_link.h" +#endif +#ifdef VISUALIZER_ENABLE +# include "visualizer/visualizer.h" +#endif +#ifdef POINTING_DEVICE_ENABLE +# include "pointing_device.h" +#endif +#ifdef MIDI_ENABLE +# include "process_midi.h" +#endif +#ifdef JOYSTICK_ENABLE +# include "process_joystick.h" +#endif +#ifdef HD44780_ENABLE +# include "hd44780.h" +#endif +#ifdef QWIIC_ENABLE +# include "qwiic.h" +#endif +#ifdef OLED_DRIVER_ENABLE +# include "oled_driver.h" +#endif +#ifdef ST7565_ENABLE +# include "st7565.h" +#endif +#ifdef VELOCIKEY_ENABLE +# include "velocikey.h" +#endif +#ifdef VIA_ENABLE +# include "via.h" +#endif +#ifdef DIP_SWITCH_ENABLE +# include "dip_switch.h" +#endif +#ifdef STM32_EEPROM_ENABLE +# include "eeprom_stm32.h" +#endif +#ifdef EEPROM_DRIVER +# include "eeprom_driver.h" +#endif +#if defined(CRC_ENABLE) +# include "crc.h" +#endif +#ifdef DIGITIZER_ENABLE +# include "digitizer.h" +#endif + +static uint32_t last_input_modification_time = 0; +uint32_t last_input_activity_time(void) { return last_input_modification_time; } +uint32_t last_input_activity_elapsed(void) { return timer_elapsed32(last_input_modification_time); } + +static uint32_t last_matrix_modification_time = 0; +uint32_t last_matrix_activity_time(void) { return last_matrix_modification_time; } +uint32_t last_matrix_activity_elapsed(void) { return timer_elapsed32(last_matrix_modification_time); } +void last_matrix_activity_trigger(void) { last_matrix_modification_time = last_input_modification_time = timer_read32(); } + +static uint32_t last_encoder_modification_time = 0; +uint32_t last_encoder_activity_time(void) { return last_encoder_modification_time; } +uint32_t last_encoder_activity_elapsed(void) { return timer_elapsed32(last_encoder_modification_time); } +void last_encoder_activity_trigger(void) { last_encoder_modification_time = last_input_modification_time = timer_read32(); } + +// Only enable this if console is enabled to print to +#if defined(DEBUG_MATRIX_SCAN_RATE) +static uint32_t matrix_timer = 0; +static uint32_t matrix_scan_count = 0; +static uint32_t last_matrix_scan_count = 0; + +void matrix_scan_perf_task(void) { + matrix_scan_count++; + + uint32_t timer_now = timer_read32(); + if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) { +# if defined(CONSOLE_ENABLE) + dprintf("matrix scan frequency: %lu\n", matrix_scan_count); +# endif + last_matrix_scan_count = matrix_scan_count; + matrix_timer = timer_now; + matrix_scan_count = 0; + } +} + +uint32_t get_matrix_scan_rate(void) { return last_matrix_scan_count; } +#else +# define matrix_scan_perf_task() +#endif + +#ifdef MATRIX_HAS_GHOST +extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; +static matrix_row_t get_real_keys(uint8_t row, matrix_row_t rowdata) { + matrix_row_t out = 0; + for (uint8_t col = 0; col < MATRIX_COLS; col++) { + // read each key in the row data and check if the keymap defines it as a real key + if (pgm_read_byte(&keymaps[0][row][col]) && (rowdata & (1 << col))) { + // this creates new row data, if a key is defined in the keymap, it will be set here + out |= 1 << col; + } + } + return out; +} + +static inline bool popcount_more_than_one(matrix_row_t rowdata) { + rowdata &= rowdata - 1; // if there are less than two bits (keys) set, rowdata will become zero + return rowdata; +} + +static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) { + /* No ghost exists when less than 2 keys are down on the row. + If there are "active" blanks in the matrix, the key can't be pressed by the user, + there is no doubt as to which keys are really being pressed. + The ghosts will be ignored, they are KC_NO. */ + rowdata = get_real_keys(row, rowdata); + if ((popcount_more_than_one(rowdata)) == 0) { + return false; + } + /* Ghost occurs when the row shares a column line with other row, + and two columns are read on each row. Blanks in the matrix don't matter, + so they are filtered out. + If there are two or more real keys pressed and they match columns with + at least two of another row's real keys, the row will be ignored. Keep in mind, + we are checking one row at a time, not all of them at once. + */ + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + if (i != row && popcount_more_than_one(get_real_keys(i, matrix_get_row(i)) & rowdata)) { + return true; + } + } + return false; +} + +#endif + +void disable_jtag(void) { +// To use PF4-7 (PC2-5 on ATmega32A), disable JTAG by writing JTD bit twice within four cycles. +#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) + MCUCR |= _BV(JTD); + MCUCR |= _BV(JTD); +#elif defined(__AVR_ATmega32A__) + MCUCSR |= _BV(JTD); + MCUCSR |= _BV(JTD); +#endif +} + +/** \brief matrix_setup + * + * FIXME: needs doc + */ +__attribute__((weak)) void matrix_setup(void) {} + +/** \brief keyboard_pre_init_user + * + * FIXME: needs doc + */ +__attribute__((weak)) void keyboard_pre_init_user(void) {} + +/** \brief keyboard_pre_init_kb + * + * FIXME: needs doc + */ +__attribute__((weak)) void keyboard_pre_init_kb(void) { keyboard_pre_init_user(); } + +/** \brief keyboard_post_init_user + * + * FIXME: needs doc + */ + +__attribute__((weak)) void keyboard_post_init_user() {} + +/** \brief keyboard_post_init_kb + * + * FIXME: needs doc + */ + +__attribute__((weak)) void keyboard_post_init_kb(void) { keyboard_post_init_user(); } + +/** \brief keyboard_setup + * + * FIXME: needs doc + */ +void keyboard_setup(void) { +#ifndef NO_JTAG_DISABLE + disable_jtag(); +#endif + print_set_sendchar(sendchar); +#ifdef STM32_EEPROM_ENABLE + EEPROM_Init(); +#endif +#ifdef EEPROM_DRIVER + eeprom_driver_init(); +#endif + matrix_setup(); + keyboard_pre_init_kb(); +} + +#ifndef SPLIT_KEYBOARD + +/** \brief is_keyboard_master + * + * FIXME: needs doc + */ +__attribute__((weak)) bool is_keyboard_master(void) { return true; } + +/** \brief is_keyboard_left + * + * FIXME: needs doc + */ +__attribute__((weak)) bool is_keyboard_left(void) { return true; } + +#endif + +/** \brief should_process_keypress + * + * Override this function if you have a condition where keypresses processing should change: + * - splits where the slave side needs to process for rgb/oled functionality + */ +__attribute__((weak)) bool should_process_keypress(void) { return is_keyboard_master(); } + +/** \brief housekeeping_task_kb + * + * Override this function if you have a need to execute code for every keyboard main loop iteration. + * This is specific to keyboard-level functionality. + */ +__attribute__((weak)) void housekeeping_task_kb(void) {} + +/** \brief housekeeping_task_user + * + * Override this function if you have a need to execute code for every keyboard main loop iteration. + * This is specific to user/keymap-level functionality. + */ +__attribute__((weak)) void housekeeping_task_user(void) {} + +/** \brief housekeeping_task + * + * Invokes hooks for executing code after QMK is done after each loop iteration. + */ +void housekeeping_task(void) { + housekeeping_task_kb(); + housekeeping_task_user(); +} + +/** \brief keyboard_init + * + * FIXME: needs doc + */ +void keyboard_init(void) { + timer_init(); + sync_timer_init(); + matrix_init(); +#if defined(CRC_ENABLE) + crc_init(); +#endif +#ifdef VIA_ENABLE + via_init(); +#endif +#ifdef QWIIC_ENABLE + qwiic_init(); +#endif +#ifdef OLED_DRIVER_ENABLE + oled_init(OLED_ROTATION_0); +#endif +#ifdef ST7565_ENABLE + st7565_init(DISPLAY_ROTATION_0); +#endif +#ifdef PS2_MOUSE_ENABLE + ps2_mouse_init(); +#endif +#ifdef SERIAL_MOUSE_ENABLE + serial_mouse_init(); +#endif +#ifdef ADB_MOUSE_ENABLE + adb_mouse_init(); +#endif +#ifdef BACKLIGHT_ENABLE + backlight_init(); +#endif +#ifdef RGBLIGHT_ENABLE + rgblight_init(); +#endif +#ifdef ENCODER_ENABLE + encoder_init(); +#endif +#ifdef STENO_ENABLE + steno_init(); +#endif +#ifdef POINTING_DEVICE_ENABLE + pointing_device_init(); +#endif +#if defined(NKRO_ENABLE) && defined(FORCE_NKRO) + keymap_config.nkro = 1; + eeconfig_update_keymap(keymap_config.raw); +#endif +#ifdef DIP_SWITCH_ENABLE + dip_switch_init(); +#endif + +#if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE) + debug_enable = true; +#endif + + keyboard_post_init_kb(); /* Always keep this last */ +} + +/** \brief key_event_task + * + * This function is responsible for calling into other systems when they need to respond to electrical switch press events. + * This is differnet than keycode events as no layer processing, or filtering occurs. + */ +void switch_events(uint8_t row, uint8_t col, bool pressed) { +#if defined(LED_MATRIX_ENABLE) + process_led_matrix(row, col, pressed); +#endif +#if defined(RGB_MATRIX_ENABLE) + process_rgb_matrix(row, col, pressed); +#endif +} + +/** \brief Keyboard task: Do keyboard routine jobs + * + * Do routine keyboard jobs: + * + * * scan matrix + * * handle mouse movements + * * run visualizer code + * * handle midi commands + * * light LEDs + * + * This is repeatedly called as fast as possible. + */ +void keyboard_task(void) { + static matrix_row_t matrix_prev[MATRIX_ROWS]; + static uint8_t led_status = 0; + matrix_row_t matrix_row = 0; + matrix_row_t matrix_change = 0; +#ifdef QMK_KEYS_PER_SCAN + uint8_t keys_processed = 0; +#endif +#ifdef ENCODER_ENABLE + bool encoders_changed = false; +#endif + + uint8_t matrix_changed = matrix_scan(); + if (matrix_changed) last_matrix_activity_trigger(); + + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { + matrix_row = matrix_get_row(r); + matrix_change = matrix_row ^ matrix_prev[r]; + if (matrix_change) { +#ifdef MATRIX_HAS_GHOST + if (has_ghost_in_row(r, matrix_row)) { + continue; + } +#endif + if (debug_matrix) matrix_print(); + matrix_row_t col_mask = 1; + for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) { + if (matrix_change & col_mask) { + if (should_process_keypress()) { + action_exec((keyevent_t){ + .key = (keypos_t){.row = r, .col = c}, .pressed = (matrix_row & col_mask), .time = (timer_read() | 1) /* time should not be 0 */ + }); + } + // record a processed key + matrix_prev[r] ^= col_mask; + + switch_events(r, c, (matrix_row & col_mask)); + +#ifdef QMK_KEYS_PER_SCAN + // only jump out if we have processed "enough" keys. + if (++keys_processed >= QMK_KEYS_PER_SCAN) +#endif + // process a key per task call + goto MATRIX_LOOP_END; + } + } + } + } + // call with pseudo tick event when no real key event. +#ifdef QMK_KEYS_PER_SCAN + // we can get here with some keys processed now. + if (!keys_processed) +#endif + action_exec(TICK); + +MATRIX_LOOP_END: + +#ifdef DEBUG_MATRIX_SCAN_RATE + matrix_scan_perf_task(); +#endif + +#if defined(RGBLIGHT_ENABLE) + rgblight_task(); +#endif + +#ifdef LED_MATRIX_ENABLE + led_matrix_task(); +#endif +#ifdef RGB_MATRIX_ENABLE + rgb_matrix_task(); +#endif + +#if defined(BACKLIGHT_ENABLE) +# if defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS) + backlight_task(); +# endif +#endif + +#ifdef ENCODER_ENABLE + encoders_changed = encoder_read(); + if (encoders_changed) last_encoder_activity_trigger(); +#endif + +#ifdef QWIIC_ENABLE + qwiic_task(); +#endif + +#ifdef OLED_DRIVER_ENABLE + oled_task(); +# ifndef OLED_DISABLE_TIMEOUT + // Wake up oled if user is using those fabulous keys or spinning those encoders! +# ifdef ENCODER_ENABLE + if (matrix_changed || encoders_changed) oled_on(); +# else + if (matrix_changed) oled_on(); +# endif +# endif +#endif + +#ifdef ST7565_ENABLE + st7565_task(); +# ifndef ST7565_DISABLE_TIMEOUT + // Wake up display if user is using those fabulous keys or spinning those encoders! +# ifdef ENCODER_ENABLE + if (matrix_changed || encoders_changed) st7565_on(); +# else + if (matrix_changed) st7565_on(); +# endif +# endif +#endif + +#ifdef MOUSEKEY_ENABLE + // mousekey repeat & acceleration + mousekey_task(); +#endif + +#ifdef PS2_MOUSE_ENABLE + ps2_mouse_task(); +#endif + +#ifdef SERIAL_MOUSE_ENABLE + serial_mouse_task(); +#endif + +#ifdef ADB_MOUSE_ENABLE + adb_mouse_task(); +#endif + +#ifdef SERIAL_LINK_ENABLE + serial_link_update(); +#endif + +#ifdef VISUALIZER_ENABLE + visualizer_update(default_layer_state, layer_state, visualizer_get_mods(), host_keyboard_leds()); +#endif + +#ifdef POINTING_DEVICE_ENABLE + pointing_device_task(); +#endif + +#ifdef MIDI_ENABLE + midi_task(); +#endif + +#ifdef VELOCIKEY_ENABLE + if (velocikey_enabled()) { + velocikey_decelerate(); + } +#endif + +#ifdef JOYSTICK_ENABLE + joystick_task(); +#endif + +#ifdef DIGITIZER_ENABLE + digitizer_task(); +#endif + + // update LED + if (led_status != host_keyboard_leds()) { + led_status = host_keyboard_leds(); + keyboard_set_leds(led_status); + } +} + +/** \brief keyboard set leds + * + * FIXME: needs doc + */ +void keyboard_set_leds(uint8_t leds) { + if (debug_keyboard) { + debug("keyboard_set_led: "); + debug_hex8(leds); + debug("\n"); + } + led_set(leds); +} diff --git a/quantum/keyboard.h b/quantum/keyboard.h new file mode 100644 index 0000000000..08f4e84f94 --- /dev/null +++ b/quantum/keyboard.h @@ -0,0 +1,90 @@ +/* +Copyright 2011,2012,2013 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* key matrix position */ +typedef struct { + uint8_t col; + uint8_t row; +} keypos_t; + +/* key event */ +typedef struct { + keypos_t key; + bool pressed; + uint16_t time; +} keyevent_t; + +/* equivalent test of keypos_t */ +#define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col) + +/* Rules for No Event: + * 1) (time == 0) to handle (keyevent_t){} as empty event + * 2) Matrix(255, 255) to make TICK event available + */ +static inline bool IS_NOEVENT(keyevent_t event) { return event.time == 0 || (event.key.row == 255 && event.key.col == 255); } +static inline bool IS_PRESSED(keyevent_t event) { return (!IS_NOEVENT(event) && event.pressed); } +static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) && !event.pressed); } + +/* Tick event */ +#define TICK \ + (keyevent_t) { .key = (keypos_t){.row = 255, .col = 255}, .pressed = false, .time = (timer_read() | 1) } + +/* it runs once at early stage of startup before keyboard_init. */ +void keyboard_setup(void); +/* it runs once after initializing host side protocol, debug and MCU peripherals. */ +void keyboard_init(void); +/* it runs repeatedly in main loop */ +void keyboard_task(void); +/* it runs when host LED status is updated */ +void keyboard_set_leds(uint8_t leds); +/* it runs whenever code has to behave differently on a slave */ +bool is_keyboard_master(void); +/* it runs whenever code has to behave differently on left vs right split */ +bool is_keyboard_left(void); + +void keyboard_pre_init_kb(void); +void keyboard_pre_init_user(void); +void keyboard_post_init_kb(void); +void keyboard_post_init_user(void); + +void housekeeping_task(void); // To be executed by the main loop in each backend TMK protocol +void housekeeping_task_kb(void); // To be overridden by keyboard-level code +void housekeeping_task_user(void); // To be overridden by user/keymap-level code + +uint32_t last_input_activity_time(void); // Timestamp of the last matrix or encoder activity +uint32_t last_input_activity_elapsed(void); // Number of milliseconds since the last matrix or encoder activity + +uint32_t last_matrix_activity_time(void); // Timestamp of the last matrix activity +uint32_t last_matrix_activity_elapsed(void); // Number of milliseconds since the last matrix activity + +uint32_t last_encoder_activity_time(void); // Timestamp of the last encoder activity +uint32_t last_encoder_activity_elapsed(void); // Number of milliseconds since the last encoder activity + +uint32_t get_matrix_scan_rate(void); + +#ifdef __cplusplus +} +#endif diff --git a/quantum/keycode.h b/quantum/keycode.h new file mode 100644 index 0000000000..8facabd818 --- /dev/null +++ b/quantum/keycode.h @@ -0,0 +1,560 @@ +/* +Copyright 2011,2012 Jun Wako + +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, either version 2 of the License, or +(at your option) any later version. + +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 . +*/ + +/* + * Keycodes based on HID Keyboard/Keypad Usage Page (0x07) plus media keys from Generic Desktop Page (0x01) and Consumer Page (0x0C) + * + * See https://web.archive.org/web/20060218214400/http://www.usb.org/developers/devclass_docs/Hut1_12.pdf + * or http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (older) + */ + +#pragma once + +/* FIXME: Add doxygen comments here */ + +#define IS_ERROR(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED) +#define IS_ANY(code) (KC_A <= (code) && (code) <= 0xFF) +#define IS_KEY(code) (KC_A <= (code) && (code) <= KC_EXSEL) +#define IS_MOD(code) (KC_LCTRL <= (code) && (code) <= KC_RGUI) + +#define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) +#define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE) +#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_BRID) + +#define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31) + +#define IS_MOUSEKEY(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2) +#define IS_MOUSEKEY_MOVE(code) (KC_MS_UP <= (code) && (code) <= KC_MS_RIGHT) +#define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1 <= (code) && (code) <= KC_MS_BTN8) +#define IS_MOUSEKEY_WHEEL(code) (KC_MS_WH_UP <= (code) && (code) <= KC_MS_WH_RIGHT) +#define IS_MOUSEKEY_ACCEL(code) (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2) + +#define MOD_BIT(code) (1 << MOD_INDEX(code)) +#define MOD_INDEX(code) ((code)&0x07) + +#define MOD_MASK_CTRL (MOD_BIT(KC_LCTRL) | MOD_BIT(KC_RCTRL)) +#define MOD_MASK_SHIFT (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) +#define MOD_MASK_ALT (MOD_BIT(KC_LALT) | MOD_BIT(KC_RALT)) +#define MOD_MASK_GUI (MOD_BIT(KC_LGUI) | MOD_BIT(KC_RGUI)) +#define MOD_MASK_CS (MOD_MASK_CTRL | MOD_MASK_SHIFT) +#define MOD_MASK_CA (MOD_MASK_CTRL | MOD_MASK_ALT) +#define MOD_MASK_CG (MOD_MASK_CTRL | MOD_MASK_GUI) +#define MOD_MASK_SA (MOD_MASK_SHIFT | MOD_MASK_ALT) +#define MOD_MASK_SG (MOD_MASK_SHIFT | MOD_MASK_GUI) +#define MOD_MASK_AG (MOD_MASK_ALT | MOD_MASK_GUI) +#define MOD_MASK_CSA (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_ALT) +#define MOD_MASK_CSG (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_GUI) +#define MOD_MASK_CAG (MOD_MASK_CTRL | MOD_MASK_ALT | MOD_MASK_GUI) +#define MOD_MASK_SAG (MOD_MASK_SHIFT | MOD_MASK_ALT | MOD_MASK_GUI) +#define MOD_MASK_CSAG (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_ALT | MOD_MASK_GUI) + +#define FN_BIT(code) (1 << FN_INDEX(code)) +#define FN_INDEX(code) ((code)-KC_FN0) +#define FN_MIN KC_FN0 +#define FN_MAX KC_FN31 + +/* + * Short names for ease of definition of keymap + */ +/* Transparent */ +#define KC_TRANSPARENT 0x01 +#define KC_TRNS KC_TRANSPARENT + +/* Punctuation */ +#define KC_ENT KC_ENTER +#define KC_ESC KC_ESCAPE +#define KC_BSPC KC_BSPACE +#define KC_SPC KC_SPACE +#define KC_MINS KC_MINUS +#define KC_EQL KC_EQUAL +#define KC_LBRC KC_LBRACKET +#define KC_RBRC KC_RBRACKET +#define KC_BSLS KC_BSLASH +#define KC_NUHS KC_NONUS_HASH +#define KC_SCLN KC_SCOLON +#define KC_QUOT KC_QUOTE +#define KC_GRV KC_GRAVE +#define KC_COMM KC_COMMA +#define KC_SLSH KC_SLASH +#define KC_NUBS KC_NONUS_BSLASH + +/* Lock Keys */ +#define KC_CLCK KC_CAPSLOCK +#define KC_CAPS KC_CAPSLOCK +#define KC_SLCK KC_SCROLLLOCK +#define KC_NLCK KC_NUMLOCK +#define KC_LCAP KC_LOCKING_CAPS +#define KC_LNUM KC_LOCKING_NUM +#define KC_LSCR KC_LOCKING_SCROLL + +/* Commands */ +#define KC_PSCR KC_PSCREEN +#define KC_PAUS KC_PAUSE +#define KC_BRK KC_PAUSE +#define KC_INS KC_INSERT +#define KC_DEL KC_DELETE +#define KC_PGDN KC_PGDOWN +#define KC_RGHT KC_RIGHT +#define KC_APP KC_APPLICATION +#define KC_EXEC KC_EXECUTE +#define KC_SLCT KC_SELECT +#define KC_AGIN KC_AGAIN +#define KC_PSTE KC_PASTE +#define KC_ERAS KC_ALT_ERASE +#define KC_CLR KC_CLEAR + +/* Keypad */ +#define KC_PSLS KC_KP_SLASH +#define KC_PAST KC_KP_ASTERISK +#define KC_PMNS KC_KP_MINUS +#define KC_PPLS KC_KP_PLUS +#define KC_PENT KC_KP_ENTER +#define KC_P1 KC_KP_1 +#define KC_P2 KC_KP_2 +#define KC_P3 KC_KP_3 +#define KC_P4 KC_KP_4 +#define KC_P5 KC_KP_5 +#define KC_P6 KC_KP_6 +#define KC_P7 KC_KP_7 +#define KC_P8 KC_KP_8 +#define KC_P9 KC_KP_9 +#define KC_P0 KC_KP_0 +#define KC_PDOT KC_KP_DOT +#define KC_PEQL KC_KP_EQUAL +#define KC_PCMM KC_KP_COMMA + +/* Japanese specific */ +#define KC_ZKHK KC_GRAVE +#define KC_RO KC_INT1 +#define KC_KANA KC_INT2 +#define KC_JYEN KC_INT3 +#define KC_HENK KC_INT4 +#define KC_MHEN KC_INT5 + +/* Korean specific */ +#define KC_HAEN KC_LANG1 +#define KC_HANJ KC_LANG2 + +/* Modifiers */ +#define KC_LCTL KC_LCTRL +#define KC_LSFT KC_LSHIFT +#define KC_LOPT KC_LALT +#define KC_LCMD KC_LGUI +#define KC_LWIN KC_LGUI +#define KC_RCTL KC_RCTRL +#define KC_RSFT KC_RSHIFT +#define KC_ALGR KC_RALT +#define KC_ROPT KC_RALT +#define KC_RCMD KC_RGUI +#define KC_RWIN KC_RGUI + +/* Generic Desktop Page (0x01) */ +#define KC_PWR KC_SYSTEM_POWER +#define KC_SLEP KC_SYSTEM_SLEEP +#define KC_WAKE KC_SYSTEM_WAKE + +/* Consumer Page (0x0C) */ +#define KC_MUTE KC_AUDIO_MUTE +#define KC_VOLU KC_AUDIO_VOL_UP +#define KC_VOLD KC_AUDIO_VOL_DOWN +#define KC_MNXT KC_MEDIA_NEXT_TRACK +#define KC_MPRV KC_MEDIA_PREV_TRACK +#define KC_MSTP KC_MEDIA_STOP +#define KC_MPLY KC_MEDIA_PLAY_PAUSE +#define KC_MSEL KC_MEDIA_SELECT +#define KC_EJCT KC_MEDIA_EJECT +#define KC_CALC KC_CALCULATOR +#define KC_MYCM KC_MY_COMPUTER +#define KC_WSCH KC_WWW_SEARCH +#define KC_WHOM KC_WWW_HOME +#define KC_WBAK KC_WWW_BACK +#define KC_WFWD KC_WWW_FORWARD +#define KC_WSTP KC_WWW_STOP +#define KC_WREF KC_WWW_REFRESH +#define KC_WFAV KC_WWW_FAVORITES +#define KC_MFFD KC_MEDIA_FAST_FORWARD +#define KC_MRWD KC_MEDIA_REWIND +#define KC_BRIU KC_BRIGHTNESS_UP +#define KC_BRID KC_BRIGHTNESS_DOWN + +/* System Specific */ +#define KC_BRMU KC_PAUSE +#define KC_BRMD KC_SCROLLLOCK + +/* Mouse Keys */ +#define KC_MS_U KC_MS_UP +#define KC_MS_D KC_MS_DOWN +#define KC_MS_L KC_MS_LEFT +#define KC_MS_R KC_MS_RIGHT +#define KC_BTN1 KC_MS_BTN1 +#define KC_BTN2 KC_MS_BTN2 +#define KC_BTN3 KC_MS_BTN3 +#define KC_BTN4 KC_MS_BTN4 +#define KC_BTN5 KC_MS_BTN5 +#define KC_BTN6 KC_MS_BTN6 +#define KC_BTN7 KC_MS_BTN7 +#define KC_BTN8 KC_MS_BTN8 +#define KC_WH_U KC_MS_WH_UP +#define KC_WH_D KC_MS_WH_DOWN +#define KC_WH_L KC_MS_WH_LEFT +#define KC_WH_R KC_MS_WH_RIGHT +#define KC_ACL0 KC_MS_ACCEL0 +#define KC_ACL1 KC_MS_ACCEL1 +#define KC_ACL2 KC_MS_ACCEL2 + +/* Keyboard/Keypad Page (0x07) */ +enum hid_keyboard_keypad_usage { + KC_NO = 0x00, + KC_ROLL_OVER, + KC_POST_FAIL, + KC_UNDEFINED, + KC_A, + KC_B, + KC_C, + KC_D, + KC_E, + KC_F, + KC_G, + KC_H, + KC_I, + KC_J, + KC_K, + KC_L, + KC_M, // 0x10 + KC_N, + KC_O, + KC_P, + KC_Q, + KC_R, + KC_S, + KC_T, + KC_U, + KC_V, + KC_W, + KC_X, + KC_Y, + KC_Z, + KC_1, + KC_2, + KC_3, // 0x20 + KC_4, + KC_5, + KC_6, + KC_7, + KC_8, + KC_9, + KC_0, + KC_ENTER, + KC_ESCAPE, + KC_BSPACE, + KC_TAB, + KC_SPACE, + KC_MINUS, + KC_EQUAL, + KC_LBRACKET, + KC_RBRACKET, // 0x30 + KC_BSLASH, + KC_NONUS_HASH, + KC_SCOLON, + KC_QUOTE, + KC_GRAVE, + KC_COMMA, + KC_DOT, + KC_SLASH, + KC_CAPSLOCK, + KC_F1, + KC_F2, + KC_F3, + KC_F4, + KC_F5, + KC_F6, + KC_F7, // 0x40 + KC_F8, + KC_F9, + KC_F10, + KC_F11, + KC_F12, + KC_PSCREEN, + KC_SCROLLLOCK, + KC_PAUSE, + KC_INSERT, + KC_HOME, + KC_PGUP, + KC_DELETE, + KC_END, + KC_PGDOWN, + KC_RIGHT, + KC_LEFT, // 0x50 + KC_DOWN, + KC_UP, + KC_NUMLOCK, + KC_KP_SLASH, + KC_KP_ASTERISK, + KC_KP_MINUS, + KC_KP_PLUS, + KC_KP_ENTER, + KC_KP_1, + KC_KP_2, + KC_KP_3, + KC_KP_4, + KC_KP_5, + KC_KP_6, + KC_KP_7, + KC_KP_8, // 0x60 + KC_KP_9, + KC_KP_0, + KC_KP_DOT, + KC_NONUS_BSLASH, + KC_APPLICATION, + KC_POWER, + KC_KP_EQUAL, + KC_F13, + KC_F14, + KC_F15, + KC_F16, + KC_F17, + KC_F18, + KC_F19, + KC_F20, + KC_F21, // 0x70 + KC_F22, + KC_F23, + KC_F24, + KC_EXECUTE, + KC_HELP, + KC_MENU, + KC_SELECT, + KC_STOP, + KC_AGAIN, + KC_UNDO, + KC_CUT, + KC_COPY, + KC_PASTE, + KC_FIND, + KC__MUTE, + KC__VOLUP, // 0x80 + KC__VOLDOWN, + KC_LOCKING_CAPS, + KC_LOCKING_NUM, + KC_LOCKING_SCROLL, + KC_KP_COMMA, + KC_KP_EQUAL_AS400, + KC_INT1, + KC_INT2, + KC_INT3, + KC_INT4, + KC_INT5, + KC_INT6, + KC_INT7, + KC_INT8, + KC_INT9, + KC_LANG1, // 0x90 + KC_LANG2, + KC_LANG3, + KC_LANG4, + KC_LANG5, + KC_LANG6, + KC_LANG7, + KC_LANG8, + KC_LANG9, + KC_ALT_ERASE, + KC_SYSREQ, + KC_CANCEL, + KC_CLEAR, + KC_PRIOR, + KC_RETURN, + KC_SEPARATOR, + KC_OUT, // 0xA0 + KC_OPER, + KC_CLEAR_AGAIN, + KC_CRSEL, + KC_EXSEL, + +#if 0 + // *************************************************************** + // These keycodes are present in the HID spec, but are * + // nonfunctional on modern OSes. QMK uses this range (0xA5-0xDF) * + // for the media and function keys instead - see below. * + // *************************************************************** + + KC_KP_00 = 0xB0, + KC_KP_000, + KC_THOUSANDS_SEPARATOR, + KC_DECIMAL_SEPARATOR, + KC_CURRENCY_UNIT, + KC_CURRENCY_SUB_UNIT, + KC_KP_LPAREN, + KC_KP_RPAREN, + KC_KP_LCBRACKET, + KC_KP_RCBRACKET, + KC_KP_TAB, + KC_KP_BSPACE, + KC_KP_A, + KC_KP_B, + KC_KP_C, + KC_KP_D, + KC_KP_E, //0xC0 + KC_KP_F, + KC_KP_XOR, + KC_KP_HAT, + KC_KP_PERC, + KC_KP_LT, + KC_KP_GT, + KC_KP_AND, + KC_KP_LAZYAND, + KC_KP_OR, + KC_KP_LAZYOR, + KC_KP_COLON, + KC_KP_HASH, + KC_KP_SPACE, + KC_KP_ATMARK, + KC_KP_EXCLAMATION, + KC_KP_MEM_STORE, //0xD0 + KC_KP_MEM_RECALL, + KC_KP_MEM_CLEAR, + KC_KP_MEM_ADD, + KC_KP_MEM_SUB, + KC_KP_MEM_MUL, + KC_KP_MEM_DIV, + KC_KP_PLUS_MINUS, + KC_KP_CLEAR, + KC_KP_CLEAR_ENTRY, + KC_KP_BINARY, + KC_KP_OCTAL, + KC_KP_DECIMAL, + KC_KP_HEXADECIMAL, +#endif + + /* Modifiers */ + KC_LCTRL = 0xE0, + KC_LSHIFT, + KC_LALT, + KC_LGUI, + KC_RCTRL, + KC_RSHIFT, + KC_RALT, + KC_RGUI + + // ********************************************** + // * 0xF0-0xFF are unallocated in the HID spec. * + // * QMK uses these for Mouse Keys - see below. * + // ********************************************** +}; + +/* Media and Function keys */ +enum internal_special_keycodes { + /* Generic Desktop Page (0x01) */ + KC_SYSTEM_POWER = 0xA5, + KC_SYSTEM_SLEEP, + KC_SYSTEM_WAKE, + + /* Consumer Page (0x0C) */ + KC_AUDIO_MUTE, + KC_AUDIO_VOL_UP, + KC_AUDIO_VOL_DOWN, + KC_MEDIA_NEXT_TRACK, + KC_MEDIA_PREV_TRACK, + KC_MEDIA_STOP, + KC_MEDIA_PLAY_PAUSE, + KC_MEDIA_SELECT, + KC_MEDIA_EJECT, // 0xB0 + KC_MAIL, + KC_CALCULATOR, + KC_MY_COMPUTER, + KC_WWW_SEARCH, + KC_WWW_HOME, + KC_WWW_BACK, + KC_WWW_FORWARD, + KC_WWW_STOP, + KC_WWW_REFRESH, + KC_WWW_FAVORITES, + KC_MEDIA_FAST_FORWARD, + KC_MEDIA_REWIND, + KC_BRIGHTNESS_UP, + KC_BRIGHTNESS_DOWN, + + /* Fn keys */ + KC_FN0 = 0xC0, + KC_FN1, + KC_FN2, + KC_FN3, + KC_FN4, + KC_FN5, + KC_FN6, + KC_FN7, + KC_FN8, + KC_FN9, + KC_FN10, + KC_FN11, + KC_FN12, + KC_FN13, + KC_FN14, + KC_FN15, + KC_FN16, // 0xD0 + KC_FN17, + KC_FN18, + KC_FN19, + KC_FN20, + KC_FN21, + KC_FN22, + KC_FN23, + KC_FN24, + KC_FN25, + KC_FN26, + KC_FN27, + KC_FN28, + KC_FN29, + KC_FN30, + KC_FN31 +}; + +enum mouse_keys { +/* Mouse Buttons */ +#ifdef VIA_ENABLE + KC_MS_UP = 0xF0, +#else + KC_MS_UP = 0xED, +#endif + KC_MS_DOWN, + KC_MS_LEFT, + KC_MS_RIGHT, // 0xF0 + KC_MS_BTN1, + KC_MS_BTN2, + KC_MS_BTN3, + KC_MS_BTN4, + KC_MS_BTN5, +#ifdef VIA_ENABLE + KC_MS_BTN6 = KC_MS_BTN5, + KC_MS_BTN7 = KC_MS_BTN5, + KC_MS_BTN8 = KC_MS_BTN5, +#else + KC_MS_BTN6, + KC_MS_BTN7, + KC_MS_BTN8, +#endif + + /* Mouse Wheel */ + KC_MS_WH_UP, + KC_MS_WH_DOWN, + KC_MS_WH_LEFT, + KC_MS_WH_RIGHT, + + /* Acceleration */ + KC_MS_ACCEL0, + KC_MS_ACCEL1, + KC_MS_ACCEL2 // 0xFF +}; diff --git a/quantum/via.h b/quantum/via.h index d0510fcabd..de0a21da20 100644 --- a/quantum/via.h +++ b/quantum/via.h @@ -16,7 +16,7 @@ #pragma once -#include "tmk_core/common/eeconfig.h" // for EECONFIG_SIZE +#include "eeconfig.h" // for EECONFIG_SIZE // Keyboard level code can change where VIA stores the magic. // The magic is the build date YYMMDD encoded as BCD in 3 bytes, diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 57de8d95e8..69d27e6c0b 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -1,14 +1,8 @@ COMMON_DIR = common PLATFORM_COMMON_DIR = $(COMMON_DIR)/$(PLATFORM_KEY) -TMK_COMMON_SRC += $(COMMON_DIR)/host.c \ - $(COMMON_DIR)/keyboard.c \ - $(COMMON_DIR)/action.c \ - $(COMMON_DIR)/action_tapping.c \ - $(COMMON_DIR)/action_macro.c \ - $(COMMON_DIR)/action_layer.c \ - $(COMMON_DIR)/action_util.c \ - $(COMMON_DIR)/eeconfig.c \ +TMK_COMMON_SRC += \ + $(COMMON_DIR)/host.c \ $(COMMON_DIR)/report.c \ $(COMMON_DIR)/sync_timer.c \ $(COMMON_DIR)/usb_util.c \ diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c deleted file mode 100644 index d19fd2a045..0000000000 --- a/tmk_core/common/action.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* -Copyright 2012,2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 "host.h" -#include "keycode.h" -#include "keyboard.h" -#include "mousekey.h" -#include "command.h" -#include "led.h" -#include "action_layer.h" -#include "action_tapping.h" -#include "action_macro.h" -#include "action_util.h" -#include "action.h" -#include "wait.h" - -#ifdef BACKLIGHT_ENABLE -# include "backlight.h" -#endif - -#ifdef DEBUG_ACTION -# include "debug.h" -#else -# include "nodebug.h" -#endif - -#ifdef POINTING_DEVICE_ENABLE -# include "pointing_device.h" -#endif - -int tp_buttons; - -#if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) -int retro_tapping_counter = 0; -#endif - -#ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY -__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) { return false; } -#endif - -#ifdef RETRO_TAPPING_PER_KEY -__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) { return false; } -#endif - -__attribute__((weak)) bool pre_process_record_quantum(keyrecord_t *record) { return true; } - -#ifndef TAP_CODE_DELAY -# define TAP_CODE_DELAY 0 -#endif -#ifndef TAP_HOLD_CAPS_DELAY -# define TAP_HOLD_CAPS_DELAY 80 -#endif -/** \brief Called to execute an action. - * - * FIXME: Needs documentation. - */ -void action_exec(keyevent_t event) { - if (!IS_NOEVENT(event)) { - dprint("\n---- action_exec: start -----\n"); - dprint("EVENT: "); - debug_event(event); - dprintln(); -#if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) - retro_tapping_counter++; -#endif - } - - if (event.pressed) { - // clear the potential weak mods left by previously pressed keys - clear_weak_mods(); - } - -#ifdef SWAP_HANDS_ENABLE - if (!IS_NOEVENT(event)) { - process_hand_swap(&event); - } -#endif - - keyrecord_t record = {.event = event}; - -#ifndef NO_ACTION_ONESHOT -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - if (has_oneshot_layer_timed_out()) { - clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); - } - if (has_oneshot_mods_timed_out()) { - clear_oneshot_mods(); - } -# ifdef SWAP_HANDS_ENABLE - if (has_oneshot_swaphands_timed_out()) { - clear_oneshot_swaphands(); - } -# endif -# endif -#endif - -#ifndef NO_ACTION_TAPPING - if (IS_NOEVENT(record.event) || pre_process_record_quantum(&record)) { - action_tapping_process(record); - } -#else - if (IS_NOEVENT(record.event) || pre_process_record_quantum(&record)) { - process_record(&record); - } - if (!IS_NOEVENT(record.event)) { - dprint("processed: "); - debug_record(record); - dprintln(); - } -#endif -} - -#ifdef SWAP_HANDS_ENABLE -bool swap_hands = false; -bool swap_held = false; - -/** \brief Process Hand Swap - * - * FIXME: Needs documentation. - */ -void process_hand_swap(keyevent_t *event) { - static swap_state_row_t swap_state[MATRIX_ROWS]; - - keypos_t pos = event->key; - swap_state_row_t col_bit = (swap_state_row_t)1 << pos.col; - bool do_swap = event->pressed ? swap_hands : swap_state[pos.row] & (col_bit); - - if (do_swap) { - event->key.row = pgm_read_byte(&hand_swap_config[pos.row][pos.col].row); - event->key.col = pgm_read_byte(&hand_swap_config[pos.row][pos.col].col); - swap_state[pos.row] |= col_bit; - } else { - swap_state[pos.row] &= ~(col_bit); - } -} -#endif - -#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) -bool disable_action_cache = false; - -void process_record_nocache(keyrecord_t *record) { - disable_action_cache = true; - process_record(record); - disable_action_cache = false; -} -#else -void process_record_nocache(keyrecord_t *record) { process_record(record); } -#endif - -__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; } - -__attribute__((weak)) void post_process_record_quantum(keyrecord_t *record) {} - -#ifndef NO_ACTION_TAPPING -/** \brief Allows for handling tap-hold actions immediately instead of waiting for TAPPING_TERM or another keypress. - * - * FIXME: Needs documentation. - */ -void process_record_tap_hint(keyrecord_t *record) { - action_t action = layer_switch_get_action(record->event.key); - - switch (action.kind.id) { -# ifdef SWAP_HANDS_ENABLE - case ACT_SWAP_HANDS: - switch (action.swap.code) { - case OP_SH_ONESHOT: - break; - case OP_SH_TAP_TOGGLE: - default: - swap_hands = !swap_hands; - swap_held = true; - } - break; -# endif - } -} -#endif - -/** \brief Take a key event (key press or key release) and processes it. - * - * FIXME: Needs documentation. - */ -void process_record(keyrecord_t *record) { - if (IS_NOEVENT(record->event)) { - return; - } - - if (!process_record_quantum(record)) { -#ifndef NO_ACTION_ONESHOT - if (is_oneshot_layer_active() && record->event.pressed) { - clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); - } -#endif - return; - } - - process_record_handler(record); - post_process_record_quantum(record); -} - -void process_record_handler(keyrecord_t *record) { -#ifdef COMBO_ENABLE - action_t action; - if (record->keycode) { - action = action_for_keycode(record->keycode); - } else { - action = store_or_get_action(record->event.pressed, record->event.key); - } -#else - action_t action = store_or_get_action(record->event.pressed, record->event.key); -#endif - dprint("ACTION: "); - debug_action(action); -#ifndef NO_ACTION_LAYER - dprint(" layer_state: "); - layer_debug(); - dprint(" default_layer_state: "); - default_layer_debug(); -#endif - dprintln(); - - process_action(record, action); -} - -#if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE) -void register_button(bool pressed, enum mouse_buttons button) { -# ifdef PS2_MOUSE_ENABLE - tp_buttons = pressed ? tp_buttons | button : tp_buttons & ~button; -# endif -# ifdef POINTING_DEVICE_ENABLE - report_mouse_t currentReport = pointing_device_get_report(); - currentReport.buttons = pressed ? currentReport.buttons | button : currentReport.buttons & ~button; - pointing_device_set_report(currentReport); -# endif -} -#endif - -/** \brief Take an action and processes it. - * - * FIXME: Needs documentation. - */ -void process_action(keyrecord_t *record, action_t action) { - keyevent_t event = record->event; -#ifndef NO_ACTION_TAPPING - uint8_t tap_count = record->tap.count; -#endif - -#ifndef NO_ACTION_ONESHOT - bool do_release_oneshot = false; - // notice we only clear the one shot layer if the pressed key is not a modifier. - if (is_oneshot_layer_active() && event.pressed && (action.kind.id == ACT_USAGE || !IS_MOD(action.key.code)) -# ifdef SWAP_HANDS_ENABLE - && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT) -# endif - ) { - clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); - do_release_oneshot = !is_oneshot_layer_active(); - } -#endif - - switch (action.kind.id) { - /* Key and Mods */ - case ACT_LMODS: - case ACT_RMODS: { - uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods : action.key.mods << 4; - if (event.pressed) { - if (mods) { - if (IS_MOD(action.key.code) || action.key.code == KC_NO) { - // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless. - // This also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT). - // Same applies for some keys like KC_MEH which are declared as MEH(KC_NO). - add_mods(mods); - } else { - add_weak_mods(mods); - } - send_keyboard_report(); - } - register_code(action.key.code); - } else { - unregister_code(action.key.code); - if (mods) { - if (IS_MOD(action.key.code) || action.key.code == KC_NO) { - del_mods(mods); - } else { - del_weak_mods(mods); - } - send_keyboard_report(); - } - } - } break; -#ifndef NO_ACTION_TAPPING - case ACT_LMODS_TAP: - case ACT_RMODS_TAP: { - uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods : action.key.mods << 4; - switch (action.layer_tap.code) { -# ifndef NO_ACTION_ONESHOT - case MODS_ONESHOT: - // Oneshot modifier - if (event.pressed) { - if (tap_count == 0) { - dprint("MODS_TAP: Oneshot: 0\n"); - register_mods(mods | get_oneshot_mods()); - } else if (tap_count == 1) { - dprint("MODS_TAP: Oneshot: start\n"); - set_oneshot_mods(mods | get_oneshot_mods()); -# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 - } else if (tap_count == ONESHOT_TAP_TOGGLE) { - dprint("MODS_TAP: Toggling oneshot"); - clear_oneshot_mods(); - set_oneshot_locked_mods(mods); - register_mods(mods); -# endif - } else { - register_mods(mods | get_oneshot_mods()); - } - } else { - if (tap_count == 0) { - clear_oneshot_mods(); - unregister_mods(mods); - } else if (tap_count == 1) { - // Retain Oneshot mods -# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 - if (mods & get_mods()) { - clear_oneshot_locked_mods(); - clear_oneshot_mods(); - unregister_mods(mods); - } - } else if (tap_count == ONESHOT_TAP_TOGGLE) { - // Toggle Oneshot Layer -# endif - } else { - clear_oneshot_mods(); - unregister_mods(mods); - } - } - break; -# endif - case MODS_TAP_TOGGLE: - if (event.pressed) { - if (tap_count <= TAPPING_TOGGLE) { - register_mods(mods); - } - } else { - if (tap_count < TAPPING_TOGGLE) { - unregister_mods(mods); - } - } - break; - default: - if (event.pressed) { - if (tap_count > 0) { -# if !defined(IGNORE_MOD_TAP_INTERRUPT) || defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY) - if ( -# ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY - !get_ignore_mod_tap_interrupt(get_event_keycode(record->event, false), record) && -# endif - record->tap.interrupted) { - dprint("mods_tap: tap: cancel: add_mods\n"); - // ad hoc: set 0 to cancel tap - record->tap.count = 0; - register_mods(mods); - } else -# endif - { - dprint("MODS_TAP: Tap: register_code\n"); - register_code(action.key.code); - } - } else { - dprint("MODS_TAP: No tap: add_mods\n"); - register_mods(mods); - } - } else { - if (tap_count > 0) { - dprint("MODS_TAP: Tap: unregister_code\n"); - if (action.layer_tap.code == KC_CAPS) { - wait_ms(TAP_HOLD_CAPS_DELAY); - } else { - wait_ms(TAP_CODE_DELAY); - } - unregister_code(action.key.code); - } else { - dprint("MODS_TAP: No tap: add_mods\n"); - unregister_mods(mods); - } - } - break; - } - } break; -#endif -#ifdef EXTRAKEY_ENABLE - /* other HID usage */ - case ACT_USAGE: - switch (action.usage.page) { - case PAGE_SYSTEM: - if (event.pressed) { - host_system_send(action.usage.code); - } else { - host_system_send(0); - } - break; - case PAGE_CONSUMER: - if (event.pressed) { - host_consumer_send(action.usage.code); - } else { - host_consumer_send(0); - } - break; - } - break; -#endif -#ifdef MOUSEKEY_ENABLE - /* Mouse key */ - case ACT_MOUSEKEY: - if (event.pressed) { - mousekey_on(action.key.code); - } else { - mousekey_off(action.key.code); - } - switch (action.key.code) { -# if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE) -# ifdef POINTING_DEVICE_ENABLE - case KC_MS_BTN1 ... KC_MS_BTN8: -# else - case KC_MS_BTN1 ... KC_MS_BTN3: -# endif - register_button(event.pressed, MOUSE_BTN_MASK(action.key.code - KC_MS_BTN1)); - break; -# endif - default: - mousekey_send(); - break; - } - break; -#endif -#ifndef NO_ACTION_LAYER - case ACT_LAYER: - if (action.layer_bitop.on == 0) { - /* Default Layer Bitwise Operation */ - if (!event.pressed) { - uint8_t shift = action.layer_bitop.part * 4; - layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift; - layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0; - switch (action.layer_bitop.op) { - case OP_BIT_AND: - default_layer_and(bits | mask); - break; - case OP_BIT_OR: - default_layer_or(bits | mask); - break; - case OP_BIT_XOR: - default_layer_xor(bits | mask); - break; - case OP_BIT_SET: - default_layer_set(bits | mask); - break; - } - } - } else { - /* Layer Bitwise Operation */ - if (event.pressed ? (action.layer_bitop.on & ON_PRESS) : (action.layer_bitop.on & ON_RELEASE)) { - uint8_t shift = action.layer_bitop.part * 4; - layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift; - layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0; - switch (action.layer_bitop.op) { - case OP_BIT_AND: - layer_and(bits | mask); - break; - case OP_BIT_OR: - layer_or(bits | mask); - break; - case OP_BIT_XOR: - layer_xor(bits | mask); - break; - case OP_BIT_SET: - layer_state_set(bits | mask); - break; - } - } - } - break; - case ACT_LAYER_MODS: - if (event.pressed) { - layer_on(action.layer_mods.layer); - register_mods(action.layer_mods.mods); - } else { - unregister_mods(action.layer_mods.mods); - layer_off(action.layer_mods.layer); - } - break; -# ifndef NO_ACTION_TAPPING - case ACT_LAYER_TAP: - case ACT_LAYER_TAP_EXT: - switch (action.layer_tap.code) { - case OP_TAP_TOGGLE: - /* tap toggle */ - if (event.pressed) { - if (tap_count < TAPPING_TOGGLE) { - layer_invert(action.layer_tap.val); - } - } else { - if (tap_count <= TAPPING_TOGGLE) { - layer_invert(action.layer_tap.val); - } - } - break; - case OP_ON_OFF: - event.pressed ? layer_on(action.layer_tap.val) : layer_off(action.layer_tap.val); - break; - case OP_OFF_ON: - event.pressed ? layer_off(action.layer_tap.val) : layer_on(action.layer_tap.val); - break; - case OP_SET_CLEAR: - event.pressed ? layer_move(action.layer_tap.val) : layer_clear(); - break; -# ifndef NO_ACTION_ONESHOT - case OP_ONESHOT: - // Oneshot modifier -# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 - do_release_oneshot = false; - if (event.pressed) { - del_mods(get_oneshot_locked_mods()); - if (get_oneshot_layer_state() == ONESHOT_TOGGLED) { - reset_oneshot_layer(); - layer_off(action.layer_tap.val); - break; - } else if (tap_count < ONESHOT_TAP_TOGGLE) { - layer_on(action.layer_tap.val); - set_oneshot_layer(action.layer_tap.val, ONESHOT_START); - } - } else { - add_mods(get_oneshot_locked_mods()); - if (tap_count >= ONESHOT_TAP_TOGGLE) { - reset_oneshot_layer(); - clear_oneshot_locked_mods(); - set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED); - } else { - clear_oneshot_layer_state(ONESHOT_PRESSED); - } - } -# else - if (event.pressed) { - layer_on(action.layer_tap.val); - set_oneshot_layer(action.layer_tap.val, ONESHOT_START); - } else { - clear_oneshot_layer_state(ONESHOT_PRESSED); - if (tap_count > 1) { - clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); - } - } -# endif - break; -# endif - default: - /* tap key */ - if (event.pressed) { - if (tap_count > 0) { - dprint("KEYMAP_TAP_KEY: Tap: register_code\n"); - register_code(action.layer_tap.code); - } else { - dprint("KEYMAP_TAP_KEY: No tap: On on press\n"); - layer_on(action.layer_tap.val); - } - } else { - if (tap_count > 0) { - dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n"); - if (action.layer_tap.code == KC_CAPS) { - wait_ms(TAP_HOLD_CAPS_DELAY); - } else { - wait_ms(TAP_CODE_DELAY); - } - unregister_code(action.layer_tap.code); - } else { - dprint("KEYMAP_TAP_KEY: No tap: Off on release\n"); - layer_off(action.layer_tap.val); - } - } - break; - } - break; -# endif -#endif - /* Extentions */ -#ifndef NO_ACTION_MACRO - case ACT_MACRO: - action_macro_play(action_get_macro(record, action.func.id, action.func.opt)); - break; -#endif -#ifdef SWAP_HANDS_ENABLE - case ACT_SWAP_HANDS: - switch (action.swap.code) { - case OP_SH_TOGGLE: - if (event.pressed) { - swap_hands = !swap_hands; - } - break; - case OP_SH_ON_OFF: - swap_hands = event.pressed; - break; - case OP_SH_OFF_ON: - swap_hands = !event.pressed; - break; - case OP_SH_ON: - if (!event.pressed) { - swap_hands = true; - } - break; - case OP_SH_OFF: - if (!event.pressed) { - swap_hands = false; - } - break; -# ifndef NO_ACTION_ONESHOT - case OP_SH_ONESHOT: - if (event.pressed) { - set_oneshot_swaphands(); - } else { - release_oneshot_swaphands(); - } - break; -# endif - -# ifndef NO_ACTION_TAPPING - case OP_SH_TAP_TOGGLE: - /* tap toggle */ - - if (event.pressed) { - if (swap_held) { - swap_held = false; - } else { - swap_hands = !swap_hands; - } - } else { - if (tap_count < TAPPING_TOGGLE) { - swap_hands = !swap_hands; - } - } - break; - default: - /* tap key */ - if (tap_count > 0) { - if (swap_held) { - swap_hands = !swap_hands; // undo hold set up in _tap_hint - swap_held = false; - } - if (event.pressed) { - register_code(action.swap.code); - } else { - wait_ms(TAP_CODE_DELAY); - unregister_code(action.swap.code); - *record = (keyrecord_t){}; // hack: reset tap mode - } - } else { - if (swap_held && !event.pressed) { - swap_hands = !swap_hands; // undo hold set up in _tap_hint - swap_held = false; - } - } -# endif - } -#endif -#ifndef NO_ACTION_FUNCTION - case ACT_FUNCTION: - action_function(record, action.func.id, action.func.opt); - break; -#endif - default: - break; - } - -#ifndef NO_ACTION_LAYER - // if this event is a layer action, update the leds - switch (action.kind.id) { - case ACT_LAYER: - case ACT_LAYER_MODS: -# ifndef NO_ACTION_TAPPING - case ACT_LAYER_TAP: - case ACT_LAYER_TAP_EXT: -# endif - led_set(host_keyboard_leds()); - break; - default: - break; - } -#endif - -#ifndef NO_ACTION_TAPPING -# if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) - if (!is_tap_action(action)) { - retro_tapping_counter = 0; - } else { - if (event.pressed) { - if (tap_count > 0) { - retro_tapping_counter = 0; - } - } else { - if (tap_count > 0) { - retro_tapping_counter = 0; - } else { - if ( -# ifdef RETRO_TAPPING_PER_KEY - get_retro_tapping(get_event_keycode(record->event, false), record) && -# endif - retro_tapping_counter == 2) { - tap_code(action.layer_tap.code); - } - retro_tapping_counter = 0; - } - } - } -# endif -#endif - -#ifdef SWAP_HANDS_ENABLE -# ifndef NO_ACTION_ONESHOT - if (event.pressed && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)) { - use_oneshot_swaphands(); - } -# endif -#endif - -#ifndef NO_ACTION_ONESHOT - /* Because we switch layers after a oneshot event, we need to release the - * key before we leave the layer or no key up event will be generated. - */ - if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED)) { - record->event.pressed = false; - layer_on(get_oneshot_layer()); - process_record(record); - layer_off(get_oneshot_layer()); - } -#endif -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void register_code(uint8_t code) { - if (code == KC_NO) { - return; - } -#ifdef LOCKING_SUPPORT_ENABLE - else if (KC_LOCKING_CAPS == code) { -# ifdef LOCKING_RESYNC_ENABLE - // Resync: ignore if caps lock already is on - if (host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK)) return; -# endif - add_key(KC_CAPSLOCK); - send_keyboard_report(); - wait_ms(100); - del_key(KC_CAPSLOCK); - send_keyboard_report(); - } - - else if (KC_LOCKING_NUM == code) { -# ifdef LOCKING_RESYNC_ENABLE - if (host_keyboard_leds() & (1 << USB_LED_NUM_LOCK)) return; -# endif - add_key(KC_NUMLOCK); - send_keyboard_report(); - wait_ms(100); - del_key(KC_NUMLOCK); - send_keyboard_report(); - } - - else if (KC_LOCKING_SCROLL == code) { -# ifdef LOCKING_RESYNC_ENABLE - if (host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK)) return; -# endif - add_key(KC_SCROLLLOCK); - send_keyboard_report(); - wait_ms(100); - del_key(KC_SCROLLLOCK); - send_keyboard_report(); - } -#endif - - else if IS_KEY (code) { - // TODO: should push command_proc out of this block? - if (command_proc(code)) return; - -#ifndef NO_ACTION_ONESHOT -/* TODO: remove - if (oneshot_state.mods && !oneshot_state.disabled) { - uint8_t tmp_mods = get_mods(); - add_mods(oneshot_state.mods); - - add_key(code); - send_keyboard_report(); - - set_mods(tmp_mods); - send_keyboard_report(); - oneshot_cancel(); - } else -*/ -#endif - { - // Force a new key press if the key is already pressed - // without this, keys with the same keycode, but different - // modifiers will be reported incorrectly, see issue #1708 - if (is_key_pressed(keyboard_report, code)) { - del_key(code); - send_keyboard_report(); - } - add_key(code); - send_keyboard_report(); - } - } else if IS_MOD (code) { - add_mods(MOD_BIT(code)); - send_keyboard_report(); - } -#ifdef EXTRAKEY_ENABLE - else if IS_SYSTEM (code) { - host_system_send(KEYCODE2SYSTEM(code)); - } else if IS_CONSUMER (code) { - host_consumer_send(KEYCODE2CONSUMER(code)); - } -#endif -#ifdef MOUSEKEY_ENABLE - else if IS_MOUSEKEY (code) { - mousekey_on(code); - mousekey_send(); - } -#endif -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void unregister_code(uint8_t code) { - if (code == KC_NO) { - return; - } -#ifdef LOCKING_SUPPORT_ENABLE - else if (KC_LOCKING_CAPS == code) { -# ifdef LOCKING_RESYNC_ENABLE - // Resync: ignore if caps lock already is off - if (!(host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK))) return; -# endif - add_key(KC_CAPSLOCK); - send_keyboard_report(); - del_key(KC_CAPSLOCK); - send_keyboard_report(); - } - - else if (KC_LOCKING_NUM == code) { -# ifdef LOCKING_RESYNC_ENABLE - if (!(host_keyboard_leds() & (1 << USB_LED_NUM_LOCK))) return; -# endif - add_key(KC_NUMLOCK); - send_keyboard_report(); - del_key(KC_NUMLOCK); - send_keyboard_report(); - } - - else if (KC_LOCKING_SCROLL == code) { -# ifdef LOCKING_RESYNC_ENABLE - if (!(host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK))) return; -# endif - add_key(KC_SCROLLLOCK); - send_keyboard_report(); - del_key(KC_SCROLLLOCK); - send_keyboard_report(); - } -#endif - - else if IS_KEY (code) { - del_key(code); - send_keyboard_report(); - } else if IS_MOD (code) { - del_mods(MOD_BIT(code)); - send_keyboard_report(); - } else if IS_SYSTEM (code) { - host_system_send(0); - } else if IS_CONSUMER (code) { - host_consumer_send(0); - } -#ifdef MOUSEKEY_ENABLE - else if IS_MOUSEKEY (code) { - mousekey_off(code); - mousekey_send(); - } -#endif -} - -/** \brief Tap a keycode with a delay. - * - * \param code The basic keycode to tap. - * \param delay The amount of time in milliseconds to leave the keycode registered, before unregistering it. - */ -void tap_code_delay(uint8_t code, uint16_t delay) { - register_code(code); - for (uint16_t i = delay; i > 0; i--) { - wait_ms(1); - } - unregister_code(code); -} - -/** \brief Tap a keycode with the default delay. - * - * \param code The basic keycode to tap. If `code` is `KC_CAPS`, the delay will be `TAP_HOLD_CAPS_DELAY`, otherwise `TAP_CODE_DELAY`, if defined. - */ -void tap_code(uint8_t code) { tap_code_delay(code, code == KC_CAPS ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY); } - -/** \brief Adds the given physically pressed modifiers and sends a keyboard report immediately. - * - * \param mods A bitfield of modifiers to register. - */ -void register_mods(uint8_t mods) { - if (mods) { - add_mods(mods); - send_keyboard_report(); - } -} - -/** \brief Removes the given physically pressed modifiers and sends a keyboard report immediately. - * - * \param mods A bitfield of modifiers to unregister. - */ -void unregister_mods(uint8_t mods) { - if (mods) { - del_mods(mods); - send_keyboard_report(); - } -} - -/** \brief Adds the given weak modifiers and sends a keyboard report immediately. - * - * \param mods A bitfield of modifiers to register. - */ -void register_weak_mods(uint8_t mods) { - if (mods) { - add_weak_mods(mods); - send_keyboard_report(); - } -} - -/** \brief Removes the given weak modifiers and sends a keyboard report immediately. - * - * \param mods A bitfield of modifiers to unregister. - */ -void unregister_weak_mods(uint8_t mods) { - if (mods) { - del_weak_mods(mods); - send_keyboard_report(); - } -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void clear_keyboard(void) { - clear_mods(); - clear_keyboard_but_mods(); -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void clear_keyboard_but_mods(void) { - clear_keys(); - clear_keyboard_but_mods_and_keys(); -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void clear_keyboard_but_mods_and_keys() { -#ifdef EXTRAKEY_ENABLE - host_system_send(0); - host_consumer_send(0); -#endif - clear_weak_mods(); - clear_macro_mods(); - send_keyboard_report(); -#ifdef MOUSEKEY_ENABLE - mousekey_clear(); - mousekey_send(); -#endif -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -bool is_tap_key(keypos_t key) { - action_t action = layer_switch_get_action(key); - return is_tap_action(action); -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -bool is_tap_record(keyrecord_t *record) { -#ifdef COMBO_ENABLE - action_t action; - if (record->keycode) { - action = action_for_keycode(record->keycode); - } else { - action = layer_switch_get_action(record->event.key); - } -#else - action_t action = layer_switch_get_action(record->event.key); -#endif - return is_tap_action(action); -} - -/** \brief Utilities for actions. (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -bool is_tap_action(action_t action) { - switch (action.kind.id) { - case ACT_LMODS_TAP: - case ACT_RMODS_TAP: - case ACT_LAYER_TAP: - case ACT_LAYER_TAP_EXT: - switch (action.layer_tap.code) { - case KC_NO ... KC_RGUI: - case OP_TAP_TOGGLE: - case OP_ONESHOT: - return true; - } - return false; - case ACT_SWAP_HANDS: - switch (action.swap.code) { - case KC_NO ... KC_RGUI: - case OP_SH_TAP_TOGGLE: - return true; - } - return false; - case ACT_MACRO: - case ACT_FUNCTION: - if (action.func.opt & FUNC_TAP) { - return true; - } - return false; - } - return false; -} - -/** \brief Debug print (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); } -/** \brief Debug print (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void debug_record(keyrecord_t record) { - debug_event(record.event); -#ifndef NO_ACTION_TAPPING - dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' ')); -#endif -} - -/** \brief Debug print (FIXME: Needs better description) - * - * FIXME: Needs documentation. - */ -void debug_action(action_t action) { - switch (action.kind.id) { - case ACT_LMODS: - dprint("ACT_LMODS"); - break; - case ACT_RMODS: - dprint("ACT_RMODS"); - break; - case ACT_LMODS_TAP: - dprint("ACT_LMODS_TAP"); - break; - case ACT_RMODS_TAP: - dprint("ACT_RMODS_TAP"); - break; - case ACT_USAGE: - dprint("ACT_USAGE"); - break; - case ACT_MOUSEKEY: - dprint("ACT_MOUSEKEY"); - break; - case ACT_LAYER: - dprint("ACT_LAYER"); - break; - case ACT_LAYER_MODS: - dprint("ACT_LAYER_MODS"); - break; - case ACT_LAYER_TAP: - dprint("ACT_LAYER_TAP"); - break; - case ACT_LAYER_TAP_EXT: - dprint("ACT_LAYER_TAP_EXT"); - break; - case ACT_MACRO: - dprint("ACT_MACRO"); - break; - case ACT_FUNCTION: - dprint("ACT_FUNCTION"); - break; - case ACT_SWAP_HANDS: - dprint("ACT_SWAP_HANDS"); - break; - default: - dprint("UNKNOWN"); - break; - } - dprintf("[%X:%02X]", action.kind.param >> 8, action.kind.param & 0xff); -} diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h deleted file mode 100644 index 3d357b33b8..0000000000 --- a/tmk_core/common/action.h +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2012,2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include -#include "keyboard.h" -#include "keycode.h" -#include "action_code.h" -#include "action_macro.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Disable macro and function features when LTO is enabled, since they break */ -#ifdef LTO_ENABLE -# ifndef NO_ACTION_MACRO -# define NO_ACTION_MACRO -# endif -# ifndef NO_ACTION_FUNCTION -# define NO_ACTION_FUNCTION -# endif -#endif - -/* tapping count and state */ -typedef struct { - bool interrupted : 1; - bool reserved2 : 1; - bool reserved1 : 1; - bool reserved0 : 1; - uint8_t count : 4; -} tap_t; - -/* Key event container for recording */ -typedef struct { - keyevent_t event; -#ifndef NO_ACTION_TAPPING - tap_t tap; -#endif -#ifdef COMBO_ENABLE - uint16_t keycode; -#endif -} keyrecord_t; - -/* Execute action per keyevent */ -void action_exec(keyevent_t event); - -/* action for key */ -action_t action_for_key(uint8_t layer, keypos_t key); -action_t action_for_keycode(uint16_t keycode); - -/* macro */ -const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt); - -/* user defined special function */ -void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); - -/* keyboard-specific key event (pre)processing */ -bool process_record_quantum(keyrecord_t *record); - -/* Utilities for actions. */ -#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) -extern bool disable_action_cache; -#endif - -/* Code for handling one-handed key modifiers. */ -#ifdef SWAP_HANDS_ENABLE -extern bool swap_hands; -extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS]; -# if (MATRIX_COLS <= 8) -typedef uint8_t swap_state_row_t; -# elif (MATRIX_COLS <= 16) -typedef uint16_t swap_state_row_t; -# elif (MATRIX_COLS <= 32) -typedef uint32_t swap_state_row_t; -# else -# error "MATRIX_COLS: invalid value" -# endif - -void process_hand_swap(keyevent_t *record); -#endif - -void process_record_nocache(keyrecord_t *record); -void process_record(keyrecord_t *record); -void process_record_handler(keyrecord_t *record); -void post_process_record_quantum(keyrecord_t *record); -void process_action(keyrecord_t *record, action_t action); -void register_code(uint8_t code); -void unregister_code(uint8_t code); -void tap_code(uint8_t code); -void tap_code_delay(uint8_t code, uint16_t delay); -void register_mods(uint8_t mods); -void unregister_mods(uint8_t mods); -void register_weak_mods(uint8_t mods); -void unregister_weak_mods(uint8_t mods); -// void set_mods(uint8_t mods); -void clear_keyboard(void); -void clear_keyboard_but_mods(void); -void clear_keyboard_but_mods_and_keys(void); -void layer_switch(uint8_t new_layer); -bool is_tap_key(keypos_t key); -bool is_tap_record(keyrecord_t *record); -bool is_tap_action(action_t action); - -#ifndef NO_ACTION_TAPPING -void process_record_tap_hint(keyrecord_t *record); -#endif - -/* debug */ -void debug_event(keyevent_t event); -void debug_record(keyrecord_t record); -void debug_action(action_t action); - -#ifdef __cplusplus -} -#endif diff --git a/tmk_core/common/action_code.h b/tmk_core/common/action_code.h deleted file mode 100644 index eb18c36ae8..0000000000 --- a/tmk_core/common/action_code.h +++ /dev/null @@ -1,308 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 - -/** \brief Action codes - * - * 16bit code: action_kind(4bit) + action_parameter(12bit) - * - * Key Actions(00xx) - * ----------------- - * ACT_MODS(000r): - * 000r|0000|0000 0000 No action code - * 000r|0000|0000 0001 Transparent code - * 000r|0000| keycode Key - * 000r|mods|0000 0000 Modifiers - * 000r|mods| keycode Modifiers+Key(Modified key) - * r: Left/Right flag(Left:0, Right:1) - * - * ACT_MODS_TAP(001r): - * 001r|mods|0000 0000 Modifiers with OneShot - * 001r|mods|0000 0001 Modifiers with tap toggle - * 001r|mods|0000 00xx (reserved) - * 001r|mods| keycode Modifiers with Tap Key(Dual role) - * - * Other Keys(01xx) - * ---------------- - * ACT_USAGE(0100): TODO: Not needed? - * 0100|00| usage(10) System control(0x80) - General Desktop page(0x01) - * 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C) - * 0100|10| usage(10) (reserved) - * 0100|11| usage(10) (reserved) - * - * ACT_MOUSEKEY(0101): TODO: Merge these two actions to conserve space? - * 0101|xxxx| keycode Mouse key - * - * ACT_SWAP_HANDS(0110): - * 0110|xxxx| keycode Swap hands (keycode on tap, or options) - * - * 0111|xxxx xxxx xxxx (reserved) - * - * Layer Actions(10xx) - * ------------------- - * ACT_LAYER(1000): - * 1000|oo00|pppE BBBB Default Layer Bitwise operation - * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET) - * ppp: 4-bit chunk part(0-7) - * EBBBB: bits and extra bit - * 1000|ooee|pppE BBBB Layer Bitwise Operation - * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET) - * ppp: 4-bit chunk part(0-7) - * EBBBB: bits and extra bit - * ee: on event(01:press, 10:release, 11:both) - * - * ACT_LAYER_MODS(1001): - * 1001|LLLL| mods Layer with modifiers held - * - * ACT_LAYER_TAP(101x): - * 101E|LLLL| keycode On/Off with tap key (0x00-DF)[TAP] - * 101E|LLLL|1110 mods On/Off with modifiers (0xE0-EF)[NOT TAP] - * 101E|LLLL|1111 0000 Invert with tap toggle (0xF0) [TAP] - * 101E|LLLL|1111 0001 On/Off (0xF1) [NOT TAP] - * 101E|LLLL|1111 0010 Off/On (0xF2) [NOT TAP] - * 101E|LLLL|1111 0011 Set/Clear (0xF3) [NOT TAP] - * 101E|LLLL|1111 0100 One Shot Layer (0xF4) [TAP] - * 101E|LLLL|1111 xxxx Reserved (0xF5-FF) - * ELLLL: layer 0-31(E: extra bit for layer 16-31) - * - * Extensions(11xx) - * ---------------- - * ACT_MACRO(1100): - * 1100|opt | id(8) Macro play? - * 1100|1111| id(8) Macro record? - * - * 1101|xxxx xxxx xxxx (reserved) - * 1110|xxxx xxxx xxxx (reserved) - * - * ACT_FUNCTION(1111): - * 1111| address(12) Function? - * 1111|opt | id(8) Function? - */ -enum action_kind_id { - /* Key Actions */ - ACT_MODS = 0b0000, - ACT_LMODS = 0b0000, - ACT_RMODS = 0b0001, - ACT_MODS_TAP = 0b0010, - ACT_LMODS_TAP = 0b0010, - ACT_RMODS_TAP = 0b0011, - /* Other Keys */ - ACT_USAGE = 0b0100, - ACT_MOUSEKEY = 0b0101, - /* One-hand Support */ - ACT_SWAP_HANDS = 0b0110, - /* Layer Actions */ - ACT_LAYER = 0b1000, - ACT_LAYER_MODS = 0b1001, - ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */ - ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */ - /* Extensions */ - ACT_MACRO = 0b1100, - ACT_FUNCTION = 0b1111 -}; - -/** \brief Action Code Struct - * - * NOTE: - * In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15). - * AVR looks like a little endian in avr-gcc. - * Not portable across compiler/endianness? - * - * Byte order and bit order of 0x1234: - * Big endian: Little endian: - * -------------------- -------------------- - * FEDC BA98 7654 3210 0123 4567 89AB CDEF - * 0001 0010 0011 0100 0010 1100 0100 1000 - * 0x12 0x34 0x34 0x12 - */ -typedef union { - uint16_t code; - struct action_kind { - uint16_t param : 12; - uint8_t id : 4; - } kind; - struct action_key { - uint8_t code : 8; - uint8_t mods : 4; - uint8_t kind : 4; - } key; - struct action_layer_bitop { - uint8_t bits : 4; - uint8_t xbit : 1; - uint8_t part : 3; - uint8_t on : 2; - uint8_t op : 2; - uint8_t kind : 4; - } layer_bitop; - struct action_layer_mods { - uint8_t mods : 8; - uint8_t layer : 4; - uint8_t kind : 4; - } layer_mods; - struct action_layer_tap { - uint8_t code : 8; - uint8_t val : 5; - uint8_t kind : 3; - } layer_tap; - struct action_usage { - uint16_t code : 10; - uint8_t page : 2; - uint8_t kind : 4; - } usage; - struct action_function { - uint8_t id : 8; - uint8_t opt : 4; - uint8_t kind : 4; - } func; - struct action_swap { - uint8_t code : 8; - uint8_t opt : 4; - uint8_t kind : 4; - } swap; -} action_t; - -/* action utility */ -#define ACTION_NO 0 -#define ACTION_TRANSPARENT 1 -#define ACTION(kind, param) ((kind) << 12 | (param)) - -/** \brief Key Actions - * - * Mod bits: 43210 - * bit 0 ||||+- Control - * bit 1 |||+-- Shift - * bit 2 ||+--- Alt - * bit 3 |+---- Gui - * bit 4 +----- LR flag(Left:0, Right:1) - */ -enum mods_bit { - MOD_LCTL = 0x01, - MOD_LSFT = 0x02, - MOD_LALT = 0x04, - MOD_LGUI = 0x08, - MOD_RCTL = 0x11, - MOD_RSFT = 0x12, - MOD_RALT = 0x14, - MOD_RGUI = 0x18, -}; -enum mods_codes { - MODS_ONESHOT = 0x00, - MODS_TAP_TOGGLE = 0x01, -}; -#define ACTION_KEY(key) ACTION(ACT_MODS, (key)) -#define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f) << 8 | 0) -#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f) << 8 | (key)) -#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | (key)) -#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | MODS_ONESHOT) -#define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | MODS_TAP_TOGGLE) - -/** \brief Other Keys - */ -enum usage_pages { PAGE_SYSTEM, PAGE_CONSUMER }; -#define ACTION_USAGE_SYSTEM(id) ACTION(ACT_USAGE, PAGE_SYSTEM << 10 | (id)) -#define ACTION_USAGE_CONSUMER(id) ACTION(ACT_USAGE, PAGE_CONSUMER << 10 | (id)) -#define ACTION_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key) - -/** \brief Layer Actions - */ -enum layer_param_on { - ON_PRESS = 1, - ON_RELEASE = 2, - ON_BOTH = 3, -}; - -/** \brief Layer Actions - */ -enum layer_param_bit_op { - OP_BIT_AND = 0, - OP_BIT_OR = 1, - OP_BIT_XOR = 2, - OP_BIT_SET = 3, -}; - -/** \brief Layer Actions - */ -enum layer_param_tap_op { - OP_TAP_TOGGLE = 0xF0, - OP_ON_OFF, - OP_OFF_ON, - OP_SET_CLEAR, - OP_ONESHOT, -}; -#define ACTION_LAYER_BITOP(op, part, bits, on) ACTION(ACT_LAYER, (op) << 10 | (on) << 8 | (part) << 5 | ((bits)&0x1f)) -#define ACTION_LAYER_TAP(layer, key) ACTION(ACT_LAYER_TAP, (layer) << 8 | (key)) -/* Default Layer */ -#define ACTION_DEFAULT_LAYER_SET(layer) ACTION_DEFAULT_LAYER_BIT_SET((layer) / 4, 1 << ((layer) % 4)) -/* Layer Operation */ -#define ACTION_LAYER_CLEAR(on) ACTION_LAYER_BIT_AND(0, 0, (on)) -#define ACTION_LAYER_MOMENTARY(layer) ACTION_LAYER_ON_OFF(layer) -#define ACTION_LAYER_TOGGLE(layer) ACTION_LAYER_INVERT(layer, ON_RELEASE) -#define ACTION_LAYER_INVERT(layer, on) ACTION_LAYER_BIT_XOR((layer) / 4, 1 << ((layer) % 4), (on)) -#define ACTION_LAYER_ON(layer, on) ACTION_LAYER_BIT_OR((layer) / 4, 1 << ((layer) % 4), (on)) -#define ACTION_LAYER_OFF(layer, on) ACTION_LAYER_BIT_AND((layer) / 4, ~(1 << ((layer) % 4)), (on)) -#define ACTION_LAYER_SET(layer, on) ACTION_LAYER_BIT_SET((layer) / 4, 1 << ((layer) % 4), (on)) -#define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF) -#define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON) -#define ACTION_LAYER_SET_CLEAR(layer) ACTION_LAYER_TAP((layer), OP_SET_CLEAR) -#define ACTION_LAYER_ONESHOT(layer) ACTION_LAYER_TAP((layer), OP_ONESHOT) -#define ACTION_LAYER_MODS(layer, mods) ACTION(ACT_LAYER_MODS, (layer) << 8 | (mods)) -/* With Tapping */ -#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key)) -#define ACTION_LAYER_TAP_TOGGLE(layer) ACTION_LAYER_TAP((layer), OP_TAP_TOGGLE) -/* Bitwise Operation */ -#define ACTION_LAYER_BIT_AND(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), (on)) -#define ACTION_LAYER_BIT_OR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), (on)) -#define ACTION_LAYER_BIT_XOR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), (on)) -#define ACTION_LAYER_BIT_SET(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), (on)) -/* Default Layer Bitwise Operation */ -#define ACTION_DEFAULT_LAYER_BIT_AND(part, bits) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), 0) -#define ACTION_DEFAULT_LAYER_BIT_OR(part, bits) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), 0) -#define ACTION_DEFAULT_LAYER_BIT_XOR(part, bits) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), 0) -#define ACTION_DEFAULT_LAYER_BIT_SET(part, bits) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), 0) - -/* Macro */ -#define ACTION_MACRO(id) ACTION(ACT_MACRO, (id)) -#define ACTION_MACRO_TAP(id) ACTION(ACT_MACRO, FUNC_TAP << 8 | (id)) -#define ACTION_MACRO_OPT(id, opt) ACTION(ACT_MACRO, (opt) << 8 | (id)) -/* Function */ -enum function_opts { - FUNC_TAP = 0x8, /* indciates function is tappable */ -}; -#define ACTION_FUNCTION(id) ACTION(ACT_FUNCTION, (id)) -#define ACTION_FUNCTION_TAP(id) ACTION(ACT_FUNCTION, FUNC_TAP << 8 | (id)) -#define ACTION_FUNCTION_OPT(id, opt) ACTION(ACT_FUNCTION, (opt) << 8 | (id)) -/* OneHand Support */ -enum swap_hands_param_tap_op { - OP_SH_TOGGLE = 0xF0, - OP_SH_TAP_TOGGLE, - OP_SH_ON_OFF, - OP_SH_OFF_ON, - OP_SH_OFF, - OP_SH_ON, - OP_SH_ONESHOT, -}; - -#define ACTION_SWAP_HANDS() ACTION_SWAP_HANDS_ON_OFF() -#define ACTION_SWAP_HANDS_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TOGGLE) -#define ACTION_SWAP_HANDS_TAP_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TAP_TOGGLE) -#define ACTION_SWAP_HANDS_ONESHOT() ACTION(ACT_SWAP_HANDS, OP_SH_ONESHOT) -#define ACTION_SWAP_HANDS_TAP_KEY(key) ACTION(ACT_SWAP_HANDS, key) -#define ACTION_SWAP_HANDS_ON_OFF() ACTION(ACT_SWAP_HANDS, OP_SH_ON_OFF) -#define ACTION_SWAP_HANDS_OFF_ON() ACTION(ACT_SWAP_HANDS, OP_SH_OFF_ON) -#define ACTION_SWAP_HANDS_ON() ACTION(ACT_SWAP_HANDS, OP_SH_ON) -#define ACTION_SWAP_HANDS_OFF() ACTION(ACT_SWAP_HANDS, OP_SH_OFF) diff --git a/tmk_core/common/action_layer.c b/tmk_core/common/action_layer.c deleted file mode 100644 index ed1a4bd20d..0000000000 --- a/tmk_core/common/action_layer.c +++ /dev/null @@ -1,279 +0,0 @@ -#include -#include "keyboard.h" -#include "action.h" -#include "util.h" -#include "action_layer.h" - -#ifdef DEBUG_ACTION -# include "debug.h" -#else -# include "nodebug.h" -#endif - -/** \brief Default Layer State - */ -layer_state_t default_layer_state = 0; - -/** \brief Default Layer State Set At user Level - * - * Run user code on default layer state change - */ -__attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state) { return state; } - -/** \brief Default Layer State Set At Keyboard Level - * - * Run keyboard code on default layer state change - */ -__attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state) { return default_layer_state_set_user(state); } - -/** \brief Default Layer State Set - * - * Static function to set the default layer state, prints debug info and clears keys - */ -static void default_layer_state_set(layer_state_t state) { - state = default_layer_state_set_kb(state); - debug("default_layer_state: "); - default_layer_debug(); - debug(" to "); - default_layer_state = state; - default_layer_debug(); - debug("\n"); -#ifdef STRICT_LAYER_RELEASE - clear_keyboard_but_mods(); // To avoid stuck keys -#else - clear_keyboard_but_mods_and_keys(); // Don't reset held keys -#endif -} - -/** \brief Default Layer Print - * - * Print out the hex value of the 32-bit default layer state, as well as the value of the highest bit. - */ -void default_layer_debug(void) { dprintf("%08lX(%u)", default_layer_state, get_highest_layer(default_layer_state)); } - -/** \brief Default Layer Set - * - * Sets the default layer state. - */ -void default_layer_set(layer_state_t state) { default_layer_state_set(state); } - -#ifndef NO_ACTION_LAYER -/** \brief Default Layer Or - * - * Turns on the default layer based on matching bits between specifed layer and existing layer state - */ -void default_layer_or(layer_state_t state) { default_layer_state_set(default_layer_state | state); } -/** \brief Default Layer And - * - * Turns on default layer based on matching enabled bits between specifed layer and existing layer state - */ -void default_layer_and(layer_state_t state) { default_layer_state_set(default_layer_state & state); } -/** \brief Default Layer Xor - * - * Turns on default layer based on non-matching bits between specifed layer and existing layer state - */ -void default_layer_xor(layer_state_t state) { default_layer_state_set(default_layer_state ^ state); } -#endif - -#ifndef NO_ACTION_LAYER -/** \brief Keymap Layer State - */ -layer_state_t layer_state = 0; - -/** \brief Layer state set user - * - * Runs user code on layer state change - */ -__attribute__((weak)) layer_state_t layer_state_set_user(layer_state_t state) { return state; } - -/** \brief Layer state set keyboard - * - * Runs keyboard code on layer state change - */ -__attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) { return layer_state_set_user(state); } - -/** \brief Layer state set - * - * Sets the layer to match the specifed state (a bitmask) - */ -void layer_state_set(layer_state_t state) { - state = layer_state_set_kb(state); - dprint("layer_state: "); - layer_debug(); - dprint(" to "); - layer_state = state; - layer_debug(); - dprintln(); -# ifdef STRICT_LAYER_RELEASE - clear_keyboard_but_mods(); // To avoid stuck keys -# else - clear_keyboard_but_mods_and_keys(); // Don't reset held keys -# endif -} - -/** \brief Layer clear - * - * Turn off all layers - */ -void layer_clear(void) { layer_state_set(0); } - -/** \brief Layer state is - * - * Return whether the given state is on (it might still be shadowed by a higher state, though) - */ -bool layer_state_is(uint8_t layer) { return layer_state_cmp(layer_state, layer); } - -/** \brief Layer state compare - * - * Used for comparing layers {mostly used for unit testing} - */ -bool layer_state_cmp(layer_state_t cmp_layer_state, uint8_t layer) { - if (!cmp_layer_state) { - return layer == 0; - } - return (cmp_layer_state & ((layer_state_t)1 << layer)) != 0; -} - -/** \brief Layer move - * - * Turns on the given layer and turn off all other layers - */ -void layer_move(uint8_t layer) { layer_state_set((layer_state_t)1 << layer); } - -/** \brief Layer on - * - * Turns on given layer - */ -void layer_on(uint8_t layer) { layer_state_set(layer_state | ((layer_state_t)1 << layer)); } - -/** \brief Layer off - * - * Turns off given layer - */ -void layer_off(uint8_t layer) { layer_state_set(layer_state & ~((layer_state_t)1 << layer)); } - -/** \brief Layer invert - * - * Toggle the given layer (set it if it's unset, or unset it if it's set) - */ -void layer_invert(uint8_t layer) { layer_state_set(layer_state ^ ((layer_state_t)1 << layer)); } - -/** \brief Layer or - * - * Turns on layers based on matching bits between specifed layer and existing layer state - */ -void layer_or(layer_state_t state) { layer_state_set(layer_state | state); } -/** \brief Layer and - * - * Turns on layers based on matching enabled bits between specifed layer and existing layer state - */ -void layer_and(layer_state_t state) { layer_state_set(layer_state & state); } -/** \brief Layer xor - * - * Turns on layers based on non-matching bits between specifed layer and existing layer state - */ -void layer_xor(layer_state_t state) { layer_state_set(layer_state ^ state); } - -/** \brief Layer debug printing - * - * Print out the hex value of the 32-bit layer state, as well as the value of the highest bit. - */ -void layer_debug(void) { dprintf("%08lX(%u)", layer_state, get_highest_layer(layer_state)); } -#endif - -#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) -/** \brief source layer cache - */ - -uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}}; - -/** \brief update source layers cache - * - * Updates the cached keys when changing layers - */ -void update_source_layers_cache(keypos_t key, uint8_t layer) { - const uint8_t key_number = key.col + (key.row * MATRIX_COLS); - const uint8_t storage_row = key_number / 8; - const uint8_t storage_bit = key_number % 8; - - for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { - source_layers_cache[storage_row][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ source_layers_cache[storage_row][bit_number]) & (1U << storage_bit); - } -} - -/** \brief read source layers cache - * - * reads the cached keys stored when the layer was changed - */ -uint8_t read_source_layers_cache(keypos_t key) { - const uint8_t key_number = key.col + (key.row * MATRIX_COLS); - const uint8_t storage_row = key_number / 8; - const uint8_t storage_bit = key_number % 8; - uint8_t layer = 0; - - for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { - layer |= ((source_layers_cache[storage_row][bit_number] & (1U << storage_bit)) != 0) << bit_number; - } - - return layer; -} -#endif - -/** \brief Store or get action (FIXME: Needs better summary) - * - * Make sure the action triggered when the key is released is the same - * one as the one triggered on press. It's important for the mod keys - * when the layer is switched after the down event but before the up - * event as they may get stuck otherwise. - */ -action_t store_or_get_action(bool pressed, keypos_t key) { -#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) - if (disable_action_cache) { - return layer_switch_get_action(key); - } - - uint8_t layer; - - if (pressed) { - layer = layer_switch_get_layer(key); - update_source_layers_cache(key, layer); - } else { - layer = read_source_layers_cache(key); - } - return action_for_key(layer, key); -#else - return layer_switch_get_action(key); -#endif -} - -/** \brief Layer switch get layer - * - * Gets the layer based on key info - */ -uint8_t layer_switch_get_layer(keypos_t key) { -#ifndef NO_ACTION_LAYER - action_t action; - action.code = ACTION_TRANSPARENT; - - layer_state_t layers = layer_state | default_layer_state; - /* check top layer first */ - for (int8_t i = MAX_LAYER - 1; i >= 0; i--) { - if (layers & ((layer_state_t)1 << i)) { - action = action_for_key(i, key); - if (action.code != ACTION_TRANSPARENT) { - return i; - } - } - } - /* fall back to layer 0 */ - return 0; -#else - return get_highest_layer(default_layer_state); -#endif -} - -/** \brief Layer switch get layer - * - * Gets action code based on key position - */ -action_t layer_switch_get_action(keypos_t key) { return action_for_key(layer_switch_get_layer(key), key); } diff --git a/tmk_core/common/action_layer.h b/tmk_core/common/action_layer.h deleted file mode 100644 index b87d096eed..0000000000 --- a/tmk_core/common/action_layer.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include "keyboard.h" -#include "action.h" - -#ifdef DYNAMIC_KEYMAP_ENABLE -# ifndef DYNAMIC_KEYMAP_LAYER_COUNT -# define DYNAMIC_KEYMAP_LAYER_COUNT 4 -# endif -# if DYNAMIC_KEYMAP_LAYER_COUNT <= 8 -# ifndef LAYER_STATE_8BIT -# define LAYER_STATE_8BIT -# endif -# elif DYNAMIC_KEYMAP_LAYER_COUNT <= 16 -# ifndef LAYER_STATE_16BIT -# define LAYER_STATE_16BIT -# endif -# else -# ifndef LAYER_STATE_32BIT -# define LAYER_STATE_32BIT -# endif -# endif -#endif - -#if !defined(LAYER_STATE_8BIT) && !defined(LAYER_STATE_16BIT) && !defined(LAYER_STATE_32BIT) -# define LAYER_STATE_32BIT -#endif - -#if defined(LAYER_STATE_8BIT) -typedef uint8_t layer_state_t; -# define MAX_LAYER_BITS 3 -# ifndef MAX_LAYER -# define MAX_LAYER 8 -# endif -# define get_highest_layer(state) biton(state) -#elif defined(LAYER_STATE_16BIT) -typedef uint16_t layer_state_t; -# define MAX_LAYER_BITS 4 -# ifndef MAX_LAYER -# define MAX_LAYER 16 -# endif -# define get_highest_layer(state) biton16(state) -#elif defined(LAYER_STATE_32BIT) -typedef uint32_t layer_state_t; -# define MAX_LAYER_BITS 5 -# ifndef MAX_LAYER -# define MAX_LAYER 32 -# endif -# define get_highest_layer(state) biton32(state) -#else -# error Layer Mask size not specified. HOW?! -#endif - -/* - * Default Layer - */ -extern layer_state_t default_layer_state; -void default_layer_debug(void); -void default_layer_set(layer_state_t state); - -__attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state); -__attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state); - -#ifndef NO_ACTION_LAYER -/* bitwise operation */ -void default_layer_or(layer_state_t state); -void default_layer_and(layer_state_t state); -void default_layer_xor(layer_state_t state); -#else -# define default_layer_or(state) -# define default_layer_and(state) -# define default_layer_xor(state) -#endif - -/* - * Keymap Layer - */ -#ifndef NO_ACTION_LAYER -extern layer_state_t layer_state; - -void layer_state_set(layer_state_t state); -bool layer_state_is(uint8_t layer); -bool layer_state_cmp(layer_state_t layer1, uint8_t layer2); - -void layer_debug(void); -void layer_clear(void); -void layer_move(uint8_t layer); -void layer_on(uint8_t layer); -void layer_off(uint8_t layer); -void layer_invert(uint8_t layer); -/* bitwise operation */ -void layer_or(layer_state_t state); -void layer_and(layer_state_t state); -void layer_xor(layer_state_t state); -layer_state_t layer_state_set_user(layer_state_t state); -layer_state_t layer_state_set_kb(layer_state_t state); -#else -# define layer_state 0 - -# define layer_state_set(layer) -# define layer_state_is(layer) (layer == 0) -# define layer_state_cmp(state, layer) (state == 0 ? layer == 0 : (state & (layer_state_t)1 << layer) != 0) - -# define layer_debug() -# define layer_clear() -# define layer_move(layer) (void)layer -# define layer_on(layer) (void)layer -# define layer_off(layer) (void)layer -# define layer_invert(layer) (void)layer -# define layer_or(state) (void)state -# define layer_and(state) (void)state -# define layer_xor(state) (void)state -# define layer_state_set_kb(state) (void)state -# define layer_state_set_user(state) (void)state -#endif - -/* pressed actions cache */ -#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) - -void update_source_layers_cache(keypos_t key, uint8_t layer); -uint8_t read_source_layers_cache(keypos_t key); -#endif -action_t store_or_get_action(bool pressed, keypos_t key); - -/* return the topmost non-transparent layer currently associated with key */ -uint8_t layer_switch_get_layer(keypos_t key); - -/* return action depending on current layer status */ -action_t layer_switch_get_action(keypos_t key); diff --git a/tmk_core/common/action_macro.c b/tmk_core/common/action_macro.c deleted file mode 100644 index 92228c0ba8..0000000000 --- a/tmk_core/common/action_macro.c +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 "action.h" -#include "action_util.h" -#include "action_macro.h" -#include "wait.h" - -#ifdef DEBUG_ACTION -# include "debug.h" -#else -# include "nodebug.h" -#endif - -#ifndef NO_ACTION_MACRO - -# define MACRO_READ() (macro = MACRO_GET(macro_p++)) -/** \brief Action Macro Play - * - * FIXME: Needs doc - */ -void action_macro_play(const macro_t *macro_p) { - macro_t macro = END; - uint8_t interval = 0; - - if (!macro_p) return; - while (true) { - switch (MACRO_READ()) { - case KEY_DOWN: - MACRO_READ(); - dprintf("KEY_DOWN(%02X)\n", macro); - if (IS_MOD(macro)) { - add_macro_mods(MOD_BIT(macro)); - send_keyboard_report(); - } else { - register_code(macro); - } - break; - case KEY_UP: - MACRO_READ(); - dprintf("KEY_UP(%02X)\n", macro); - if (IS_MOD(macro)) { - del_macro_mods(MOD_BIT(macro)); - send_keyboard_report(); - } else { - unregister_code(macro); - } - break; - case WAIT: - MACRO_READ(); - dprintf("WAIT(%u)\n", macro); - { - uint8_t ms = macro; - while (ms--) wait_ms(1); - } - break; - case INTERVAL: - interval = MACRO_READ(); - dprintf("INTERVAL(%u)\n", interval); - break; - case 0x04 ... 0x73: - dprintf("DOWN(%02X)\n", macro); - register_code(macro); - break; - case 0x84 ... 0xF3: - dprintf("UP(%02X)\n", macro); - unregister_code(macro & 0x7F); - break; - case END: - default: - return; - } - // interval - { - uint8_t ms = interval; - while (ms--) wait_ms(1); - } - } -} -#endif diff --git a/tmk_core/common/action_macro.h b/tmk_core/common/action_macro.h deleted file mode 100644 index 685e2c6ffc..0000000000 --- a/tmk_core/common/action_macro.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include "progmem.h" - -typedef uint8_t macro_t; - -#define MACRO_NONE (macro_t *)0 -#define MACRO(...) \ - ({ \ - static const macro_t __m[] PROGMEM = {__VA_ARGS__}; \ - &__m[0]; \ - }) -#define MACRO_GET(p) pgm_read_byte(p) - -// Sends press when the macro key is pressed, release when release, or tap_macro when the key has been tapped -#define MACRO_TAP_HOLD(record, press, release, tap_macro) (((record)->event.pressed) ? (((record)->tap.count <= 0 || (record)->tap.interrupted) ? (press) : MACRO_NONE) : (((record)->tap.count > 0 && !((record)->tap.interrupted)) ? (tap_macro) : (release))) - -// Holds down the modifier mod when the macro key is held, or sends macro instead when tapped -#define MACRO_TAP_HOLD_MOD(record, macro, mod) MACRO_TAP_HOLD(record, (MACRO(D(mod), END)), MACRO(U(mod), END), macro) - -// Holds down the modifier mod when the macro key is held, or pressed a shifted key when tapped (eg: shift+3 for #) -#define MACRO_TAP_SHFT_KEY_HOLD_MOD(record, key, mod) MACRO_TAP_HOLD_MOD(record, (MACRO(I(10), D(LSFT), T(key), U(LSFT), END)), mod) - -// Momentary switch layer when held, sends macro if tapped -#define MACRO_TAP_HOLD_LAYER(record, macro, layer) \ - (((record)->event.pressed) ? (((record)->tap.count <= 0 || (record)->tap.interrupted) ? ({ \ - layer_on((layer)); \ - MACRO_NONE; \ - }) \ - : MACRO_NONE) \ - : (((record)->tap.count > 0 && !((record)->tap.interrupted)) ? (macro) : ({ \ - layer_off((layer)); \ - MACRO_NONE; \ - }))) - -// Momentary switch layer when held, presses a shifted key when tapped (eg: shift+3 for #) -#define MACRO_TAP_SHFT_KEY_HOLD_LAYER(record, key, layer) MACRO_TAP_HOLD_LAYER(record, MACRO(I(10), D(LSFT), T(key), U(LSFT), END), layer) - -#ifndef NO_ACTION_MACRO -void action_macro_play(const macro_t *macro_p); -#else -# define action_macro_play(macro) -#endif - -/* Macro commands - * code(0x04-73) // key down(1byte) - * code(0x04-73) | 0x80 // key up(1byte) - * { KEY_DOWN, code(0x04-0xff) } // key down(2bytes) - * { KEY_UP, code(0x04-0xff) } // key up(2bytes) - * WAIT // wait milli-seconds - * INTERVAL // set interval between macro commands - * END // stop macro execution - * - * Ideas(Not implemented): - * modifiers - * system usage - * consumer usage - * unicode usage - * function call - * conditionals - * loop - */ -enum macro_command_id { - /* 0x00 - 0x03 */ - END = 0x00, - KEY_DOWN, - KEY_UP, - - /* 0x04 - 0x73 (reserved for keycode down) */ - - /* 0x74 - 0x83 */ - WAIT = 0x74, - INTERVAL, - - /* 0x84 - 0xf3 (reserved for keycode up) */ - - /* 0xf4 - 0xff */ -}; - -/* TODO: keycode:0x04-0x73 can be handled by 1byte command else 2bytes are needed - * if keycode between 0x04 and 0x73 - * keycode / (keycode|0x80) - * else - * {KEY_DOWN, keycode} / {KEY_UP, keycode} - */ -#define DOWN(key) KEY_DOWN, (key) -#define UP(key) KEY_UP, (key) -#define TYPE(key) DOWN(key), UP(key) -#define WAIT(ms) WAIT, (ms) -#define INTERVAL(ms) INTERVAL, (ms) - -/* key down */ -#define D(key) DOWN(KC_##key) -/* key up */ -#define U(key) UP(KC_##key) -/* key type */ -#define T(key) TYPE(KC_##key) -/* wait */ -#define W(ms) WAIT(ms) -/* interval */ -#define I(ms) INTERVAL(ms) - -/* for backward comaptibility */ -#define MD(key) DOWN(KC_##key) -#define MU(key) UP(KC_##key) diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c deleted file mode 100644 index 36839f9faf..0000000000 --- a/tmk_core/common/action_tapping.c +++ /dev/null @@ -1,456 +0,0 @@ -#include -#include -#include "action.h" -#include "action_layer.h" -#include "action_tapping.h" -#include "keycode.h" -#include "timer.h" - -#ifdef DEBUG_ACTION -# include "debug.h" -#else -# include "nodebug.h" -#endif - -#ifndef NO_ACTION_TAPPING - -# define IS_TAPPING() !IS_NOEVENT(tapping_key.event) -# define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed) -# define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed) -# define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k))) -#ifndef COMBO_ENABLE -# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key))) -#else -# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode) -#endif - -__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; } - -# ifdef TAPPING_TERM_PER_KEY -# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_record_keycode(&tapping_key, false), &tapping_key)) -# else -# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM) -# endif - -# ifdef TAPPING_FORCE_HOLD_PER_KEY -__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) { return false; } -# endif - -# ifdef PERMISSIVE_HOLD_PER_KEY -__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { return false; } -# endif - -# ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY -__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { return false; } -# endif - -static keyrecord_t tapping_key = {}; -static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {}; -static uint8_t waiting_buffer_head = 0; -static uint8_t waiting_buffer_tail = 0; - -static bool process_tapping(keyrecord_t *record); -static bool waiting_buffer_enq(keyrecord_t record); -static void waiting_buffer_clear(void); -static bool waiting_buffer_typed(keyevent_t event); -static bool waiting_buffer_has_anykey_pressed(void); -static void waiting_buffer_scan_tap(void); -static void debug_tapping_key(void); -static void debug_waiting_buffer(void); - -/** \brief Action Tapping Process - * - * FIXME: Needs doc - */ -void action_tapping_process(keyrecord_t record) { - if (process_tapping(&record)) { - if (!IS_NOEVENT(record.event)) { - debug("processed: "); - debug_record(record); - debug("\n"); - } - } else { - if (!waiting_buffer_enq(record)) { - // clear all in case of overflow. - debug("OVERFLOW: CLEAR ALL STATES\n"); - clear_keyboard(); - waiting_buffer_clear(); - tapping_key = (keyrecord_t){}; - } - } - - // process waiting_buffer - if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) { - debug("---- action_exec: process waiting_buffer -----\n"); - } - for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) { - if (process_tapping(&waiting_buffer[waiting_buffer_tail])) { - debug("processed: waiting_buffer["); - debug_dec(waiting_buffer_tail); - debug("] = "); - debug_record(waiting_buffer[waiting_buffer_tail]); - debug("\n\n"); - } else { - break; - } - } - if (!IS_NOEVENT(record.event)) { - debug("\n"); - } -} - -/** \brief Tapping - * - * Rule: Tap key is typed(pressed and released) within TAPPING_TERM. - * (without interfering by typing other key) - */ -/* return true when key event is processed or consumed. */ -bool process_tapping(keyrecord_t *keyp) { - keyevent_t event = keyp->event; - - // if tapping - if (IS_TAPPING_PRESSED()) { - if (WITHIN_TAPPING_TERM(event)) { - if (tapping_key.tap.count == 0) { - if (IS_TAPPING_RECORD(keyp) && !event.pressed) { - // first tap! - debug("Tapping: First tap(0->1).\n"); - tapping_key.tap.count = 1; - debug_tapping_key(); - process_record(&tapping_key); - - // copy tapping state - keyp->tap = tapping_key.tap; - // enqueue - return false; - } - /* Process a key typed within TAPPING_TERM - * This can register the key before settlement of tapping, - * useful for long TAPPING_TERM but may prevent fast typing. - */ -# if defined(TAPPING_TERM_PER_KEY) || (TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD) || defined(PERMISSIVE_HOLD_PER_KEY) - else if ((( -# ifdef TAPPING_TERM_PER_KEY - get_tapping_term(get_record_keycode(&tapping_key, false), keyp) -# else - TAPPING_TERM -# endif - >= 500) - -# ifdef PERMISSIVE_HOLD_PER_KEY - || get_permissive_hold(get_record_keycode(&tapping_key, false), keyp) -# elif defined(PERMISSIVE_HOLD) - || true -# endif - ) && - IS_RELEASED(event) && waiting_buffer_typed(event)) { - debug("Tapping: End. No tap. Interfered by typing key\n"); - process_record(&tapping_key); - tapping_key = (keyrecord_t){}; - debug_tapping_key(); - // enqueue - return false; - } -# endif - /* Process release event of a key pressed before tapping starts - * Without this unexpected repeating will occur with having fast repeating setting - * https://github.com/tmk/tmk_keyboard/issues/60 - */ - else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) { - // Modifier should be retained till end of this tapping. - action_t action = layer_switch_get_action(event.key); - switch (action.kind.id) { - case ACT_LMODS: - case ACT_RMODS: - if (action.key.mods && !action.key.code) return false; - if (IS_MOD(action.key.code)) return false; - break; - case ACT_LMODS_TAP: - case ACT_RMODS_TAP: - if (action.key.mods && keyp->tap.count == 0) return false; - if (IS_MOD(action.key.code)) return false; - break; - } - // Release of key should be process immediately. - debug("Tapping: release event of a key pressed before tapping\n"); - process_record(keyp); - return true; - } else { - // set interrupted flag when other key preesed during tapping - if (event.pressed) { - tapping_key.tap.interrupted = true; -# if defined(HOLD_ON_OTHER_KEY_PRESS) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) -# if defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) - if (get_hold_on_other_key_press(get_record_keycode(&tapping_key, false), keyp)) -# endif - { - debug("Tapping: End. No tap. Interfered by pressed key\n"); - process_record(&tapping_key); - tapping_key = (keyrecord_t){}; - debug_tapping_key(); - // enqueue - return false; - } -# endif - } - // enqueue - return false; - } - } - // tap_count > 0 - else { - if (IS_TAPPING_RECORD(keyp) && !event.pressed) { - debug("Tapping: Tap release("); - debug_dec(tapping_key.tap.count); - debug(")\n"); - keyp->tap = tapping_key.tap; - process_record(keyp); - tapping_key = *keyp; - debug_tapping_key(); - return true; - } else if (is_tap_record(keyp) && event.pressed) { - if (tapping_key.tap.count > 1) { - debug("Tapping: Start new tap with releasing last tap(>1).\n"); - // unregister key - process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false, -#ifdef COMBO_ENABLE - .keycode = tapping_key.keycode, -#endif - }); - } else { - debug("Tapping: Start while last tap(1).\n"); - } - tapping_key = *keyp; - waiting_buffer_scan_tap(); - debug_tapping_key(); - return true; - } else { - if (!IS_NOEVENT(event)) { - debug("Tapping: key event while last tap(>0).\n"); - } - process_record(keyp); - return true; - } - } - } - // after TAPPING_TERM - else { - if (tapping_key.tap.count == 0) { - debug("Tapping: End. Timeout. Not tap(0): "); - debug_event(event); - debug("\n"); - process_record(&tapping_key); - tapping_key = (keyrecord_t){}; - debug_tapping_key(); - return false; - } else { - if (IS_TAPPING_RECORD(keyp) && !event.pressed) { - debug("Tapping: End. last timeout tap release(>0)."); - keyp->tap = tapping_key.tap; - process_record(keyp); - tapping_key = (keyrecord_t){}; - return true; - } else if (is_tap_record(keyp) && event.pressed) { - if (tapping_key.tap.count > 1) { - debug("Tapping: Start new tap with releasing last timeout tap(>1).\n"); - // unregister key - process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false, -#ifdef COMBO_ENABLE - .keycode = tapping_key.keycode, -#endif - }); - } else { - debug("Tapping: Start while last timeout tap(1).\n"); - } - tapping_key = *keyp; - waiting_buffer_scan_tap(); - debug_tapping_key(); - return true; - } else { - if (!IS_NOEVENT(event)) { - debug("Tapping: key event while last timeout tap(>0).\n"); - } - process_record(keyp); - return true; - } - } - } - } else if (IS_TAPPING_RELEASED()) { - if (WITHIN_TAPPING_TERM(event)) { - if (event.pressed) { - if (IS_TAPPING_RECORD(keyp)) { -//# ifndef TAPPING_FORCE_HOLD -# if !defined(TAPPING_FORCE_HOLD) || defined(TAPPING_FORCE_HOLD_PER_KEY) - if ( -# ifdef TAPPING_FORCE_HOLD_PER_KEY - !get_tapping_force_hold(get_record_keycode(&tapping_key, false), keyp) && -# endif - !tapping_key.tap.interrupted && tapping_key.tap.count > 0) { - // sequential tap. - keyp->tap = tapping_key.tap; - if (keyp->tap.count < 15) keyp->tap.count += 1; - debug("Tapping: Tap press("); - debug_dec(keyp->tap.count); - debug(")\n"); - process_record(keyp); - tapping_key = *keyp; - debug_tapping_key(); - return true; - } -# endif - // FIX: start new tap again - tapping_key = *keyp; - return true; - } else if (is_tap_record(keyp)) { - // Sequential tap can be interfered with other tap key. - debug("Tapping: Start with interfering other tap.\n"); - tapping_key = *keyp; - waiting_buffer_scan_tap(); - debug_tapping_key(); - return true; - } else { - // should none in buffer - // FIX: interrupted when other key is pressed - tapping_key.tap.interrupted = true; - process_record(keyp); - return true; - } - } else { - if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n"); - process_record(keyp); - return true; - } - } else { - // FIX: process_action here? - // timeout. no sequential tap. - debug("Tapping: End(Timeout after releasing last tap): "); - debug_event(event); - debug("\n"); - tapping_key = (keyrecord_t){}; - debug_tapping_key(); - return false; - } - } - // not tapping state - else { - if (event.pressed && is_tap_record(keyp)) { - debug("Tapping: Start(Press tap key).\n"); - tapping_key = *keyp; - process_record_tap_hint(&tapping_key); - waiting_buffer_scan_tap(); - debug_tapping_key(); - return true; - } else { - process_record(keyp); - return true; - } - } -} - -/** \brief Waiting buffer enq - * - * FIXME: Needs docs - */ -bool waiting_buffer_enq(keyrecord_t record) { - if (IS_NOEVENT(record.event)) { - return true; - } - - if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) { - debug("waiting_buffer_enq: Over flow.\n"); - return false; - } - - waiting_buffer[waiting_buffer_head] = record; - waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE; - - debug("waiting_buffer_enq: "); - debug_waiting_buffer(); - return true; -} - -/** \brief Waiting buffer clear - * - * FIXME: Needs docs - */ -void waiting_buffer_clear(void) { - waiting_buffer_head = 0; - waiting_buffer_tail = 0; -} - -/** \brief Waiting buffer typed - * - * FIXME: Needs docs - */ -bool waiting_buffer_typed(keyevent_t event) { - for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { - if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) { - return true; - } - } - return false; -} - -/** \brief Waiting buffer has anykey pressed - * - * FIXME: Needs docs - */ -__attribute__((unused)) bool waiting_buffer_has_anykey_pressed(void) { - for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { - if (waiting_buffer[i].event.pressed) return true; - } - return false; -} - -/** \brief Scan buffer for tapping - * - * FIXME: Needs docs - */ -void waiting_buffer_scan_tap(void) { - // tapping already is settled - if (tapping_key.tap.count > 0) return; - // invalid state: tapping_key released && tap.count == 0 - if (!tapping_key.event.pressed) return; - - for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { - if (IS_TAPPING_KEY(waiting_buffer[i].event.key) && !waiting_buffer[i].event.pressed && WITHIN_TAPPING_TERM(waiting_buffer[i].event)) { - tapping_key.tap.count = 1; - waiting_buffer[i].tap.count = 1; - process_record(&tapping_key); - - debug("waiting_buffer_scan_tap: found at ["); - debug_dec(i); - debug("]\n"); - debug_waiting_buffer(); - return; - } - } -} - -/** \brief Tapping key debug print - * - * FIXME: Needs docs - */ -static void debug_tapping_key(void) { - debug("TAPPING_KEY="); - debug_record(tapping_key); - debug("\n"); -} - -/** \brief Waiting buffer debug print - * - * FIXME: Needs docs - */ -static void debug_waiting_buffer(void) { - debug("{ "); - for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { - debug("["); - debug_dec(i); - debug("]="); - debug_record(waiting_buffer[i]); - debug(" "); - } - debug("}\n"); -} - -#endif diff --git a/tmk_core/common/action_tapping.h b/tmk_core/common/action_tapping.h deleted file mode 100644 index 7de8049c7f..0000000000 --- a/tmk_core/common/action_tapping.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 - -/* period of tapping(ms) */ -#ifndef TAPPING_TERM -# define TAPPING_TERM 200 -#endif - -/* tap count needed for toggling a feature */ -#ifndef TAPPING_TOGGLE -# define TAPPING_TOGGLE 5 -#endif - -#define WAITING_BUFFER_SIZE 8 - -#ifndef NO_ACTION_TAPPING -uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache); -uint16_t get_event_keycode(keyevent_t event, bool update_layer_cache); -void action_tapping_process(keyrecord_t record); - -uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record); -bool get_permissive_hold(uint16_t keycode, keyrecord_t *record); -bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record); -bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record); -bool get_retro_tapping(uint16_t keycode, keyrecord_t *record); -#endif diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c deleted file mode 100644 index 2b3c00cba0..0000000000 --- a/tmk_core/common/action_util.c +++ /dev/null @@ -1,455 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 "host.h" -#include "report.h" -#include "debug.h" -#include "action_util.h" -#include "action_layer.h" -#include "timer.h" -#include "keycode_config.h" - -extern keymap_config_t keymap_config; - -static uint8_t real_mods = 0; -static uint8_t weak_mods = 0; -static uint8_t macro_mods = 0; -#ifdef KEY_OVERRIDE_ENABLE -static uint8_t weak_override_mods = 0; -static uint8_t suppressed_mods = 0; -#endif - -#ifdef USB_6KRO_ENABLE -# define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS) -# define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS) -# define RO_INC(a) RO_ADD(a, 1) -# define RO_DEC(a) RO_SUB(a, 1) -static int8_t cb_head = 0; -static int8_t cb_tail = 0; -static int8_t cb_count = 0; -#endif - -// TODO: pointer variable is not needed -// report_keyboard_t keyboard_report = {}; -report_keyboard_t *keyboard_report = &(report_keyboard_t){}; - -extern inline void add_key(uint8_t key); -extern inline void del_key(uint8_t key); -extern inline void clear_keys(void); - -#ifndef NO_ACTION_ONESHOT -static uint8_t oneshot_mods = 0; -static uint8_t oneshot_locked_mods = 0; -uint8_t get_oneshot_locked_mods(void) { return oneshot_locked_mods; } -void set_oneshot_locked_mods(uint8_t mods) { - if (mods != oneshot_locked_mods) { - oneshot_locked_mods = mods; - oneshot_locked_mods_changed_kb(oneshot_locked_mods); - } -} -void clear_oneshot_locked_mods(void) { - if (oneshot_locked_mods) { - oneshot_locked_mods = 0; - oneshot_locked_mods_changed_kb(oneshot_locked_mods); - } -} -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) -static uint16_t oneshot_time = 0; -bool has_oneshot_mods_timed_out(void) { return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT; } -# else -bool has_oneshot_mods_timed_out(void) { return false; } -# endif -#endif - -/* oneshot layer */ -#ifndef NO_ACTION_ONESHOT -/** \brief oneshot_layer_data bits - * LLLL LSSS - * where: - * L => are layer bits - * S => oneshot state bits - */ -static int8_t oneshot_layer_data = 0; - -inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; } -inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; } - -# ifdef SWAP_HANDS_ENABLE -enum { - SHO_OFF, - SHO_ACTIVE, // Swap hands button was pressed, and we didn't send any swapped keys yet - SHO_PRESSED, // Swap hands button is currently pressed - SHO_USED, // Swap hands button is still pressed, and we already sent swapped keys -} swap_hands_oneshot = SHO_OFF; -# endif - -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) -static uint16_t oneshot_layer_time = 0; -inline bool has_oneshot_layer_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT && !(get_oneshot_layer_state() & ONESHOT_TOGGLED); } -# ifdef SWAP_HANDS_ENABLE -static uint16_t oneshot_swaphands_time = 0; -inline bool has_oneshot_swaphands_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_swaphands_time) >= ONESHOT_TIMEOUT && (swap_hands_oneshot == SHO_ACTIVE); } -# endif -# endif - -# ifdef SWAP_HANDS_ENABLE - -void set_oneshot_swaphands(void) { - swap_hands_oneshot = SHO_PRESSED; - swap_hands = true; -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_swaphands_time = timer_read(); - if (oneshot_layer_time != 0) { - oneshot_layer_time = oneshot_swaphands_time; - } -# endif -} - -void release_oneshot_swaphands(void) { - if (swap_hands_oneshot == SHO_PRESSED) { - swap_hands_oneshot = SHO_ACTIVE; - } - if (swap_hands_oneshot == SHO_USED) { - clear_oneshot_swaphands(); - } -} - -void use_oneshot_swaphands(void) { - if (swap_hands_oneshot == SHO_PRESSED) { - swap_hands_oneshot = SHO_USED; - } - if (swap_hands_oneshot == SHO_ACTIVE) { - clear_oneshot_swaphands(); - } -} - -void clear_oneshot_swaphands(void) { - swap_hands_oneshot = SHO_OFF; - swap_hands = false; -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_swaphands_time = 0; -# endif -} - -# endif - -/** \brief Set oneshot layer - * - * FIXME: needs doc - */ -void set_oneshot_layer(uint8_t layer, uint8_t state) { - if (!keymap_config.oneshot_disable) { - oneshot_layer_data = layer << 3 | state; - layer_on(layer); -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_layer_time = timer_read(); -# endif - oneshot_layer_changed_kb(get_oneshot_layer()); - } else { - layer_on(layer); - } -} -/** \brief Reset oneshot layer - * - * FIXME: needs doc - */ -void reset_oneshot_layer(void) { - oneshot_layer_data = 0; -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_layer_time = 0; -# endif - oneshot_layer_changed_kb(get_oneshot_layer()); -} -/** \brief Clear oneshot layer - * - * FIXME: needs doc - */ -void clear_oneshot_layer_state(oneshot_fullfillment_t state) { - uint8_t start_state = oneshot_layer_data; - oneshot_layer_data &= ~state; - if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) || keymap_config.oneshot_disable) { - layer_off(get_oneshot_layer()); - reset_oneshot_layer(); - } -} -/** \brief Is oneshot layer active - * - * FIXME: needs doc - */ -bool is_oneshot_layer_active(void) { return get_oneshot_layer_state(); } - -/** \brief set oneshot - * - * FIXME: needs doc - */ -void oneshot_set(bool active) { - if (keymap_config.oneshot_disable != active) { - keymap_config.oneshot_disable = active; - eeconfig_update_keymap(keymap_config.raw); - dprintf("Oneshot: active: %d\n", active); - } -} - -/** \brief toggle oneshot - * - * FIXME: needs doc - */ -void oneshot_toggle(void) { oneshot_set(!keymap_config.oneshot_disable); } - -/** \brief enable oneshot - * - * FIXME: needs doc - */ -void oneshot_enable(void) { oneshot_set(true); } - -/** \brief disable oneshot - * - * FIXME: needs doc - */ -void oneshot_disable(void) { oneshot_set(false); } - -bool is_oneshot_enabled(void) { return keymap_config.oneshot_disable; } - -#endif - -/** \brief Send keyboard report - * - * FIXME: needs doc - */ -void send_keyboard_report(void) { - keyboard_report->mods = real_mods; - keyboard_report->mods |= weak_mods; - keyboard_report->mods |= macro_mods; - -#ifndef NO_ACTION_ONESHOT - if (oneshot_mods) { -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - if (has_oneshot_mods_timed_out()) { - dprintf("Oneshot: timeout\n"); - clear_oneshot_mods(); - } -# endif - keyboard_report->mods |= oneshot_mods; - if (has_anykey(keyboard_report)) { - clear_oneshot_mods(); - } - } - -#endif - -#ifdef KEY_OVERRIDE_ENABLE - // These need to be last to be able to properly control key overrides - keyboard_report->mods &= ~suppressed_mods; - keyboard_report->mods |= weak_override_mods; -#endif - - host_keyboard_send(keyboard_report); -} - -/** \brief Get mods - * - * FIXME: needs doc - */ -uint8_t get_mods(void) { return real_mods; } -/** \brief add mods - * - * FIXME: needs doc - */ -void add_mods(uint8_t mods) { real_mods |= mods; } -/** \brief del mods - * - * FIXME: needs doc - */ -void del_mods(uint8_t mods) { real_mods &= ~mods; } -/** \brief set mods - * - * FIXME: needs doc - */ -void set_mods(uint8_t mods) { real_mods = mods; } -/** \brief clear mods - * - * FIXME: needs doc - */ -void clear_mods(void) { real_mods = 0; } - -/** \brief get weak mods - * - * FIXME: needs doc - */ -uint8_t get_weak_mods(void) { return weak_mods; } -/** \brief add weak mods - * - * FIXME: needs doc - */ -void add_weak_mods(uint8_t mods) { weak_mods |= mods; } -/** \brief del weak mods - * - * FIXME: needs doc - */ -void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; } -/** \brief set weak mods - * - * FIXME: needs doc - */ -void set_weak_mods(uint8_t mods) { weak_mods = mods; } -/** \brief clear weak mods - * - * FIXME: needs doc - */ -void clear_weak_mods(void) { weak_mods = 0; } - -#ifdef KEY_OVERRIDE_ENABLE -/** \brief set weak mods used by key overrides. DO not call this manually - */ -void set_weak_override_mods(uint8_t mods) { weak_override_mods = mods; } -/** \brief clear weak mods used by key overrides. DO not call this manually - */ -void clear_weak_override_mods(void) { weak_override_mods = 0; } - -/** \brief set suppressed mods used by key overrides. DO not call this manually - */ -void set_suppressed_override_mods(uint8_t mods) { suppressed_mods = mods; } -/** \brief clear suppressed mods used by key overrides. DO not call this manually - */ -void clear_suppressed_override_mods(void) { suppressed_mods = 0; } -#endif - -/* macro modifier */ -/** \brief get macro mods - * - * FIXME: needs doc - */ -uint8_t get_macro_mods(void) { return macro_mods; } -/** \brief add macro mods - * - * FIXME: needs doc - */ -void add_macro_mods(uint8_t mods) { macro_mods |= mods; } -/** \brief del macro mods - * - * FIXME: needs doc - */ -void del_macro_mods(uint8_t mods) { macro_mods &= ~mods; } -/** \brief set macro mods - * - * FIXME: needs doc - */ -void set_macro_mods(uint8_t mods) { macro_mods = mods; } -/** \brief clear macro mods - * - * FIXME: needs doc - */ -void clear_macro_mods(void) { macro_mods = 0; } - -#ifndef NO_ACTION_ONESHOT -/** \brief get oneshot mods - * - * FIXME: needs doc - */ -uint8_t get_oneshot_mods(void) { return oneshot_mods; } - -void add_oneshot_mods(uint8_t mods) { - if ((oneshot_mods & mods) != mods) { -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_time = timer_read(); -# endif - oneshot_mods |= mods; - oneshot_mods_changed_kb(mods); - } -} - -void del_oneshot_mods(uint8_t mods) { - if (oneshot_mods & mods) { - oneshot_mods &= ~mods; -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_time = oneshot_mods ? timer_read() : 0; -# endif - oneshot_mods_changed_kb(oneshot_mods); - } -} - -/** \brief set oneshot mods - * - * FIXME: needs doc - */ -void set_oneshot_mods(uint8_t mods) { - if (!keymap_config.oneshot_disable) { - if (oneshot_mods != mods) { -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_time = timer_read(); -# endif - oneshot_mods = mods; - oneshot_mods_changed_kb(mods); - } - } -} - -/** \brief clear oneshot mods - * - * FIXME: needs doc - */ -void clear_oneshot_mods(void) { - if (oneshot_mods) { - oneshot_mods = 0; -# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) - oneshot_time = 0; -# endif - oneshot_mods_changed_kb(oneshot_mods); - } -} -#endif - -/** \brief Called when the one shot modifiers have been changed. - * - * \param mods Contains the active modifiers active after the change. - */ -__attribute__((weak)) void oneshot_locked_mods_changed_user(uint8_t mods) {} - -/** \brief Called when the locked one shot modifiers have been changed. - * - * \param mods Contains the active modifiers active after the change. - */ -__attribute__((weak)) void oneshot_locked_mods_changed_kb(uint8_t mods) { oneshot_locked_mods_changed_user(mods); } - -/** \brief Called when the one shot modifiers have been changed. - * - * \param mods Contains the active modifiers active after the change. - */ -__attribute__((weak)) void oneshot_mods_changed_user(uint8_t mods) {} - -/** \brief Called when the one shot modifiers have been changed. - * - * \param mods Contains the active modifiers active after the change. - */ -__attribute__((weak)) void oneshot_mods_changed_kb(uint8_t mods) { oneshot_mods_changed_user(mods); } - -/** \brief Called when the one shot layers have been changed. - * - * \param layer Contains the layer that is toggled on, or zero when toggled off. - */ -__attribute__((weak)) void oneshot_layer_changed_user(uint8_t layer) {} - -/** \brief Called when the one shot layers have been changed. - * - * \param layer Contains the layer that is toggled on, or zero when toggled off. - */ -__attribute__((weak)) void oneshot_layer_changed_kb(uint8_t layer) { oneshot_layer_changed_user(layer); } - -/** \brief inspect keyboard state - * - * FIXME: needs doc - */ -uint8_t has_anymod(void) { return bitpop(real_mods); } diff --git a/tmk_core/common/action_util.h b/tmk_core/common/action_util.h deleted file mode 100644 index f2b3897ae5..0000000000 --- a/tmk_core/common/action_util.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include "report.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern report_keyboard_t *keyboard_report; - -void send_keyboard_report(void); - -/* key */ -inline void add_key(uint8_t key) { add_key_to_report(keyboard_report, key); } - -inline void del_key(uint8_t key) { del_key_from_report(keyboard_report, key); } - -inline void clear_keys(void) { clear_keys_from_report(keyboard_report); } - -/* modifier */ -uint8_t get_mods(void); -void add_mods(uint8_t mods); -void del_mods(uint8_t mods); -void set_mods(uint8_t mods); -void clear_mods(void); - -/* weak modifier */ -uint8_t get_weak_mods(void); -void add_weak_mods(uint8_t mods); -void del_weak_mods(uint8_t mods); -void set_weak_mods(uint8_t mods); -void clear_weak_mods(void); - -/* macro modifier */ -uint8_t get_macro_mods(void); -void add_macro_mods(uint8_t mods); -void del_macro_mods(uint8_t mods); -void set_macro_mods(uint8_t mods); -void clear_macro_mods(void); - -/* oneshot modifier */ -uint8_t get_oneshot_mods(void); -void add_oneshot_mods(uint8_t mods); -void del_oneshot_mods(uint8_t mods); -void set_oneshot_mods(uint8_t mods); -void clear_oneshot_mods(void); -bool has_oneshot_mods_timed_out(void); - -uint8_t get_oneshot_locked_mods(void); -void set_oneshot_locked_mods(uint8_t mods); -void clear_oneshot_locked_mods(void); - -typedef enum { ONESHOT_PRESSED = 0b01, ONESHOT_OTHER_KEY_PRESSED = 0b10, ONESHOT_START = 0b11, ONESHOT_TOGGLED = 0b100 } oneshot_fullfillment_t; -void set_oneshot_layer(uint8_t layer, uint8_t state); -uint8_t get_oneshot_layer(void); -void clear_oneshot_layer_state(oneshot_fullfillment_t state); -void reset_oneshot_layer(void); -bool is_oneshot_layer_active(void); -uint8_t get_oneshot_layer_state(void); -bool has_oneshot_layer_timed_out(void); -bool has_oneshot_swaphands_timed_out(void); - -void oneshot_locked_mods_changed_user(uint8_t mods); -void oneshot_locked_mods_changed_kb(uint8_t mods); -void oneshot_mods_changed_user(uint8_t mods); -void oneshot_mods_changed_kb(uint8_t mods); -void oneshot_layer_changed_user(uint8_t layer); -void oneshot_layer_changed_kb(uint8_t layer); - -void oneshot_toggle(void); -void oneshot_enable(void); -void oneshot_disable(void); -bool is_oneshot_enabled(void); - -/* inspect */ -uint8_t has_anymod(void); - -#ifdef SWAP_HANDS_ENABLE -void set_oneshot_swaphands(void); -void release_oneshot_swaphands(void); -void use_oneshot_swaphands(void); -void clear_oneshot_swaphands(void); -#endif - -#ifdef __cplusplus -} -#endif diff --git a/tmk_core/common/eeconfig.c b/tmk_core/common/eeconfig.c deleted file mode 100644 index ffa56ab56d..0000000000 --- a/tmk_core/common/eeconfig.c +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include "eeprom.h" -#include "eeconfig.h" -#include "action_layer.h" - -#ifdef STM32_EEPROM_ENABLE -# include -# include "eeprom_stm32.h" -#endif - -#if defined(EEPROM_DRIVER) -# include "eeprom_driver.h" -#endif - -#if defined(HAPTIC_ENABLE) -# include "haptic.h" -#endif - -/** \brief eeconfig enable - * - * FIXME: needs doc - */ -__attribute__((weak)) void eeconfig_init_user(void) { - // Reset user EEPROM value to blank, rather than to a set value - eeconfig_update_user(0); -} - -__attribute__((weak)) void eeconfig_init_kb(void) { - // Reset Keyboard EEPROM value to blank, rather than to a set value - eeconfig_update_kb(0); - - eeconfig_init_user(); -} - -/* - * FIXME: needs doc - */ -void eeconfig_init_quantum(void) { -#ifdef STM32_EEPROM_ENABLE - EEPROM_Erase(); -#endif -#if defined(EEPROM_DRIVER) - eeprom_driver_erase(); -#endif - eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); - eeprom_update_byte(EECONFIG_DEBUG, 0); - eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0); - default_layer_state = 0; - eeprom_update_byte(EECONFIG_KEYMAP_LOWER_BYTE, 0); - eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, 0); - eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0); - eeprom_update_byte(EECONFIG_BACKLIGHT, 0); - eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default - eeprom_update_dword(EECONFIG_RGBLIGHT, 0); - eeprom_update_byte(EECONFIG_STENOMODE, 0); - eeprom_update_dword(EECONFIG_HAPTIC, 0); - eeprom_update_byte(EECONFIG_VELOCIKEY, 0); - eeprom_update_dword(EECONFIG_RGB_MATRIX, 0); - eeprom_update_word(EECONFIG_RGB_MATRIX_EXTENDED, 0); - - // TODO: Remove once ARM has a way to configure EECONFIG_HANDEDNESS - // within the emulated eeprom via dfu-util or another tool -#if defined INIT_EE_HANDS_LEFT -# pragma message "Faking EE_HANDS for left hand" - eeprom_update_byte(EECONFIG_HANDEDNESS, 1); -#elif defined INIT_EE_HANDS_RIGHT -# pragma message "Faking EE_HANDS for right hand" - eeprom_update_byte(EECONFIG_HANDEDNESS, 0); -#endif - -#if defined(HAPTIC_ENABLE) - haptic_reset(); -#else - // this is used in case haptic is disabled, but we still want sane defaults - // in the haptic configuration eeprom. All zero will trigger a haptic_reset - // when a haptic-enabled firmware is loaded onto the keyboard. - eeprom_update_dword(EECONFIG_HAPTIC, 0); -#endif - - eeconfig_init_kb(); -} - -/** \brief eeconfig initialization - * - * FIXME: needs doc - */ -void eeconfig_init(void) { eeconfig_init_quantum(); } - -/** \brief eeconfig enable - * - * FIXME: needs doc - */ -void eeconfig_enable(void) { eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); } - -/** \brief eeconfig disable - * - * FIXME: needs doc - */ -void eeconfig_disable(void) { -#ifdef STM32_EEPROM_ENABLE - EEPROM_Erase(); -#endif -#if defined(EEPROM_DRIVER) - eeprom_driver_erase(); -#endif - eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER_OFF); -} - -/** \brief eeconfig is enabled - * - * FIXME: needs doc - */ -bool eeconfig_is_enabled(void) { return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER); } - -/** \brief eeconfig is disabled - * - * FIXME: needs doc - */ -bool eeconfig_is_disabled(void) { return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER_OFF); } - -/** \brief eeconfig read debug - * - * FIXME: needs doc - */ -uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); } -/** \brief eeconfig update debug - * - * FIXME: needs doc - */ -void eeconfig_update_debug(uint8_t val) { eeprom_update_byte(EECONFIG_DEBUG, val); } - -/** \brief eeconfig read default layer - * - * FIXME: needs doc - */ -uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); } -/** \brief eeconfig update default layer - * - * FIXME: needs doc - */ -void eeconfig_update_default_layer(uint8_t val) { eeprom_update_byte(EECONFIG_DEFAULT_LAYER, val); } - -/** \brief eeconfig read keymap - * - * FIXME: needs doc - */ -uint16_t eeconfig_read_keymap(void) { return (eeprom_read_byte(EECONFIG_KEYMAP_LOWER_BYTE) | (eeprom_read_byte(EECONFIG_KEYMAP_UPPER_BYTE) << 8)); } -/** \brief eeconfig update keymap - * - * FIXME: needs doc - */ -void eeconfig_update_keymap(uint16_t val) { - eeprom_update_byte(EECONFIG_KEYMAP_LOWER_BYTE, val & 0xFF); - eeprom_update_byte(EECONFIG_KEYMAP_UPPER_BYTE, (val >> 8) & 0xFF); -} - -/** \brief eeconfig read audio - * - * FIXME: needs doc - */ -uint8_t eeconfig_read_audio(void) { return eeprom_read_byte(EECONFIG_AUDIO); } -/** \brief eeconfig update audio - * - * FIXME: needs doc - */ -void eeconfig_update_audio(uint8_t val) { eeprom_update_byte(EECONFIG_AUDIO, val); } - -/** \brief eeconfig read kb - * - * FIXME: needs doc - */ -uint32_t eeconfig_read_kb(void) { return eeprom_read_dword(EECONFIG_KEYBOARD); } -/** \brief eeconfig update kb - * - * FIXME: needs doc - */ -void eeconfig_update_kb(uint32_t val) { eeprom_update_dword(EECONFIG_KEYBOARD, val); } - -/** \brief eeconfig read user - * - * FIXME: needs doc - */ -uint32_t eeconfig_read_user(void) { return eeprom_read_dword(EECONFIG_USER); } -/** \brief eeconfig update user - * - * FIXME: needs doc - */ -void eeconfig_update_user(uint32_t val) { eeprom_update_dword(EECONFIG_USER, val); } - -/** \brief eeconfig read haptic - * - * FIXME: needs doc - */ -uint32_t eeconfig_read_haptic(void) { return eeprom_read_dword(EECONFIG_HAPTIC); } -/** \brief eeconfig update haptic - * - * FIXME: needs doc - */ -void eeconfig_update_haptic(uint32_t val) { eeprom_update_dword(EECONFIG_HAPTIC, val); } - -/** \brief eeconfig read split handedness - * - * FIXME: needs doc - */ -bool eeconfig_read_handedness(void) { return !!eeprom_read_byte(EECONFIG_HANDEDNESS); } -/** \brief eeconfig update split handedness - * - * FIXME: needs doc - */ -void eeconfig_update_handedness(bool val) { eeprom_update_byte(EECONFIG_HANDEDNESS, !!val); } diff --git a/tmk_core/common/eeconfig.h b/tmk_core/common/eeconfig.h deleted file mode 100644 index a88071729d..0000000000 --- a/tmk_core/common/eeconfig.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include - -#ifndef EECONFIG_MAGIC_NUMBER -# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEEA // When changing, decrement this value to avoid future re-init issues -#endif -#define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF - -/* EEPROM parameter address */ -#define EECONFIG_MAGIC (uint16_t *)0 -#define EECONFIG_DEBUG (uint8_t *)2 -#define EECONFIG_DEFAULT_LAYER (uint8_t *)3 -#define EECONFIG_KEYMAP (uint8_t *)4 -#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5 -#define EECONFIG_BACKLIGHT (uint8_t *)6 -#define EECONFIG_AUDIO (uint8_t *)7 -#define EECONFIG_RGBLIGHT (uint32_t *)8 -#define EECONFIG_UNICODEMODE (uint8_t *)12 -#define EECONFIG_STENOMODE (uint8_t *)13 -// EEHANDS for two handed boards -#define EECONFIG_HANDEDNESS (uint8_t *)14 -#define EECONFIG_KEYBOARD (uint32_t *)15 -#define EECONFIG_USER (uint32_t *)19 -#define EECONFIG_VELOCIKEY (uint8_t *)23 - -#define EECONFIG_HAPTIC (uint32_t *)24 - -// Mutually exclusive -#define EECONFIG_LED_MATRIX (uint32_t *)28 -#define EECONFIG_RGB_MATRIX (uint32_t *)28 -// Speed & Flags -#define EECONFIG_LED_MATRIX_EXTENDED (uint16_t *)32 -#define EECONFIG_RGB_MATRIX_EXTENDED (uint16_t *)32 - -// TODO: Combine these into a single word and single block of EEPROM -#define EECONFIG_KEYMAP_UPPER_BYTE (uint8_t *)34 -// Size of EEPROM being used, other code can refer to this for available EEPROM -#define EECONFIG_SIZE 35 -/* debug bit */ -#define EECONFIG_DEBUG_ENABLE (1 << 0) -#define EECONFIG_DEBUG_MATRIX (1 << 1) -#define EECONFIG_DEBUG_KEYBOARD (1 << 2) -#define EECONFIG_DEBUG_MOUSE (1 << 3) - -/* keyconf bit */ -#define EECONFIG_KEYMAP_SWAP_CONTROL_CAPSLOCK (1 << 0) -#define EECONFIG_KEYMAP_CAPSLOCK_TO_CONTROL (1 << 1) -#define EECONFIG_KEYMAP_SWAP_LALT_LGUI (1 << 2) -#define EECONFIG_KEYMAP_SWAP_RALT_RGUI (1 << 3) -#define EECONFIG_KEYMAP_NO_GUI (1 << 4) -#define EECONFIG_KEYMAP_SWAP_GRAVE_ESC (1 << 5) -#define EECONFIG_KEYMAP_SWAP_BACKSLASH_BACKSPACE (1 << 6) -#define EECONFIG_KEYMAP_NKRO (1 << 7) - -#define EECONFIG_KEYMAP_LOWER_BYTE EECONFIG_KEYMAP - -bool eeconfig_is_enabled(void); -bool eeconfig_is_disabled(void); - -void eeconfig_init(void); -void eeconfig_init_quantum(void); -void eeconfig_init_kb(void); -void eeconfig_init_user(void); - -void eeconfig_enable(void); - -void eeconfig_disable(void); - -uint8_t eeconfig_read_debug(void); -void eeconfig_update_debug(uint8_t val); - -uint8_t eeconfig_read_default_layer(void); -void eeconfig_update_default_layer(uint8_t val); - -uint16_t eeconfig_read_keymap(void); -void eeconfig_update_keymap(uint16_t val); - -#ifdef AUDIO_ENABLE -uint8_t eeconfig_read_audio(void); -void eeconfig_update_audio(uint8_t val); -#endif - -uint32_t eeconfig_read_kb(void); -void eeconfig_update_kb(uint32_t val); -uint32_t eeconfig_read_user(void); -void eeconfig_update_user(uint32_t val); - -#ifdef HAPTIC_ENABLE -uint32_t eeconfig_read_haptic(void); -void eeconfig_update_haptic(uint32_t val); -#endif - -bool eeconfig_read_handedness(void); -void eeconfig_update_handedness(bool val); diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c deleted file mode 100644 index fcc51973fd..0000000000 --- a/tmk_core/common/keyboard.c +++ /dev/null @@ -1,565 +0,0 @@ -/* -Copyright 2011, 2012, 2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include "keyboard.h" -#include "matrix.h" -#include "keymap.h" -#include "host.h" -#include "led.h" -#include "keycode.h" -#include "timer.h" -#include "sync_timer.h" -#include "print.h" -#include "debug.h" -#include "command.h" -#include "util.h" -#include "sendchar.h" -#include "eeconfig.h" -#include "action_layer.h" -#ifdef BACKLIGHT_ENABLE -# include "backlight.h" -#endif -#ifdef MOUSEKEY_ENABLE -# include "mousekey.h" -#endif -#ifdef PS2_MOUSE_ENABLE -# include "ps2_mouse.h" -#endif -#ifdef SERIAL_MOUSE_ENABLE -# include "serial_mouse.h" -#endif -#ifdef ADB_MOUSE_ENABLE -# include "adb.h" -#endif -#ifdef RGBLIGHT_ENABLE -# include "rgblight.h" -#endif -#ifdef LED_MATRIX_ENABLE -# include "led_matrix.h" -#endif -#ifdef RGB_MATRIX_ENABLE -# include "rgb_matrix.h" -#endif -#ifdef ENCODER_ENABLE -# include "encoder.h" -#endif -#ifdef STENO_ENABLE -# include "process_steno.h" -#endif -#ifdef SERIAL_LINK_ENABLE -# include "serial_link/system/serial_link.h" -#endif -#ifdef VISUALIZER_ENABLE -# include "visualizer/visualizer.h" -#endif -#ifdef POINTING_DEVICE_ENABLE -# include "pointing_device.h" -#endif -#ifdef MIDI_ENABLE -# include "process_midi.h" -#endif -#ifdef JOYSTICK_ENABLE -# include "process_joystick.h" -#endif -#ifdef HD44780_ENABLE -# include "hd44780.h" -#endif -#ifdef QWIIC_ENABLE -# include "qwiic.h" -#endif -#ifdef OLED_DRIVER_ENABLE -# include "oled_driver.h" -#endif -#ifdef ST7565_ENABLE -# include "st7565.h" -#endif -#ifdef VELOCIKEY_ENABLE -# include "velocikey.h" -#endif -#ifdef VIA_ENABLE -# include "via.h" -#endif -#ifdef DIP_SWITCH_ENABLE -# include "dip_switch.h" -#endif -#ifdef STM32_EEPROM_ENABLE -# include "eeprom_stm32.h" -#endif -#ifdef EEPROM_DRIVER -# include "eeprom_driver.h" -#endif -#if defined(CRC_ENABLE) -# include "crc.h" -#endif -#ifdef DIGITIZER_ENABLE -# include "digitizer.h" -#endif - -static uint32_t last_input_modification_time = 0; -uint32_t last_input_activity_time(void) { return last_input_modification_time; } -uint32_t last_input_activity_elapsed(void) { return timer_elapsed32(last_input_modification_time); } - -static uint32_t last_matrix_modification_time = 0; -uint32_t last_matrix_activity_time(void) { return last_matrix_modification_time; } -uint32_t last_matrix_activity_elapsed(void) { return timer_elapsed32(last_matrix_modification_time); } -void last_matrix_activity_trigger(void) { last_matrix_modification_time = last_input_modification_time = timer_read32(); } - -static uint32_t last_encoder_modification_time = 0; -uint32_t last_encoder_activity_time(void) { return last_encoder_modification_time; } -uint32_t last_encoder_activity_elapsed(void) { return timer_elapsed32(last_encoder_modification_time); } -void last_encoder_activity_trigger(void) { last_encoder_modification_time = last_input_modification_time = timer_read32(); } - -// Only enable this if console is enabled to print to -#if defined(DEBUG_MATRIX_SCAN_RATE) -static uint32_t matrix_timer = 0; -static uint32_t matrix_scan_count = 0; -static uint32_t last_matrix_scan_count = 0; - -void matrix_scan_perf_task(void) { - matrix_scan_count++; - - uint32_t timer_now = timer_read32(); - if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) { -# if defined(CONSOLE_ENABLE) - dprintf("matrix scan frequency: %lu\n", matrix_scan_count); -# endif - last_matrix_scan_count = matrix_scan_count; - matrix_timer = timer_now; - matrix_scan_count = 0; - } -} - -uint32_t get_matrix_scan_rate(void) { return last_matrix_scan_count; } -#else -# define matrix_scan_perf_task() -#endif - -#ifdef MATRIX_HAS_GHOST -extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; -static matrix_row_t get_real_keys(uint8_t row, matrix_row_t rowdata) { - matrix_row_t out = 0; - for (uint8_t col = 0; col < MATRIX_COLS; col++) { - // read each key in the row data and check if the keymap defines it as a real key - if (pgm_read_byte(&keymaps[0][row][col]) && (rowdata & (1 << col))) { - // this creates new row data, if a key is defined in the keymap, it will be set here - out |= 1 << col; - } - } - return out; -} - -static inline bool popcount_more_than_one(matrix_row_t rowdata) { - rowdata &= rowdata - 1; // if there are less than two bits (keys) set, rowdata will become zero - return rowdata; -} - -static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) { - /* No ghost exists when less than 2 keys are down on the row. - If there are "active" blanks in the matrix, the key can't be pressed by the user, - there is no doubt as to which keys are really being pressed. - The ghosts will be ignored, they are KC_NO. */ - rowdata = get_real_keys(row, rowdata); - if ((popcount_more_than_one(rowdata)) == 0) { - return false; - } - /* Ghost occurs when the row shares a column line with other row, - and two columns are read on each row. Blanks in the matrix don't matter, - so they are filtered out. - If there are two or more real keys pressed and they match columns with - at least two of another row's real keys, the row will be ignored. Keep in mind, - we are checking one row at a time, not all of them at once. - */ - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - if (i != row && popcount_more_than_one(get_real_keys(i, matrix_get_row(i)) & rowdata)) { - return true; - } - } - return false; -} - -#endif - -void disable_jtag(void) { -// To use PF4-7 (PC2-5 on ATmega32A), disable JTAG by writing JTD bit twice within four cycles. -#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) - MCUCR |= _BV(JTD); - MCUCR |= _BV(JTD); -#elif defined(__AVR_ATmega32A__) - MCUCSR |= _BV(JTD); - MCUCSR |= _BV(JTD); -#endif -} - -/** \brief matrix_setup - * - * FIXME: needs doc - */ -__attribute__((weak)) void matrix_setup(void) {} - -/** \brief keyboard_pre_init_user - * - * FIXME: needs doc - */ -__attribute__((weak)) void keyboard_pre_init_user(void) {} - -/** \brief keyboard_pre_init_kb - * - * FIXME: needs doc - */ -__attribute__((weak)) void keyboard_pre_init_kb(void) { keyboard_pre_init_user(); } - -/** \brief keyboard_post_init_user - * - * FIXME: needs doc - */ - -__attribute__((weak)) void keyboard_post_init_user() {} - -/** \brief keyboard_post_init_kb - * - * FIXME: needs doc - */ - -__attribute__((weak)) void keyboard_post_init_kb(void) { keyboard_post_init_user(); } - -/** \brief keyboard_setup - * - * FIXME: needs doc - */ -void keyboard_setup(void) { -#ifndef NO_JTAG_DISABLE - disable_jtag(); -#endif - print_set_sendchar(sendchar); -#ifdef STM32_EEPROM_ENABLE - EEPROM_Init(); -#endif -#ifdef EEPROM_DRIVER - eeprom_driver_init(); -#endif - matrix_setup(); - keyboard_pre_init_kb(); -} - -/** \brief is_keyboard_master - * - * FIXME: needs doc - */ -__attribute__((weak)) bool is_keyboard_master(void) { return true; } - -/** \brief is_keyboard_left - * - * FIXME: needs doc - */ -__attribute__((weak)) bool is_keyboard_left(void) { return true; } - -/** \brief should_process_keypress - * - * Override this function if you have a condition where keypresses processing should change: - * - splits where the slave side needs to process for rgb/oled functionality - */ -__attribute__((weak)) bool should_process_keypress(void) { return is_keyboard_master(); } - -/** \brief housekeeping_task_kb - * - * Override this function if you have a need to execute code for every keyboard main loop iteration. - * This is specific to keyboard-level functionality. - */ -__attribute__((weak)) void housekeeping_task_kb(void) {} - -/** \brief housekeeping_task_user - * - * Override this function if you have a need to execute code for every keyboard main loop iteration. - * This is specific to user/keymap-level functionality. - */ -__attribute__((weak)) void housekeeping_task_user(void) {} - -/** \brief housekeeping_task - * - * Invokes hooks for executing code after QMK is done after each loop iteration. - */ -void housekeeping_task(void) { - housekeeping_task_kb(); - housekeeping_task_user(); -} - -/** \brief keyboard_init - * - * FIXME: needs doc - */ -void keyboard_init(void) { - timer_init(); - sync_timer_init(); - matrix_init(); -#if defined(CRC_ENABLE) - crc_init(); -#endif -#ifdef VIA_ENABLE - via_init(); -#endif -#ifdef QWIIC_ENABLE - qwiic_init(); -#endif -#ifdef OLED_DRIVER_ENABLE - oled_init(OLED_ROTATION_0); -#endif -#ifdef ST7565_ENABLE - st7565_init(DISPLAY_ROTATION_0); -#endif -#ifdef PS2_MOUSE_ENABLE - ps2_mouse_init(); -#endif -#ifdef SERIAL_MOUSE_ENABLE - serial_mouse_init(); -#endif -#ifdef ADB_MOUSE_ENABLE - adb_mouse_init(); -#endif -#ifdef BACKLIGHT_ENABLE - backlight_init(); -#endif -#ifdef RGBLIGHT_ENABLE - rgblight_init(); -#endif -#ifdef ENCODER_ENABLE - encoder_init(); -#endif -#ifdef STENO_ENABLE - steno_init(); -#endif -#ifdef POINTING_DEVICE_ENABLE - pointing_device_init(); -#endif -#if defined(NKRO_ENABLE) && defined(FORCE_NKRO) - keymap_config.nkro = 1; - eeconfig_update_keymap(keymap_config.raw); -#endif -#ifdef DIP_SWITCH_ENABLE - dip_switch_init(); -#endif - -#if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE) - debug_enable = true; -#endif - - keyboard_post_init_kb(); /* Always keep this last */ -} - -/** \brief key_event_task - * - * This function is responsible for calling into other systems when they need to respond to electrical switch press events. - * This is differnet than keycode events as no layer processing, or filtering occurs. - */ -void switch_events(uint8_t row, uint8_t col, bool pressed) { -#if defined(LED_MATRIX_ENABLE) - process_led_matrix(row, col, pressed); -#endif -#if defined(RGB_MATRIX_ENABLE) - process_rgb_matrix(row, col, pressed); -#endif -} - -/** \brief Keyboard task: Do keyboard routine jobs - * - * Do routine keyboard jobs: - * - * * scan matrix - * * handle mouse movements - * * run visualizer code - * * handle midi commands - * * light LEDs - * - * This is repeatedly called as fast as possible. - */ -void keyboard_task(void) { - static matrix_row_t matrix_prev[MATRIX_ROWS]; - static uint8_t led_status = 0; - matrix_row_t matrix_row = 0; - matrix_row_t matrix_change = 0; -#ifdef QMK_KEYS_PER_SCAN - uint8_t keys_processed = 0; -#endif -#ifdef ENCODER_ENABLE - bool encoders_changed = false; -#endif - - uint8_t matrix_changed = matrix_scan(); - if (matrix_changed) last_matrix_activity_trigger(); - - for (uint8_t r = 0; r < MATRIX_ROWS; r++) { - matrix_row = matrix_get_row(r); - matrix_change = matrix_row ^ matrix_prev[r]; - if (matrix_change) { -#ifdef MATRIX_HAS_GHOST - if (has_ghost_in_row(r, matrix_row)) { - continue; - } -#endif - if (debug_matrix) matrix_print(); - matrix_row_t col_mask = 1; - for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) { - if (matrix_change & col_mask) { - if (should_process_keypress()) { - action_exec((keyevent_t){ - .key = (keypos_t){.row = r, .col = c}, .pressed = (matrix_row & col_mask), .time = (timer_read() | 1) /* time should not be 0 */ - }); - } - // record a processed key - matrix_prev[r] ^= col_mask; - - switch_events(r, c, (matrix_row & col_mask)); - -#ifdef QMK_KEYS_PER_SCAN - // only jump out if we have processed "enough" keys. - if (++keys_processed >= QMK_KEYS_PER_SCAN) -#endif - // process a key per task call - goto MATRIX_LOOP_END; - } - } - } - } - // call with pseudo tick event when no real key event. -#ifdef QMK_KEYS_PER_SCAN - // we can get here with some keys processed now. - if (!keys_processed) -#endif - action_exec(TICK); - -MATRIX_LOOP_END: - -#ifdef DEBUG_MATRIX_SCAN_RATE - matrix_scan_perf_task(); -#endif - -#if defined(RGBLIGHT_ENABLE) - rgblight_task(); -#endif - -#ifdef LED_MATRIX_ENABLE - led_matrix_task(); -#endif -#ifdef RGB_MATRIX_ENABLE - rgb_matrix_task(); -#endif - -#if defined(BACKLIGHT_ENABLE) -# if defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS) - backlight_task(); -# endif -#endif - -#ifdef ENCODER_ENABLE - encoders_changed = encoder_read(); - if (encoders_changed) last_encoder_activity_trigger(); -#endif - -#ifdef QWIIC_ENABLE - qwiic_task(); -#endif - -#ifdef OLED_DRIVER_ENABLE - oled_task(); -# ifndef OLED_DISABLE_TIMEOUT - // Wake up oled if user is using those fabulous keys or spinning those encoders! -# ifdef ENCODER_ENABLE - if (matrix_changed || encoders_changed) oled_on(); -# else - if (matrix_changed) oled_on(); -# endif -# endif -#endif - -#ifdef ST7565_ENABLE - st7565_task(); -# ifndef ST7565_DISABLE_TIMEOUT - // Wake up display if user is using those fabulous keys or spinning those encoders! -# ifdef ENCODER_ENABLE - if (matrix_changed || encoders_changed) st7565_on(); -# else - if (matrix_changed) st7565_on(); -# endif -# endif -#endif - -#ifdef MOUSEKEY_ENABLE - // mousekey repeat & acceleration - mousekey_task(); -#endif - -#ifdef PS2_MOUSE_ENABLE - ps2_mouse_task(); -#endif - -#ifdef SERIAL_MOUSE_ENABLE - serial_mouse_task(); -#endif - -#ifdef ADB_MOUSE_ENABLE - adb_mouse_task(); -#endif - -#ifdef SERIAL_LINK_ENABLE - serial_link_update(); -#endif - -#ifdef VISUALIZER_ENABLE - visualizer_update(default_layer_state, layer_state, visualizer_get_mods(), host_keyboard_leds()); -#endif - -#ifdef POINTING_DEVICE_ENABLE - pointing_device_task(); -#endif - -#ifdef MIDI_ENABLE - midi_task(); -#endif - -#ifdef VELOCIKEY_ENABLE - if (velocikey_enabled()) { - velocikey_decelerate(); - } -#endif - -#ifdef JOYSTICK_ENABLE - joystick_task(); -#endif - -#ifdef DIGITIZER_ENABLE - digitizer_task(); -#endif - - // update LED - if (led_status != host_keyboard_leds()) { - led_status = host_keyboard_leds(); - keyboard_set_leds(led_status); - } -} - -/** \brief keyboard set leds - * - * FIXME: needs doc - */ -void keyboard_set_leds(uint8_t leds) { - if (debug_keyboard) { - debug("keyboard_set_led: "); - debug_hex8(leds); - debug("\n"); - } - led_set(leds); -} diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h deleted file mode 100644 index 08f4e84f94..0000000000 --- a/tmk_core/common/keyboard.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2011,2012,2013 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* key matrix position */ -typedef struct { - uint8_t col; - uint8_t row; -} keypos_t; - -/* key event */ -typedef struct { - keypos_t key; - bool pressed; - uint16_t time; -} keyevent_t; - -/* equivalent test of keypos_t */ -#define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col) - -/* Rules for No Event: - * 1) (time == 0) to handle (keyevent_t){} as empty event - * 2) Matrix(255, 255) to make TICK event available - */ -static inline bool IS_NOEVENT(keyevent_t event) { return event.time == 0 || (event.key.row == 255 && event.key.col == 255); } -static inline bool IS_PRESSED(keyevent_t event) { return (!IS_NOEVENT(event) && event.pressed); } -static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) && !event.pressed); } - -/* Tick event */ -#define TICK \ - (keyevent_t) { .key = (keypos_t){.row = 255, .col = 255}, .pressed = false, .time = (timer_read() | 1) } - -/* it runs once at early stage of startup before keyboard_init. */ -void keyboard_setup(void); -/* it runs once after initializing host side protocol, debug and MCU peripherals. */ -void keyboard_init(void); -/* it runs repeatedly in main loop */ -void keyboard_task(void); -/* it runs when host LED status is updated */ -void keyboard_set_leds(uint8_t leds); -/* it runs whenever code has to behave differently on a slave */ -bool is_keyboard_master(void); -/* it runs whenever code has to behave differently on left vs right split */ -bool is_keyboard_left(void); - -void keyboard_pre_init_kb(void); -void keyboard_pre_init_user(void); -void keyboard_post_init_kb(void); -void keyboard_post_init_user(void); - -void housekeeping_task(void); // To be executed by the main loop in each backend TMK protocol -void housekeeping_task_kb(void); // To be overridden by keyboard-level code -void housekeeping_task_user(void); // To be overridden by user/keymap-level code - -uint32_t last_input_activity_time(void); // Timestamp of the last matrix or encoder activity -uint32_t last_input_activity_elapsed(void); // Number of milliseconds since the last matrix or encoder activity - -uint32_t last_matrix_activity_time(void); // Timestamp of the last matrix activity -uint32_t last_matrix_activity_elapsed(void); // Number of milliseconds since the last matrix activity - -uint32_t last_encoder_activity_time(void); // Timestamp of the last encoder activity -uint32_t last_encoder_activity_elapsed(void); // Number of milliseconds since the last encoder activity - -uint32_t get_matrix_scan_rate(void); - -#ifdef __cplusplus -} -#endif diff --git a/tmk_core/common/keycode.h b/tmk_core/common/keycode.h deleted file mode 100644 index 8facabd818..0000000000 --- a/tmk_core/common/keycode.h +++ /dev/null @@ -1,560 +0,0 @@ -/* -Copyright 2011,2012 Jun Wako - -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, either version 2 of the License, or -(at your option) any later version. - -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 . -*/ - -/* - * Keycodes based on HID Keyboard/Keypad Usage Page (0x07) plus media keys from Generic Desktop Page (0x01) and Consumer Page (0x0C) - * - * See https://web.archive.org/web/20060218214400/http://www.usb.org/developers/devclass_docs/Hut1_12.pdf - * or http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (older) - */ - -#pragma once - -/* FIXME: Add doxygen comments here */ - -#define IS_ERROR(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED) -#define IS_ANY(code) (KC_A <= (code) && (code) <= 0xFF) -#define IS_KEY(code) (KC_A <= (code) && (code) <= KC_EXSEL) -#define IS_MOD(code) (KC_LCTRL <= (code) && (code) <= KC_RGUI) - -#define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) -#define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE) -#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_BRID) - -#define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31) - -#define IS_MOUSEKEY(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2) -#define IS_MOUSEKEY_MOVE(code) (KC_MS_UP <= (code) && (code) <= KC_MS_RIGHT) -#define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1 <= (code) && (code) <= KC_MS_BTN8) -#define IS_MOUSEKEY_WHEEL(code) (KC_MS_WH_UP <= (code) && (code) <= KC_MS_WH_RIGHT) -#define IS_MOUSEKEY_ACCEL(code) (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2) - -#define MOD_BIT(code) (1 << MOD_INDEX(code)) -#define MOD_INDEX(code) ((code)&0x07) - -#define MOD_MASK_CTRL (MOD_BIT(KC_LCTRL) | MOD_BIT(KC_RCTRL)) -#define MOD_MASK_SHIFT (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) -#define MOD_MASK_ALT (MOD_BIT(KC_LALT) | MOD_BIT(KC_RALT)) -#define MOD_MASK_GUI (MOD_BIT(KC_LGUI) | MOD_BIT(KC_RGUI)) -#define MOD_MASK_CS (MOD_MASK_CTRL | MOD_MASK_SHIFT) -#define MOD_MASK_CA (MOD_MASK_CTRL | MOD_MASK_ALT) -#define MOD_MASK_CG (MOD_MASK_CTRL | MOD_MASK_GUI) -#define MOD_MASK_SA (MOD_MASK_SHIFT | MOD_MASK_ALT) -#define MOD_MASK_SG (MOD_MASK_SHIFT | MOD_MASK_GUI) -#define MOD_MASK_AG (MOD_MASK_ALT | MOD_MASK_GUI) -#define MOD_MASK_CSA (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_ALT) -#define MOD_MASK_CSG (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_GUI) -#define MOD_MASK_CAG (MOD_MASK_CTRL | MOD_MASK_ALT | MOD_MASK_GUI) -#define MOD_MASK_SAG (MOD_MASK_SHIFT | MOD_MASK_ALT | MOD_MASK_GUI) -#define MOD_MASK_CSAG (MOD_MASK_CTRL | MOD_MASK_SHIFT | MOD_MASK_ALT | MOD_MASK_GUI) - -#define FN_BIT(code) (1 << FN_INDEX(code)) -#define FN_INDEX(code) ((code)-KC_FN0) -#define FN_MIN KC_FN0 -#define FN_MAX KC_FN31 - -/* - * Short names for ease of definition of keymap - */ -/* Transparent */ -#define KC_TRANSPARENT 0x01 -#define KC_TRNS KC_TRANSPARENT - -/* Punctuation */ -#define KC_ENT KC_ENTER -#define KC_ESC KC_ESCAPE -#define KC_BSPC KC_BSPACE -#define KC_SPC KC_SPACE -#define KC_MINS KC_MINUS -#define KC_EQL KC_EQUAL -#define KC_LBRC KC_LBRACKET -#define KC_RBRC KC_RBRACKET -#define KC_BSLS KC_BSLASH -#define KC_NUHS KC_NONUS_HASH -#define KC_SCLN KC_SCOLON -#define KC_QUOT KC_QUOTE -#define KC_GRV KC_GRAVE -#define KC_COMM KC_COMMA -#define KC_SLSH KC_SLASH -#define KC_NUBS KC_NONUS_BSLASH - -/* Lock Keys */ -#define KC_CLCK KC_CAPSLOCK -#define KC_CAPS KC_CAPSLOCK -#define KC_SLCK KC_SCROLLLOCK -#define KC_NLCK KC_NUMLOCK -#define KC_LCAP KC_LOCKING_CAPS -#define KC_LNUM KC_LOCKING_NUM -#define KC_LSCR KC_LOCKING_SCROLL - -/* Commands */ -#define KC_PSCR KC_PSCREEN -#define KC_PAUS KC_PAUSE -#define KC_BRK KC_PAUSE -#define KC_INS KC_INSERT -#define KC_DEL KC_DELETE -#define KC_PGDN KC_PGDOWN -#define KC_RGHT KC_RIGHT -#define KC_APP KC_APPLICATION -#define KC_EXEC KC_EXECUTE -#define KC_SLCT KC_SELECT -#define KC_AGIN KC_AGAIN -#define KC_PSTE KC_PASTE -#define KC_ERAS KC_ALT_ERASE -#define KC_CLR KC_CLEAR - -/* Keypad */ -#define KC_PSLS KC_KP_SLASH -#define KC_PAST KC_KP_ASTERISK -#define KC_PMNS KC_KP_MINUS -#define KC_PPLS KC_KP_PLUS -#define KC_PENT KC_KP_ENTER -#define KC_P1 KC_KP_1 -#define KC_P2 KC_KP_2 -#define KC_P3 KC_KP_3 -#define KC_P4 KC_KP_4 -#define KC_P5 KC_KP_5 -#define KC_P6 KC_KP_6 -#define KC_P7 KC_KP_7 -#define KC_P8 KC_KP_8 -#define KC_P9 KC_KP_9 -#define KC_P0 KC_KP_0 -#define KC_PDOT KC_KP_DOT -#define KC_PEQL KC_KP_EQUAL -#define KC_PCMM KC_KP_COMMA - -/* Japanese specific */ -#define KC_ZKHK KC_GRAVE -#define KC_RO KC_INT1 -#define KC_KANA KC_INT2 -#define KC_JYEN KC_INT3 -#define KC_HENK KC_INT4 -#define KC_MHEN KC_INT5 - -/* Korean specific */ -#define KC_HAEN KC_LANG1 -#define KC_HANJ KC_LANG2 - -/* Modifiers */ -#define KC_LCTL KC_LCTRL -#define KC_LSFT KC_LSHIFT -#define KC_LOPT KC_LALT -#define KC_LCMD KC_LGUI -#define KC_LWIN KC_LGUI -#define KC_RCTL KC_RCTRL -#define KC_RSFT KC_RSHIFT -#define KC_ALGR KC_RALT -#define KC_ROPT KC_RALT -#define KC_RCMD KC_RGUI -#define KC_RWIN KC_RGUI - -/* Generic Desktop Page (0x01) */ -#define KC_PWR KC_SYSTEM_POWER -#define KC_SLEP KC_SYSTEM_SLEEP -#define KC_WAKE KC_SYSTEM_WAKE - -/* Consumer Page (0x0C) */ -#define KC_MUTE KC_AUDIO_MUTE -#define KC_VOLU KC_AUDIO_VOL_UP -#define KC_VOLD KC_AUDIO_VOL_DOWN -#define KC_MNXT KC_MEDIA_NEXT_TRACK -#define KC_MPRV KC_MEDIA_PREV_TRACK -#define KC_MSTP KC_MEDIA_STOP -#define KC_MPLY KC_MEDIA_PLAY_PAUSE -#define KC_MSEL KC_MEDIA_SELECT -#define KC_EJCT KC_MEDIA_EJECT -#define KC_CALC KC_CALCULATOR -#define KC_MYCM KC_MY_COMPUTER -#define KC_WSCH KC_WWW_SEARCH -#define KC_WHOM KC_WWW_HOME -#define KC_WBAK KC_WWW_BACK -#define KC_WFWD KC_WWW_FORWARD -#define KC_WSTP KC_WWW_STOP -#define KC_WREF KC_WWW_REFRESH -#define KC_WFAV KC_WWW_FAVORITES -#define KC_MFFD KC_MEDIA_FAST_FORWARD -#define KC_MRWD KC_MEDIA_REWIND -#define KC_BRIU KC_BRIGHTNESS_UP -#define KC_BRID KC_BRIGHTNESS_DOWN - -/* System Specific */ -#define KC_BRMU KC_PAUSE -#define KC_BRMD KC_SCROLLLOCK - -/* Mouse Keys */ -#define KC_MS_U KC_MS_UP -#define KC_MS_D KC_MS_DOWN -#define KC_MS_L KC_MS_LEFT -#define KC_MS_R KC_MS_RIGHT -#define KC_BTN1 KC_MS_BTN1 -#define KC_BTN2 KC_MS_BTN2 -#define KC_BTN3 KC_MS_BTN3 -#define KC_BTN4 KC_MS_BTN4 -#define KC_BTN5 KC_MS_BTN5 -#define KC_BTN6 KC_MS_BTN6 -#define KC_BTN7 KC_MS_BTN7 -#define KC_BTN8 KC_MS_BTN8 -#define KC_WH_U KC_MS_WH_UP -#define KC_WH_D KC_MS_WH_DOWN -#define KC_WH_L KC_MS_WH_LEFT -#define KC_WH_R KC_MS_WH_RIGHT -#define KC_ACL0 KC_MS_ACCEL0 -#define KC_ACL1 KC_MS_ACCEL1 -#define KC_ACL2 KC_MS_ACCEL2 - -/* Keyboard/Keypad Page (0x07) */ -enum hid_keyboard_keypad_usage { - KC_NO = 0x00, - KC_ROLL_OVER, - KC_POST_FAIL, - KC_UNDEFINED, - KC_A, - KC_B, - KC_C, - KC_D, - KC_E, - KC_F, - KC_G, - KC_H, - KC_I, - KC_J, - KC_K, - KC_L, - KC_M, // 0x10 - KC_N, - KC_O, - KC_P, - KC_Q, - KC_R, - KC_S, - KC_T, - KC_U, - KC_V, - KC_W, - KC_X, - KC_Y, - KC_Z, - KC_1, - KC_2, - KC_3, // 0x20 - KC_4, - KC_5, - KC_6, - KC_7, - KC_8, - KC_9, - KC_0, - KC_ENTER, - KC_ESCAPE, - KC_BSPACE, - KC_TAB, - KC_SPACE, - KC_MINUS, - KC_EQUAL, - KC_LBRACKET, - KC_RBRACKET, // 0x30 - KC_BSLASH, - KC_NONUS_HASH, - KC_SCOLON, - KC_QUOTE, - KC_GRAVE, - KC_COMMA, - KC_DOT, - KC_SLASH, - KC_CAPSLOCK, - KC_F1, - KC_F2, - KC_F3, - KC_F4, - KC_F5, - KC_F6, - KC_F7, // 0x40 - KC_F8, - KC_F9, - KC_F10, - KC_F11, - KC_F12, - KC_PSCREEN, - KC_SCROLLLOCK, - KC_PAUSE, - KC_INSERT, - KC_HOME, - KC_PGUP, - KC_DELETE, - KC_END, - KC_PGDOWN, - KC_RIGHT, - KC_LEFT, // 0x50 - KC_DOWN, - KC_UP, - KC_NUMLOCK, - KC_KP_SLASH, - KC_KP_ASTERISK, - KC_KP_MINUS, - KC_KP_PLUS, - KC_KP_ENTER, - KC_KP_1, - KC_KP_2, - KC_KP_3, - KC_KP_4, - KC_KP_5, - KC_KP_6, - KC_KP_7, - KC_KP_8, // 0x60 - KC_KP_9, - KC_KP_0, - KC_KP_DOT, - KC_NONUS_BSLASH, - KC_APPLICATION, - KC_POWER, - KC_KP_EQUAL, - KC_F13, - KC_F14, - KC_F15, - KC_F16, - KC_F17, - KC_F18, - KC_F19, - KC_F20, - KC_F21, // 0x70 - KC_F22, - KC_F23, - KC_F24, - KC_EXECUTE, - KC_HELP, - KC_MENU, - KC_SELECT, - KC_STOP, - KC_AGAIN, - KC_UNDO, - KC_CUT, - KC_COPY, - KC_PASTE, - KC_FIND, - KC__MUTE, - KC__VOLUP, // 0x80 - KC__VOLDOWN, - KC_LOCKING_CAPS, - KC_LOCKING_NUM, - KC_LOCKING_SCROLL, - KC_KP_COMMA, - KC_KP_EQUAL_AS400, - KC_INT1, - KC_INT2, - KC_INT3, - KC_INT4, - KC_INT5, - KC_INT6, - KC_INT7, - KC_INT8, - KC_INT9, - KC_LANG1, // 0x90 - KC_LANG2, - KC_LANG3, - KC_LANG4, - KC_LANG5, - KC_LANG6, - KC_LANG7, - KC_LANG8, - KC_LANG9, - KC_ALT_ERASE, - KC_SYSREQ, - KC_CANCEL, - KC_CLEAR, - KC_PRIOR, - KC_RETURN, - KC_SEPARATOR, - KC_OUT, // 0xA0 - KC_OPER, - KC_CLEAR_AGAIN, - KC_CRSEL, - KC_EXSEL, - -#if 0 - // *************************************************************** - // These keycodes are present in the HID spec, but are * - // nonfunctional on modern OSes. QMK uses this range (0xA5-0xDF) * - // for the media and function keys instead - see below. * - // *************************************************************** - - KC_KP_00 = 0xB0, - KC_KP_000, - KC_THOUSANDS_SEPARATOR, - KC_DECIMAL_SEPARATOR, - KC_CURRENCY_UNIT, - KC_CURRENCY_SUB_UNIT, - KC_KP_LPAREN, - KC_KP_RPAREN, - KC_KP_LCBRACKET, - KC_KP_RCBRACKET, - KC_KP_TAB, - KC_KP_BSPACE, - KC_KP_A, - KC_KP_B, - KC_KP_C, - KC_KP_D, - KC_KP_E, //0xC0 - KC_KP_F, - KC_KP_XOR, - KC_KP_HAT, - KC_KP_PERC, - KC_KP_LT, - KC_KP_GT, - KC_KP_AND, - KC_KP_LAZYAND, - KC_KP_OR, - KC_KP_LAZYOR, - KC_KP_COLON, - KC_KP_HASH, - KC_KP_SPACE, - KC_KP_ATMARK, - KC_KP_EXCLAMATION, - KC_KP_MEM_STORE, //0xD0 - KC_KP_MEM_RECALL, - KC_KP_MEM_CLEAR, - KC_KP_MEM_ADD, - KC_KP_MEM_SUB, - KC_KP_MEM_MUL, - KC_KP_MEM_DIV, - KC_KP_PLUS_MINUS, - KC_KP_CLEAR, - KC_KP_CLEAR_ENTRY, - KC_KP_BINARY, - KC_KP_OCTAL, - KC_KP_DECIMAL, - KC_KP_HEXADECIMAL, -#endif - - /* Modifiers */ - KC_LCTRL = 0xE0, - KC_LSHIFT, - KC_LALT, - KC_LGUI, - KC_RCTRL, - KC_RSHIFT, - KC_RALT, - KC_RGUI - - // ********************************************** - // * 0xF0-0xFF are unallocated in the HID spec. * - // * QMK uses these for Mouse Keys - see below. * - // ********************************************** -}; - -/* Media and Function keys */ -enum internal_special_keycodes { - /* Generic Desktop Page (0x01) */ - KC_SYSTEM_POWER = 0xA5, - KC_SYSTEM_SLEEP, - KC_SYSTEM_WAKE, - - /* Consumer Page (0x0C) */ - KC_AUDIO_MUTE, - KC_AUDIO_VOL_UP, - KC_AUDIO_VOL_DOWN, - KC_MEDIA_NEXT_TRACK, - KC_MEDIA_PREV_TRACK, - KC_MEDIA_STOP, - KC_MEDIA_PLAY_PAUSE, - KC_MEDIA_SELECT, - KC_MEDIA_EJECT, // 0xB0 - KC_MAIL, - KC_CALCULATOR, - KC_MY_COMPUTER, - KC_WWW_SEARCH, - KC_WWW_HOME, - KC_WWW_BACK, - KC_WWW_FORWARD, - KC_WWW_STOP, - KC_WWW_REFRESH, - KC_WWW_FAVORITES, - KC_MEDIA_FAST_FORWARD, - KC_MEDIA_REWIND, - KC_BRIGHTNESS_UP, - KC_BRIGHTNESS_DOWN, - - /* Fn keys */ - KC_FN0 = 0xC0, - KC_FN1, - KC_FN2, - KC_FN3, - KC_FN4, - KC_FN5, - KC_FN6, - KC_FN7, - KC_FN8, - KC_FN9, - KC_FN10, - KC_FN11, - KC_FN12, - KC_FN13, - KC_FN14, - KC_FN15, - KC_FN16, // 0xD0 - KC_FN17, - KC_FN18, - KC_FN19, - KC_FN20, - KC_FN21, - KC_FN22, - KC_FN23, - KC_FN24, - KC_FN25, - KC_FN26, - KC_FN27, - KC_FN28, - KC_FN29, - KC_FN30, - KC_FN31 -}; - -enum mouse_keys { -/* Mouse Buttons */ -#ifdef VIA_ENABLE - KC_MS_UP = 0xF0, -#else - KC_MS_UP = 0xED, -#endif - KC_MS_DOWN, - KC_MS_LEFT, - KC_MS_RIGHT, // 0xF0 - KC_MS_BTN1, - KC_MS_BTN2, - KC_MS_BTN3, - KC_MS_BTN4, - KC_MS_BTN5, -#ifdef VIA_ENABLE - KC_MS_BTN6 = KC_MS_BTN5, - KC_MS_BTN7 = KC_MS_BTN5, - KC_MS_BTN8 = KC_MS_BTN5, -#else - KC_MS_BTN6, - KC_MS_BTN7, - KC_MS_BTN8, -#endif - - /* Mouse Wheel */ - KC_MS_WH_UP, - KC_MS_WH_DOWN, - KC_MS_WH_LEFT, - KC_MS_WH_RIGHT, - - /* Acceleration */ - KC_MS_ACCEL0, - KC_MS_ACCEL1, - KC_MS_ACCEL2 // 0xFF -}; -- cgit v1.2.3