put features to separate files

This commit is contained in:
Norbert Csibra 2024-11-02 14:44:58 +01:00
parent 568e2f86ad
commit 1c39a28ca0
8 changed files with 440 additions and 94 deletions

View file

@ -15,4 +15,6 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_NUM] = LAYOUT_wrapper(NUM_LAYER),
[_WOW] = LAYOUT_wrapper(WOW_LAYER),
[_MOD] = LAYOUT_wrapper(MOD_LAYER),
};

View file

@ -1,20 +1,6 @@
#include "ncsibra.h"
// Tap hold keys
static taphold_t th_events[] = {
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_ESC, .kc_hold = KC_F11 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_1, .kc_hold = KC_F1 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_2, .kc_hold = KC_F2 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_3, .kc_hold = KC_F3 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_4, .kc_hold = KC_F4 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_5, .kc_hold = KC_F5 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_6, .kc_hold = KC_F6 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_7, .kc_hold = KC_F7 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_8, .kc_hold = KC_F8 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_9, .kc_hold = KC_F9 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_0, .kc_hold = KC_F10 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_BSPC, .kc_hold = KC_F12 },
};
#include "osl.h"
#include "tap_hold.h"
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// if keycode is ESC or at least contains ESC(in case of Mod Tap etc) and one shot modifier or one shot layer is active, then cancel
@ -25,62 +11,10 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
return false;
}
return process_record_user_taphold(keycode, record);
return process_record_user_taphold(keycode, record) &&
process_record_user_osl(keycode, record);
};
static uint16_t prev_th_key = KC_NO;
static uint16_t prev_th_time = 0;
bool process_record_user_taphold(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
matrix_scan_tap_hold(TAPPED);
}
if (keycode < TH_FIRST || keycode > TH_LAST) { return true; }
taphold_t *th_event = &th_events[keycode - TH_FIRST];
// if pressed twice fast, hold KC_TAP instead of usual logic, Mod Tap functionality works similarly
if (record->event.pressed) {
if (keycode == prev_th_key && timer_elapsed(prev_th_time) < TH_DELAY) {
register_code16(th_event->kc_tap);
th_event->is_double = true;
return false;
} else {
prev_th_key = keycode;
prev_th_time = timer_read();
}
}
if (record->event.pressed) {
th_event->timer = timer_read();
th_event->is_pressed = true;
} else if (th_event->is_pressed) {
register_code16(th_event->kc_tap);
unregister_code16(th_event->kc_tap);
th_event->is_pressed = false;
} else if (th_event->is_double) {
unregister_code16(th_event->kc_tap);
th_event->is_double = false;
}
return false;
}
void matrix_scan_tap_hold(taphold_state state) {
for (uint8_t index = 0 ; index < TH_EVENTS_COUNT ; ++index ) {
taphold_t *th_event = &th_events[index];
if (!th_event->is_pressed) { continue; }
if (state == TAPPED || timer_elapsed(th_event->timer) > TH_DELAY) {
uint16_t code = state == HELD ? th_event->kc_hold : th_event->kc_tap;
register_code16(code);
unregister_code16(code);
th_event->is_pressed = false;
}
}
}
void matrix_scan_user(void) {
matrix_scan_tap_hold(HELD);
}

View file

