qmk_userspace/users/ncsibra/tap_hold.c
2024-11-02 14:45:14 +01:00

83 lines
No EOL
3 KiB
C

#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;
}
}
}