@ -18,7 +18,8 @@ enum layers {
_LOWER,
_RAISE,
_NUM,
_WOW
_WOW,
_MOD,
};
enum keycodes {
@ -41,6 +42,15 @@ enum keycodes {
TH_0,
TH_BSPC,
// Custom oneshot layer implementation.
OSL_MOD_LAYER,
// Custom oneshot mods implementation.
OSM_SHFT,
OSM_CTRL,
OSM_ALT,
OSM_GUI,
NEW_SAFE_RANGE
};
@ -81,7 +91,7 @@ enum keycodes {
#define RAISE_LAYER \
QK_BOOT, XXXXXXX, XXXXXXX, XXXXXXX, DF(_QWERTY), XXXXXXX, XXXXXXX, DF(_COLEMAK), XXXXXXX, XXXXXXX, XXXXXXX, TO(_WOW), \
DB_TOGG, XXXXXXX, XXXXXXX, KC_LSFT, XXXXXXX, XXXXXXX, XXXXXXX, KC_HOME, KC_UP, KC_END, XXXXXXX, KC_DEL, \
_______, KC_LGUI, KC_LALT, XXXXXXX, KC_LCTL, XXXXXXX, XXXXXXX, KC_LEFT, KC_DOWN, KC_RIGHT, XXXXXXX, _______, \
_______, KC_LGUI, KC_LALT, KC_LSFT, KC_LCTL, XXXXXXX, XXXXXXX, KC_LEFT, KC_DOWN, KC_RIGHT, XXXXXXX, _______, \
KC_CAPS, _______, _______, _______, _______, _______, XXXXXXX, KC_PGUP, XXXXXXX, KC_PGDN, XXXXXXX, _______, \
_______, _______, _______, _______, _______, LCTL(KC_SPC), _______, _______, _______, TG(_RAISE), _______, _______
@ -101,25 +111,10 @@ enum keycodes {
KC_LSFT, KC_Z, KC_X, KC_N, KC_C, KC_V, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, \
KC_M, KC_Y, KC_LALT, KC_LCTL, KC_SPC, KC_P, KC_BSPC, KC_DEL, KC_DEL, KC_LGUI, KC_PSCR, TO(_COLEMAK)
// tap-hold settings
#define TH_DELAY 300
#define TH_EVENTS_COUNT 12
#define TH_FIRST TH_ESC
#define TH_LAST TH_BSPC
typedef struct {
bool is_pressed;
bool is_double;
uint16_t timer;
uint16_t kc_tap;
uint16_t kc_hold;
} taphold_t;
typedef enum {
TAPPED,
HELD,
} taphold_state;
void matrix_scan_tap_hold(taphold_state state);
bool process_record_user_taphold(uint16_t keycode, keyrecord_t *record);
#define MOD_LAYER \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, OSM_SHFT, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, OSM_GUI, OSM_ALT, OSM_SHFT, OSM_CTRL, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, OSL_MOD_LAYER

318
users/ncsibra/osl.c Normal file
View file

@ -0,0 +1,318 @@
#include QMK_KEYBOARD_H
#include "ncsibra.h"
// copied from https://github.com/Exidex/qmk_firmware/blob/custom/keyboards/beekeeb/piantor_pro/readme.md
// ================ mostly callum's oneshot mods
typedef enum {
osl_up_unqueued, // default, waiting for layer to be pressed
osl_up_queued, // layer pressed and released without pressing mod key, next modifier press will have layer enabled, on all mod release layer will be disabled
osl_up_pending_used, // layer was pressed but released when some mods were still held, on all mod release layer will be disabled
osl_down_unused, // layer pressed and held, all mod presses will have layer enabled, until all mods are released
osl_down_pending_used, // layer pressed and held, some mods are still pressed
osl_down_used, // mods were pressed but layer is still held, on layer release layer will be disabled
} oneshot_layer_state;
typedef enum {
osm_up_unqueued, // default, waiting for mod to be pressed
osm_down_unused, // mod pressed and held, all other presses will be with this modifier enabled, until mod released
osm_down_used, // other key pressed while mod is held, on mod release modifier will be disabled
osm_up_queued, // mod pressed and released without pressing other key, next press will have modifier enabled
osm_up_queued_with_layer, // other key pressed abd released while layer and mod are active, next presses will have modifier enabled until layer is released
} oneshot_mod_state;
oneshot_mod_state osm_shift_state = osm_up_unqueued;
oneshot_mod_state osm_ctrl_state = osm_up_unqueued;
oneshot_mod_state osm_alt_state = osm_up_unqueued;
oneshot_mod_state osm_gui_state = osm_up_unqueued;
bool is_oneshot_cancel_key(uint16_t keycode) {
switch (keycode) {
case MO(_LOWER):
case TT(_RAISE):
return true;
default:
return false;
}
}
bool is_oneshot_ignored_key(uint16_t keycode) {
switch (keycode) {
case OSL_MOD_LAYER:
case OSM_SHFT:
case OSM_CTRL:
case OSM_ALT:
case OSM_GUI:
return true;
default:
return false;
}
}
void update_oneshot_mod(
oneshot_layer_state *layer_state,
oneshot_mod_state *mod_state,
uint16_t mod,
uint16_t trigger,
uint16_t keycode,
keyrecord_t *record
) {
if (keycode == trigger) {
if (record->event.pressed) {
// Trigger keydown
if (*mod_state == osm_up_unqueued) {
register_code(mod);
}
*mod_state = osm_down_unused;
} else {
// Trigger keyup
switch (*mod_state) {
case osm_down_unused:
// If we didn't use the mod while trigger was held, queue it.
*mod_state = osm_up_queued;
break;
case osm_down_used:
// If we did use the mod while trigger was held, unregister it.
*mod_state = osm_up_unqueued;
unregister_code(mod);
// uprintf("0x%04X unregister_code up trigger\n", keycode);
break;
default:
break;
}
}
} else {
if (record->event.pressed) {
if (is_oneshot_cancel_key(keycode) && *mod_state != osm_up_unqueued) {
// Cancel oneshot on designated cancel keydown.
*mod_state = osm_up_unqueued;
unregister_code(mod);
// uprintf("0x%04X unregister_code down non-trigger\n", keycode);
}
} else {
if (!is_oneshot_ignored_key(keycode)) {
// On non-ignored keyup, mark the oneshot as used.
switch (*mod_state) {
case osm_down_unused:
*mod_state = osm_down_used;
break;
case osm_up_queued:
switch (*layer_state) {
case osl_up_pending_used: // because some other mod is still pressed
case osl_down_unused:
case osl_down_pending_used:
case osl_down_used:
*mod_state = osm_up_queued_with_layer;
break;
default:
*mod_state = osm_up_unqueued;
unregister_code(mod);
break;
}
break;
default:
break;
}
}
}
}
}
// ================ my oneshot layers
oneshot_layer_state osl_mod_state = osl_up_unqueued;
uint16_t pressed_one_shot_mods = 0;
#define CUSTOM_ONE_SHOT_MOD_GET_MODS(kc) ((kc)&0x1F)
bool is_oneshot_mod_key(uint16_t keycode) {
switch (keycode) {
case OSM_SHFT:
case OSM_CTRL:
case OSM_ALT:
case OSM_GUI:
return true;
default:
return false;
}
}
void update_oneshot_layer(
oneshot_layer_state *layer_state,
oneshot_mod_state *shift_state,
oneshot_mod_state *ctrl_state,
oneshot_mod_state *alt_state,
oneshot_mod_state *gui_state,
uint16_t trigger,
uint16_t layer,
uint16_t keycode,
keyrecord_t *record
) {
if (keycode == trigger) {
if (record->event.pressed) {
if (*layer_state == osl_up_unqueued) {
layer_on(layer);
}
*layer_state = osl_down_unused;
} else {
switch (*layer_state) {
case osl_down_unused:
*layer_state = osl_up_queued;
break;
case osl_down_used:
*layer_state = osl_up_unqueued;
layer_off(layer);
{
if (*shift_state == osm_up_queued_with_layer) {
*shift_state = osm_up_unqueued;
unregister_code(KC_LSFT);
}
if (*ctrl_state == osm_up_queued_with_layer) {
*ctrl_state = osm_up_unqueued;
unregister_code(KC_LCTL);
}
if (*alt_state == osm_up_queued_with_layer) {
*alt_state = osm_up_unqueued;
unregister_code(KC_LALT);
}
if (*gui_state == osm_up_queued_with_layer) {
*gui_state = osm_up_unqueued;
unregister_code(KC_LGUI);
}
}
break;
case osl_down_pending_used:
*layer_state = osl_up_pending_used;
break;
default:
break;
}
}
} else {
if (record->event.pressed) {
if (is_oneshot_mod_key(keycode)) {
pressed_one_shot_mods |= CUSTOM_ONE_SHOT_MOD_GET_MODS(keycode);
}
} else {
if (is_oneshot_mod_key(keycode)) {
pressed_one_shot_mods &= CUSTOM_ONE_SHOT_MOD_GET_MODS(~(CUSTOM_ONE_SHOT_MOD_GET_MODS(keycode)));
}
switch (*layer_state) {
case osl_down_pending_used:
case osl_down_unused:
if (is_oneshot_mod_key(keycode)) {
if (pressed_one_shot_mods) {
*layer_state = osl_down_pending_used;
} else {
*layer_state = osl_down_used;
layer_off(layer);
}
}
break;
case osl_up_queued:
case osl_up_pending_used:
if (is_oneshot_mod_key(keycode)) {
if (pressed_one_shot_mods) {
*layer_state = osl_up_pending_used;
} else {
*layer_state = osl_up_unqueued;
layer_off(layer);
}
}
break;
default:
break;
}
}
}
}
// ==============
//const char* oneshot_layer_state_string(oneshot_layer_state value) {
// switch (value) {
// case osl_up_unqueued: return "osl_up_unqueued";
// case osl_up_queued: return "osl_up_queued";
// case osl_up_pending_used: return "osl_up_pending_used";
// case osl_down_unused: return "osl_down_unused";
// case osl_down_pending_used: return "osl_down_pending_used";
// case osl_down_used: return "osl_down_used";
// default: return "-----";
// }
//}
//
//const char* oneshot_mod_state_string(oneshot_mod_state value) {
// switch (value) {
// case osm_up_unqueued: return "osm_up_unqueued";
// case osm_down_unused: return "osm_down_unused";
// case osm_down_used: return "osm_down_used";
// case osm_up_queued: return "osm_up_queued";
// case osm_up_queued_with_layer: return "osm_up_queued_with_layer";
// default: return "-----";
// }
//}
bool process_record_user_osl(uint16_t keycode, keyrecord_t *record) {
// uprintf("\n");
// uprintf("\n");
//
// uprintf("%s %s %s %s %s \n", oneshot_layer_state_string(osl_mod_state), oneshot_mod_state_string(osm_shift_state), oneshot_mod_state_string(osm_ctrl_state), oneshot_mod_state_string(osm_alt_state), oneshot_mod_state_string(osm_gui_state));
update_oneshot_mod(
&osl_mod_state,
&osm_shift_state,
KC_LSFT,
OSM_SHFT,
keycode,
record
);
update_oneshot_mod(
&osl_mod_state,
&osm_ctrl_state,
KC_LCTL,
OSM_CTRL,
keycode,
record
);
update_oneshot_mod(
&osl_mod_state,
&osm_alt_state,
KC_LALT,
OSM_ALT,
keycode,
record
);
update_oneshot_mod(
&osl_mod_state,
&osm_gui_state,
KC_LGUI,
OSM_GUI,
keycode,
record
);
update_oneshot_layer(
&osl_mod_state,
&osm_shift_state,
&osm_ctrl_state,
&osm_alt_state,
&osm_gui_state,
OSL_MOD_LAYER,
_MOD,
keycode,
record
);
// uprintf("%s %s %s %s %s \n", oneshot_layer_state_string(osl_mod_state), oneshot_mod_state_string(osm_shift_state), oneshot_mod_state_string(osm_ctrl_state), oneshot_mod_state_string(osm_alt_state), oneshot_mod_state_string(osm_gui_state));
return true;
}

3
users/ncsibra/osl.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
bool process_record_user_osl(uint16_t keycode, keyrecord_t *record);

View file

@ -1,4 +1,6 @@
SRC += ncsibra.c
SRC += ncsibra.c \
osl.c \
tap_hold.c
CONSOLE_ENABLE = yes
NKRO_ENABLE = yes

83
users/ncsibra/tap_hold.c Normal file
View file

@ -0,0 +1,83 @@
#include QMK_KEYBOARD_H
#include "ncsibra.h"
#include "tap_hold.h"
#define TH_DELAY 300
#define TH_EVENTS_COUNT 12
#define TH_FIRST TH_ESC
#define TH_LAST TH_BSPC
typedef struct {
bool is_pressed;
bool is_double;
uint16_t timer;
uint16_t kc_tap;
uint16_t kc_hold;
} taphold_t;
static uint16_t prev_th_key = KC_NO;
static uint16_t prev_th_time = 0;
static taphold_t th_events[] = {
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_ESC, .kc_hold = KC_F11 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_1, .kc_hold = KC_F1 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_2, .kc_hold = KC_F2 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_3, .kc_hold = KC_F3 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_4, .kc_hold = KC_F4 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_5, .kc_hold = KC_F5 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_6, .kc_hold = KC_F6 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_7, .kc_hold = KC_F7 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_8, .kc_hold = KC_F8 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_9, .kc_hold = KC_F9 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_0, .kc_hold = KC_F10 },
{ .is_pressed = false, .is_double = false, .timer = 0, .kc_tap = KC_BSPC, .kc_hold = KC_F12 },
};
bool process_record_user_taphold(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
matrix_scan_tap_hold(TAPPED);
}
if (keycode < TH_FIRST || keycode > TH_LAST) { return true; }
taphold_t *th_event = &th_events[keycode - TH_FIRST];
// if pressed twice fast, hold KC_TAP instead of usual logic, Mod Tap functionality works similarly
if (record->event.pressed) {
if (keycode == prev_th_key && timer_elapsed(prev_th_time) < TH_DELAY) {
register_code16(th_event->kc_tap);
th_event->is_double = true;
return false;
} else {
prev_th_key = keycode;
prev_th_time = timer_read();
}
}
if (record->event.pressed) {
th_event->timer = timer_read();
th_event->is_pressed = true;
} else if (th_event->is_pressed) {
register_code16(th_event->kc_tap);
unregister_code16(th_event->kc_tap);
th_event->is_pressed = false;
} else if (th_event->is_double) {
unregister_code16(th_event->kc_tap);
th_event->is_double = false;
}
return false;
}
void matrix_scan_tap_hold(taphold_state state) {
for (uint8_t index = 0 ; index < TH_EVENTS_COUNT ; ++index ) {
taphold_t *th_event = &th_events[index];
if (!th_event->is_pressed) { continue; }
if (state == TAPPED || timer_elapsed(th_event->timer) > TH_DELAY) {
uint16_t code = state == HELD ? th_event->kc_hold : th_event->kc_tap;
register_code16(code);
unregister_code16(code);
th_event->is_pressed = false;
}
}
}

9
users/ncsibra/tap_hold.h Normal file
View file

@ -0,0 +1,9 @@
#pragma once
typedef enum {
TAPPED,
HELD,
} taphold_state;
void matrix_scan_tap_hold(taphold_state state);
bool process_record_user_taphold(uint16_t keycode, keyrecord_t *record);