custom Caps Word

This commit is contained in:
Kawamashi 2025-10-12 10:43:42 +02:00
commit de60c2ca80
70 changed files with 1302 additions and 4552 deletions

View file

@ -171,9 +171,9 @@ void get_clever_keycode(uint16_t* ongoing_keycode, keyrecord_t* record) {
// "beaucoup"
return finish_word((uint16_t[]) {PG_E, PG_A, PG_U, PG_C, PG_O, PG_U, PG_P}, 7, ongoing_keycode, record);
case PG_D:
/* case PG_D:
// "déjà"
return finish_word((uint16_t[]) {PG_EACU, PG_J, PG_ODK, PG_A}, 4, ongoing_keycode, record);
return finish_word((uint16_t[]) {PG_EACU, PG_J, PG_ODK, PG_A}, 4, ongoing_keycode, record); */
default:
// "à"
@ -185,10 +185,10 @@ void get_clever_keycode(uint16_t* ongoing_keycode, keyrecord_t* record) {
if (!is_letter(get_recent_keycode(-2))) {
switch (prev_keycode) {
case PG_P:
/* case PG_P:
// "p@" -> "problème"
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_R, PG_O, PG_B, PG_L, PG_ODK, PG_E, PG_M, PG_E}, 8, ongoing_keycode, record);
return finish_word((uint16_t[]) {PG_R, PG_O, PG_B, PG_L, PG_ODK, PG_E, PG_M, PG_E}, 8, ongoing_keycode, record); */
case PG_A:
// "a@" -> "aujourd'hui"
@ -207,14 +207,27 @@ void get_clever_keycode(uint16_t* ongoing_keycode, keyrecord_t* record) {
break;
case PG_H:
if (prev_keycode == PG_M) {
switch (prev_keycode) {
case PG_M:
case PG_R:
case PG_A:
case PG_E:
case PG_EACU:
case PG_I:
case PG_O:
case PG_U:
case PG_Y:
update_bkspc_countdown(0);
return replace_ongoing_key(PG_B, ongoing_keycode, record);
}
/* if (prev_keycode == PG_M) {
// "mh" -> "mb"
update_bkspc_countdown(0);
return replace_ongoing_key(PG_B, ongoing_keycode, record);
} else if (prev_keycode == PG_I) {
// "ih" -> "ique"
return finish_word((uint16_t[]) {PG_Q, PG_U, PG_E}, 3, ongoing_keycode, record);
}
} */
break;
case OU_GRV:
@ -241,4 +254,9 @@ void get_clever_keycode(uint16_t* ongoing_keycode, keyrecord_t* record) {
caps_word_off();
return true;
*/
*/
/* record->keycode = S(ongoing_keycode);
processingCK = true;
if (caps_word_press_user(ongoing_keycode, record)) { processingCK = true; } */

View file

@ -62,8 +62,10 @@
//#define ONESHOT_TAP_TOGGLE 5 /* Tapping this number of times holds the key until tapped once again. */
//#define ONESHOT_TIMEOUT 5000 /* Time (in ms) before the one shot key is released */
// Recent keys
#define RECENT_KEYS_TIMEOUT 5000 // Timeout in milliseconds.
// Timeouts in milliseconds.
#define RECENT_KEYS_TIMEOUT 5000
#define CAPS_WORD_IDLE_TIMEOUT 5000
#define OS4A_EXIT_TIMEOUT 3000
//Faire de la place !

View file

@ -1,12 +1,33 @@
#include "capslist.h"
static bool caps_word_active = false;
static bool caps_list_active = false;
static signed char capslist_countdown = 1;
static unsigned char countdown_end = 6;
static uint16_t idle_timer = 0;
void caps_word_task(void) {
if (caps_word_active && timer_expired(timer_read(), idle_timer)) {
caps_word_off();
}
}
bool is_caps_word_on(void) { return caps_word_active; }
bool is_caps_list_on(void) { return caps_list_active; }
void enable_caps_list(void) {
void caps_word_on(void) {
if (caps_word_active) { return; }
clear_mods();
clear_oneshot_mods();
idle_timer = timer_read() + CAPS_WORD_IDLE_TIMEOUT;
caps_word_active = true;
}
void caps_list_on(void) {
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
caps_word_on();
caps_list_active = true;
@ -14,16 +35,31 @@ void enable_caps_list(void) {
countdown_end = 6;
}
void disable_caps_list(void) {
void caps_word_off(void) {
if (!caps_word_active) { return; }
unregister_weak_mods(MOD_BIT(KC_LSFT)); // Make sure weak shift is off.
caps_word_active = false;
}
void caps_list_off(void) {
caps_word_off();
caps_list_active = false;
}
void toggle_caps_list(void) {
void caps_word_toggle(void) {
if (caps_word_active) {
caps_word_off();
} else {
caps_word_on();
}
}
void caps_list_toggle(void) {
if (caps_list_active) {
disable_caps_list();
caps_list_off();
} else {
enable_caps_list();
caps_list_on();
}
}
@ -40,14 +76,100 @@ bool word_check(uint16_t keycodes[], uint8_t num_keycodes, unsigned char new_cou
return true;
}
bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
if (keycode == CAPSWORD) {
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
if (record->event.pressed) {
// Deactivating Caps Lock and Caps List when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
if (is_caps_list_on()) { caps_list_off(); }
caps_word_toggle();
}
return false;
} else if (keycode == KC_CAPS) {
if (record->event.pressed) {
caps_word_off();
caps_list_off();
}
return true;
}
if (!caps_word_active) { return true; }
// Caps word is active //
clear_weak_mods();
// No action on keyrelease
if (!record->event.pressed) { return true; }
const uint8_t mods = get_mods() | get_oneshot_mods();
if (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR))) {
// Avoid interfering with ctrl, alt and gui.
caps_word_off();
return true;
}
idle_timer = record->event.time + CAPS_WORD_IDLE_TIMEOUT;
if (was_keycode_replaced()) {
keycode = get_recent_keycode(-1);
} else {
switch (keycode) {
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
return true;
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
// Earlier return if this has not been considered tapped yet
if (record->tap.count == 0) { return true; }
keycode = tap_hold_extractor(keycode); // Get tapping keycode.
break;
}
}
//clear_weak_mods();
if (caps_word_press_user(keycode)) {
// Invert on shift
if (get_oneshot_mods() & MOD_MASK_SHIFT) {
set_weak_mods(get_weak_mods() ^ MOD_BIT(KC_LSFT));
del_oneshot_mods(MOD_MASK_SHIFT);
}
send_keyboard_report();
return true;
}
caps_word_off();
return true;
}
bool process_caps_list(uint16_t keycode, keyrecord_t *record) {
// Handle the custom keycodes that go with this feature
if (keycode == CAPSLIST) {
if (record->event.pressed) {
toggle_caps_list();
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
caps_list_toggle();
}
return false;
}
/* if (keycode == CAPSWORD) {
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
if (record->event.pressed) {
// Deactivating Caps Lock and Caps List when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
if (is_caps_list_on()) { caps_list_off(); }
caps_word_toggle();
}
return false;
} else if (keycode == KC_CAPS) {
if (record->event.pressed) {
caps_word_off();
caps_list_off();
}
return true;
} */
// Other than the custom keycodes, nothing else in this feature will activate
// if the behavior is not on, so allow QMK to handle the event as usual.
@ -57,6 +179,13 @@ bool process_caps_list(uint16_t keycode, keyrecord_t *record) {
// If Caps Word is on, Caps List stays on as well.
if (is_caps_word_on()) { return true; }
const uint8_t mods = get_mods() | get_oneshot_mods();
if (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR))) {
// Avoid interfering with ctrl, alt and gui.
caps_word_off();
return true;
}
// Get the base keycode of a mod or layer tap key
switch (keycode) {
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
@ -78,6 +207,6 @@ bool process_caps_list(uint16_t keycode, keyrecord_t *record) {
}
if (capslist_countdown < countdown_end) { return true; }
}
disable_caps_list();
caps_list_off();
return true;
}

View file

@ -6,9 +6,9 @@
bool is_caps_list_on(void);
void enable_caps_list(void);
void disable_caps_list(void);
void toggle_caps_list(void);
void caps_list_on(void);
void caps_list_off(void);
void caps_list_toggle(void);
bool update_capslist_countdown(signed char i);
bool word_check(uint16_t keycodes[], uint8_t num_keycodes, unsigned char new_countdown_end);
@ -16,4 +16,190 @@ bool word_check(uint16_t keycodes[], uint8_t num_keycodes, unsigned char new_cou
bool process_caps_list(uint16_t keycode, keyrecord_t *record);
bool should_continue_caps_list(uint16_t keycode);
bool caps_word_reactivation(void);
bool caps_word_reactivation(void);
// Copyright 2021-2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @file caps_word.h
* @brief Caps Word, a modern alternative to Caps Lock
*
* Overview
* --------
*
* @note Caps Word is now a core QMK feature! See
* <https://docs.qmk.fm/features/caps_word>
*
* This library implements "Caps Word", which is like conventional Caps Lock,
* but automatically disables itself at the end of the word. This is useful for
* typing all-caps identifiers like `MOD_MASK_ALT`.
*
* Caps Word is activated by pressing the left and right shift keys at the same
* time. This way you don't need a dedicated key for using Caps Word. I've
* tested that this works as expected with one-shot mods and Space Cadet Shift.
* If your shift keys are mod-taps, activate Caps Word by holding both shift
* mod-tap keys until the tapping term, release them, then begin typing.
* Alternatively, you can call `caps_word_on()` to activate Caps Word from a
* combo, tap dance, or other means.
*
* Configuration
* -------------
*
* Word-breaking keys:
* Use the `caps_word_press_user()` callback to define whether a key should
* continue Caps Word or "break the word" and stop Caps Word.
*
* Representing state:
* Use `caps_word_set_user()` callback to know when Caps Word turns on and off,
* for instance to use an LED to indicate when Caps Word is active.
*
* Idle timout:
* Optionally, Caps Word may be configured to deactivate if the keyboard is idle
* for some time. This is useful to mitigate unintended shifting when you get
* interrupted or switch to the mouse while Caps Word is active. In your
* config.h, define `CAPS_WORD_IDLE_TIMEOUT` with a time in milliseconds:
*
* #define CAPS_WORD_IDLE_TIMEOUT 5000 // Turn off after 5 seconds.
*
* and in your keymap.c, define (or add to) `housekeeping_task_user()` as
*
* void housekeeping_task_user(void) {
* caps_word_task();
* // Other tasks...
* }
*
* For full documentation, see
* <https://getreuer.info/posts/keyboards/caps-word>
*/
/**
* Handler function for Caps Word.
*
* Call this function from `process_record_user()` to implement Caps Word.
*/
bool process_caps_word(uint16_t keycode, keyrecord_t* record);
// If CAPS_WORD_IDLE_TIMEOUT is set, call `caps_word_task()` from
// `housekeeping_task_user()` as described above.
//
// If CAPS_WORD_IDLE_TIMEOUT isn't set, calling this function has no effect (but
// will still compile).
#if CAPS_WORD_IDLE_TIMEOUT > 0
void caps_word_task(void);
#else
static inline void caps_word_task(void) {}
#endif
/**
* Turns on Caps Word.
*
* For instance activate Caps Word with a combo by defining a `COMBO_ACTION`
* that calls `caps_word_on()`:
*
* void process_combo_event(uint16_t combo_index, bool pressed) {
* switch(combo_index) {
* case CAPS_COMBO:
* if (pressed) {
* caps_word_on();
* }
* break;
*
* // Other combos...
* }
* }
*/
void caps_word_on(void);
/** Turns off Caps Word. */
void caps_word_off(void);
/** Toggles Caps Word. */
void caps_word_toggle(void);
/** Returns true if Caps Word is currently on. */
bool is_caps_word_on(void);
/**
* Optional callback that gets called when Caps Word turns on or off.
*
* This callback is useful to represent the current Caps Word state, e.g. by
* setting an LED or playing a sound. In your keymap, define
*
* void caps_word_set_user(bool active) {
* if (active) {
* // Do something when Caps Word activates.
* } else {
* // Do something when Caps Word deactivates.
* }
* }
*/
void caps_word_set_user(bool active);
/**
* Optional callback, called on each key press while Caps Word is active.
*
* When the key should be shifted (that is, a letter key), the callback should
* call `add_weak_mods(MOD_BIT(KC_LSFT))` to shift the key. The callback also
* determines whether the key should continue Caps Word. Returning true
* continues the current "word", while returning false is "word breaking" and
* deactivates Caps Word. The default callback is
*
* bool caps_word_press_user(uint16_t keycode) {
* switch (keycode) {
* // Keycodes that continue Caps Word, with shift applied.
* case KC_A ... KC_Z:
* case KC_MINS:
* add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key.
* return true;
*
* // Keycodes that continue Caps Word, without shifting.
* case KC_1 ... KC_0:
* case KC_BSPC:
* case KC_DEL:
* case KC_UNDS:
* return true;
*
* default:
* return false; // Deactivate Caps Word.
* }
* }
*
* To customize, copy the above function into your keymap and add/remove
* keycodes to the above cases.
*
* @note Outside of this callback, you can use `caps_word_off()` to deactivate
* Caps Word.
*/
bool caps_word_press_user(uint16_t keycode);
// Deprecated APIs.
/** @deprecated Use `caps_word_on()` and `caps_word_off()` instead. */
static inline void caps_word_set(bool active) {
if (active) {
caps_word_on();
} else {
caps_word_off();
}
}
/** @deprecated Use `is_caps_word_on()` instead. */
static inline bool caps_word_get(void) { return is_caps_word_on(); }
#ifdef __cplusplus
}
#endif

View file

@ -28,6 +28,10 @@ uint16_t get_recent_keycode(signed char i) {
return recent[RECENT_SIZE + i];
}
bool was_keycode_replaced(void) {
return processingCK;
}
void update_bkspc_countdown(unsigned char i) {
bkspc_countdown = i;
}

View file

@ -29,6 +29,7 @@ extern "C" {
uint16_t deadline;
uint16_t get_recent_keycode(signed char);
bool was_keycode_replaced(void);
void update_bkspc_countdown(unsigned char i);
void clear_recent_keys(void);

View file

@ -60,17 +60,6 @@ bool process_macros(uint16_t keycode, keyrecord_t *record) {
clear_recent_keys();
break;
case KC_CAPS:
caps_word_off();
return true;
case CAPSWORD:
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
// Deactivating Caps Lock when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
caps_word_toggle();
return false;
case TG_APOS:
is_apos_dr = !is_apos_dr;
return false;

View file

@ -26,13 +26,13 @@ bool is_num_word_enabled(void) {
}
void enable_num_word(void) {
//if (is_num_word_on) return;
if (is_num_word_on) return;
is_num_word_on = true;
layer_on(_NUMBERS);
}
void disable_num_word(void) {
//if (!is_num_word_on) return;
if (!is_num_word_on) return;
is_num_word_on = false;
layer_off(_NUMBERS);
exit_num_word = false;
@ -58,6 +58,13 @@ bool process_numword(uint16_t keycode, const keyrecord_t *record) {
// if the behavior is not on, so allow QMK to handle the event as usual.
if (!is_num_word_on) { return true; }
// Should exit num word on key release
// in case of rolled keys as well (take the press of the 2nd one into account!)
if (exit_num_word) {
disable_num_word();
return true;
}
if (record->event.pressed) {
// Get the base keycode of a mod or layer tap key
@ -79,8 +86,8 @@ bool process_numword(uint16_t keycode, const keyrecord_t *record) {
}
exit_num_word = should_exit_num_word(keycode, record);
} else if (exit_num_word) { // On keyrelease
disable_num_word();
} else { // On keyrelease
}
return true;
}

View file

@ -25,27 +25,40 @@ void update_oneshot(oneshot_state *state, uint16_t mod, uint16_t trigger, uint16
break;
}
}
} else {
if (record->event.pressed) {
if (is_oneshot_cancel_key(keycode) && *state != os_up_unqueued) {
// Cancel oneshot on designated cancel keydown.
*state = os_up_unqueued;
unregister_code(mod);
} else if (is_oneshot_cancel_key(keycode)) {
if (record->event.pressed && *state != os_up_unqueued) {
// Cancel oneshot on designated cancel keydown.
*state = os_up_unqueued;
unregister_code(mod);
}
} else if (!is_oneshot_ignored_key(keycode)) {
// Regular key released / roll between two regular keys
if (*state == os_up_queued_used) {
*state = os_up_unqueued;
unregister_code(mod);
} else if (record->event.pressed) {
// Regular key pressed
if (*state == os_up_queued) {
*state = os_up_queued_used;
}
} else {
if (!is_oneshot_ignored_key(keycode)) {
// On non-ignored keyup, consider the oneshot used.
switch (*state) {
case os_down_unused:
*state = os_down_used;
break;
case os_up_queued:
*state = os_up_unqueued;
unregister_code(mod);
break;
default:
break;
}
// Regular key release
switch (*state) {
// When the mod key is still pressed
case os_down_unused:
*state = os_down_used;
break;
// Roll between a mod key and a regular key
case os_up_queued:
*state = os_up_unqueued;
unregister_code(mod);
break;
default:
break;
}
}
}

View file

@ -2,10 +2,11 @@
#include QMK_KEYBOARD_H
// Represents the four states a oneshot key can be in
// Represents the five states a oneshot key can be in
typedef enum {
os_up_unqueued,
os_up_queued,
os_up_queued_used,
os_down_unused,
os_down_used,
} oneshot_state;

View file

@ -20,7 +20,6 @@
oneshot_state os_shft_state = os_up_unqueued;
oneshot_state os_ctrl_state = os_up_unqueued;
oneshot_state os_alt_state = os_up_unqueued;
oneshot_state os_altgr_state = os_up_unqueued;
oneshot_state os_win_state = os_up_unqueued;
static uint8_t os4a_layer = 0;
@ -66,7 +65,7 @@ bool add_shift(uint16_t keycode, keyrecord_t *record) {
// Testing exit_os4a_layer is necessary to prevent OS shift to be added in case of rolled keys
// or when other features invoke keycodes to be processed (ex: custom altgr, clever keys).
if (exit_os4a_layer) { return false; }
//if (exit_os4a_layer) { return false; }
// Shift shouldn't be added if other mods are active
if ((get_mods() | get_oneshot_mods()) != 0) { return false; }
@ -101,29 +100,31 @@ bool process_mods(uint16_t keycode, keyrecord_t *record) {
update_oneshot(&os_ctrl_state, KC_LCTL, OS_CTRL, keycode, record);
update_oneshot(&os_alt_state, KC_LALT, OS_LALT, keycode, record);
update_oneshot(&os_win_state, KC_LWIN, OS_WIN, keycode, record);
//update_oneshot(&os_altgr_state, KC_RALT, OS_RALT, keycode, record);
// Handling OS4A keys
if (IS_OS4A_KEY(keycode)) { return process_os4a_keys(keycode, record); }
// Behaviour of the OS4A layers
if (os4a_layer != 0) {
if (record->event.pressed) {
if (os4a_layer == 0) { return true; }
if (should_stay_os4a_layer(keycode)) {
exit_os4a_layer = false;
} else {
if (add_shift(keycode, record)) { set_oneshot_mods(MOD_BIT(KC_LSFT)); }
exit_os4a_layer = true;
}
} else {
// When Ctrl or Shift are released, for mouse use.
//if (mods_for_mouse(keycode)) { mouse_mods_key_up(keycode, record); }
if (exit_os4a_layer) { os4a_layer_off(os4a_layer); }
}
// Exiting OS4A layers on keyrelease or on 2nd keypress of a roll
if (exit_os4a_layer) {
os4a_layer_off(os4a_layer);
return true;
}
// Behaviour of the OS4A layers
if (record->event.pressed) {
if (!should_stay_os4a_layer(keycode)) {
if (add_shift(keycode, record)) { set_oneshot_mods(MOD_BIT(KC_LSFT)); }
exit_os4a_layer = true;
}
} else { // On release
// When Ctrl or Shift are released, for mouse use.
//if (mods_for_mouse(keycode)) { mouse_mods_key_up(keycode, record); }
}
return true;
}

View file

@ -99,7 +99,6 @@ bool should_stay_os4a_layer(uint16_t keycode) {
switch (keycode) {
case OS_SHFT:
case OS_CTRL:
case OS_RALT:
case OS_LALT:
case OS_WIN:
return true;
@ -149,11 +148,10 @@ bool is_oneshot_ignored_key(uint16_t keycode) {
// sous peine de ne pas pouvoir faire shift + typo + touche de l'autre côté
if (mods & ~MOD_BIT(KC_ALGR)) { return true; }
break;
case L_OS4A:
case R_OS4A:
//case L_OS4A:
//case R_OS4A:
case OS_SHFT:
case OS_CTRL:
case OS_RALT:
case OS_LALT:
case OS_WIN:
case OS_FA: // to be combined with Alt

View file

@ -67,6 +67,7 @@ bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
void matrix_scan_user(void) {
recent_keys_task();
caps_word_task();
}
@ -111,12 +112,15 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// Clever keys
if (!process_clever_keys(keycode, record)) { return false; }
if (!process_caps_word(keycode, record)) {return false; }
// Process all other keycodes normally
return true;
}
void post_process_record_user(uint16_t keycode, keyrecord_t* record) {
if (is_caps_word_on()) { clear_weak_mods(); }
end_CK(record);
}

View file

@ -57,7 +57,6 @@ enum custom_keycodes {
MAGIC,
OS_SHFT,
OS_CTRL,
OS_RALT,
OS_LALT,
OS_WIN,
CNL_ODK,

View file

@ -20,7 +20,7 @@ ENCODER_MAP_ENABLE = no
TAP_DANCE_ENABLE = no
DEFERRED_EXEC_ENABLE = no
KEY_OVERRIDE_ENABLE = no
CAPS_WORD_ENABLE = yes
CAPS_WORD_ENABLE = no
COMBO_ENABLE = yes
REPEAT_KEY_ENABLE = yes

View file

@ -1,5 +0,0 @@
{
"files.associations": {
"ppg.C": "cpp"
}
}

View file

@ -1,331 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
// Correction automatique
#include "clever_keys.h"
void get_clever_keycode(uint16_t* next_keycode, keyrecord_t* record) {
uint16_t prev_keycode = recent[RECENT_SIZE - 1];
// Inversion du point et de la virgule
static bool inversion = false;
if (*next_keycode == PG_POIN) {
replace_ongoing_key(PG_VIRG, next_keycode, record);
inversion = true;
}
if (inversion == false && *next_keycode == PG_VIRG) { replace_ongoing_key(PG_POIN, next_keycode, record); }
inversion = false;
static bool apostrophe = false;
if (IS_LAYER_ON(_BASE) && *next_keycode == PG_APOS) {
if (apostrophe) {
apostrophe = false;
} else {
replace_ongoing_key(PG_MOIN, next_keycode, record);
}
}
apostrophe = false;
// Apostrophe
switch (*next_keycode) {
case PG_Q:
set_last_keycode(PG_APOS);
apostrophe = true;
break;
case PG_L:
case PG_T:
case PG_D:
case PG_C:
case PG_N:
case PG_S:
case PG_M:
case PG_Y:
case PG_J:
//if (!isLetter(prev_keycode)) { set_last_keycode(PG_APOS); }
if (!isLetter(prev_keycode)) {
set_last_keycode(PG_APOS);
apostrophe = true;
}
}
if (isLetter(*next_keycode) || isSendStringMacro(*next_keycode)) {
switch (prev_keycode) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_2PTS:
// Add space between punctuation and letters.
invoke_key(KC_SPC, record);
set_last_keycode(*next_keycode);
case KC_SPC:
switch (recent[RECENT_SIZE - 2]) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_POIN:
// Add OS shift at the beginning of sentences.
if (!is_caps_lock_on()) { set_oneshot_mods(MOD_BIT(KC_LSFT)); }
break;
}
}
}
switch (prev_keycode) {
case PG_Q:
switch (*next_keycode) {
// Ajout automatique du "u" après le "q"
case PG_E:
case PG_I:
case PG_A:
case PG_O:
case PG_EACU:
case PG_APOS:
invoke_key(PG_U, record);
set_last_keycode(*next_keycode);
break;
// Raccourci pour "quelq"
/* case PG_Q:
process_word((uint16_t[]) {PG_U, PG_E, PG_L}, 3, record);
break; */
// Raccourci pour "quoi", ça évite un aller-retour sur la main gauche.
case PG_Z:
finish_word((uint16_t[]) {PG_U, PG_O, PG_I}, 3, next_keycode, record);
break;
// Raccourci pour "quand"
case PG_N:
return finish_word((uint16_t[]) {PG_U, PG_A, PG_N, PG_D}, 4, next_keycode, record);
//set_last_keycode(*next_keycode);
//break;
}
break;
case PG_P:
switch (*next_keycode) {
case PG_M:
// "par"
return finish_word((uint16_t[]) {PG_A, PG_R}, 2, next_keycode, record);
case PG_C:
// "pas"
return finish_word((uint16_t[]) {PG_A, PG_S}, 2, next_keycode, record);
case PG_J:
if (!isLetter(recent[RECENT_SIZE - 2])) {
// "pour"
return finish_word((uint16_t[]) {PG_O, PG_U, PG_R}, 3, next_keycode, record);
}
break;
case PG_X:
// "plus"
return finish_word((uint16_t[]) {PG_L, PG_U, PG_S}, 3, next_keycode, record);
}
break;
}
switch (*next_keycode) {
case PG_QUES:
case PG_EXCL:
// On ajoute un espace insécable s'il n'a pas été entré avant le point d'exclamation.
// Il ne faut pas tester cette fonctionnalité avec Word, qui ajoute cet espace automatiquement.
if (isLetter(recent[RECENT_SIZE - 1])) {
invoke_key(KC_SPC, record);
return replace_ongoing_key(*next_keycode, next_keycode, record);
}
break;
case MAGIC:
/* if (!isLetter(prev_keycode)) {
// "je"
return finish_word((uint16_t[]) {PG_J, PG_E}, 2, next_keycode, record);
} */
switch (prev_keycode) {
case PG_O:
// oui
invoke_key(PG_U, record);
case PG_U:
// ui SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_I, next_keycode, record);
case PG_L:
// là
return finish_word((uint16_t[]) {PG_ODK, PG_A}, 2, next_keycode, record);
case PG_EACU:
// éa SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_A, next_keycode, record);
case PG_S:
// sc SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_C, next_keycode, record);
case PG_C:
// cs SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_S, next_keycode, record);
case PG_N:
// n. SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_POIN, next_keycode, record);
case PG_P:
// ph SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_H, next_keycode, record);
case PG_G:
// gt SFB
bkspc_countdown = 0;
return replace_ongoing_key(PG_T, next_keycode, record);
case PG_Q:
// qué scissor
return finish_word((uint16_t[]) {PG_U, PG_EACU}, 2, next_keycode, record);
case PG_T:
invoke_key(PG_I, record);
case PG_I:
return finish_word((uint16_t[]) {PG_O, PG_N}, 2, next_keycode, record);
case PG_M:
if (isLetter(recent[RECENT_SIZE - 2])) {
// "ment"
return finish_word((uint16_t[]) {PG_E, PG_N, PG_T}, 3, next_keycode, record);
} else {
// "même"
return finish_word((uint16_t[]) {PG_ODK, PG_O, PG_M, PG_E}, 4, next_keycode, record);
}
case PG_B:
// "beaucoup"
//layer_off(_ODK);
return finish_word((uint16_t[]) {PG_E, PG_A, PG_U, PG_C, PG_O, PG_U, PG_P}, 7, next_keycode, record);
case PG_D:
// "déjà"
//layer_off(_ODK);
return finish_word((uint16_t[]) {PG_EACU, PG_J, PG_ODK, PG_A}, 4, next_keycode, record);
default:
return;
}
case PG_AROB:
if (!isLetter(recent[RECENT_SIZE - 2])) {
switch (prev_keycode) {
case PG_P:
// "p@" -> "problème"
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_R, PG_O, PG_B, PG_L, PG_ODK, PG_E, PG_M, PG_E}, 8, next_keycode, record);
case PG_A:
// "a@" -> "aujourd'hui"
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_U, PG_J, PG_O, PG_U, PG_R, PG_D, PG_APOS, PG_H, PG_U, PG_I}, 10, next_keycode, record);
}
}
break;
case PG_M:
if (prev_keycode == PG_C) {
// "cm" -> "ch"
bkspc_countdown = 0;
return replace_ongoing_key(PG_H, next_keycode, record);
}
break;
case PG_H:
if (prev_keycode == PG_M) {
// "mh" -> "mb"
bkspc_countdown = 0;
return replace_ongoing_key(PG_B, next_keycode, record);
}
break;
/* case PG_R:
if (prev_keycode == PG_L) {
// "lr" -> "l" + 1DK
//bkspc_countdown = 0;
return replace_ongoing_key(OS_ODK, next_keycode, record);
}
break; */
/* case PG_A:
//if (prev_keycode == PG_O && !isCaps) {
if (prev_keycode == PG_O) {
// "oa" -> "oi"
bkspc_countdown = 0;
return replace_ongoing_key(PG_I, next_keycode, record);
}
break;
case PG_I:
//if (prev_keycode == PG_O && !isCaps && recent[RECENT_SIZE - 3] != PG_Q) {
if (prev_keycode == PG_O && recent[RECENT_SIZE - 3] != PG_Q) {
// "oi" -> "oa", for "keyboard"
bkspc_countdown = 0;
return replace_ongoing_key(PG_A, next_keycode, record);
}
break; */
case OU_GRV:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_O, PG_ODK, PG_N}, 3, next_keycode, record);
/* case PG_BL:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_B, PG_L}, 2, next_keycode, record); */
/* case J_APOS:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_J, PG_APOS}, 2, next_keycode, record); */
/* case L_APOS:
return finish_word((uint16_t[]) {PG_L, PG_APOS}, 2, next_keycode, record);
case D_APOS:
return finish_word((uint16_t[]) {PG_D, PG_APOS}, 2, next_keycode, record); */
case PG_APOS:
if (is_apos_dr) { return replace_ongoing_key(PG_APOD, next_keycode, record); }
break;
/* case AGRV_SPC:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_AGR, KC_SPC}, 2, next_keycode, record); */
}
}

View file

@ -1,33 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "keymap.h"
//#include <string.h>
//#include "keymap_french_frgo.h"
#ifdef __cplusplus
extern "C" {
#endif
void get_clever_keycode(uint16_t* next_keycode, keyrecord_t* record);
#ifdef __cplusplus
}
#endif

View file

@ -1,133 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef RGBLIGHT_ENABLE
# define RGBLIGHT_EFFECT_BREATHING
# define RGBLIGHT_EFFECT_RAINBOW_MOOD
# define RGBLIGHT_EFFECT_RAINBOW_SWIRL
# define RGBLIGHT_EFFECT_SNAKE
# define RGBLIGHT_EFFECT_KNIGHTis
# define RGBLIGHT_EFFECT_CHRISTMAS
# define RGBLIGHT_EFFECT_STATIC_GRADIENT
# define RGBLIGHT_EFFECT_RGB_TEST
# define RGBLIGHT_EFFECT_ALTERNATING
# define RGBLIGHT_EFFECT_TWINKLE
# define RGBLIGHT_HUE_STEP 8
# define RGBLIGHT_SAT_STEP 8
# define RGBLIGHT_VAL_STEP 8
# define RGBLIGHT_LIMIT_VAL 150
#endif
//#define TAPPING_TOGGLE 1
// combo
#define COMBO_TERM 50
//#define COMBO_TERM_PER_COMBO
#define COMBO_ONLY_FROM_LAYER 0
#define COMBO_SHOULD_TRIGGER
#define COMBO_PROCESS_KEY_REPRESS
#define TAP_INTERVAL 300
// mod tap
#define TAPPING_TERM 200
#define PERMISSIVE_HOLD
//#define PERMISSIVE_HOLD_PER_KEY
#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
#define TAPPING_TOGGLE 1
// EC11K encoders have a different resolution than other EC11 encodeisrs.
// When using the default resolution of 4, if you notice your encoder skipping
// every other tick, lower the resolution to 2.
/* #define ENCODER_RESOLUTION 2
#if defined(KEYBOARD_splitkb_kyria_rev1)
# define ENCODER_DIRECTION_FLIP
#endif */
// One shot modifiers
//#define ONESHOT_TAP_TOGGLE 5 /* Tapping this number of times holds the key until tapped once again. */
//#define ONESHOT_TIMEOUT 5000 /* Time (in ms) before the one shot key is released */
// Recent keys
#define RECENT_KEYS_TIMEOUT 5000 // Timeout in milliseconds.
//Faire de la place !
#undef LOCKING_SUPPORT_ENABLE
#undef LOCKING_RESYNC_ENABLE
#define NO_MUSIC_MODE
#undef RGBLIGHT_ANIMATIONS
#undef RGBLIGHT_EFFECT_BREATHING
#undef RGBLIGHT_EFFECT_RAINBOW_MOOD
#undef RGBLIGHT_EFFECT_RAINBOW_SWIRL
#undef RGBLIGHT_EFFECT_SNAKE
#undef RGBLIGHT_EFFECT_KNIGHT
#undef RGBLIGHT_EFFECT_CHRISTMAS
#undef RGBLIGHT_EFFECT_STATIC_GRADIENT
#undef RGBLIGHT_EFFECT_RGB_TEST
#undef RGBLIGHT_EFFECT_ALTERNATING
#undef RGBLIGHT_EFFECT_TWINKLE
#undef ENABLE_RGB_MATRIX_ALPHAS_MODS
#undef ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#undef ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
#undef ENABLE_RGB_MATRIX_BREATHING
#undef ENABLE_RGB_MATRIX_BAND_SAT
#undef ENABLE_RGB_MATRIX_BAND_VAL
#undef ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#undef ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
#undef ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
#undef ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
#undef ENABLE_RGB_MATRIX_CYCLE_ALL
#undef ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
#undef ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
#undef ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
#undef ENABLE_RGB_MATRIX_CYCLE_OUT_IN
#undef ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
#undef ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
#undef ENABLE_RGB_MATRIX_CYCLE_SPIRAL
#undef ENABLE_RGB_MATRIX_DUAL_BEACON
#undef ENABLE_RGB_MATRIX_RAINBOW_BEACON
#undef ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
#undef ENABLE_RGB_MATRIX_RAINDROPS
#undef ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
#undef ENABLE_RGB_MATRIX_HUE_BREATHING
#undef ENABLE_RGB_MATRIX_HUE_PENDULUM
#undef ENABLE_RGB_MATRIX_HUE_WAVE
#undef ENABLE_RGB_MATRIX_PIXEL_FRACTAL
#undef ENABLE_RGB_MATRIX_PIXEL_FLOW
#undef ENABLE_RGB_MATRIX_PIXEL_RAIN
#undef ENABLE_RGB_MATRIX_TYPING_HEATMAP
#undef ENABLE_RGB_MATRIX_DIGITAL_RAIN
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
#undef ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
#undef ENABLE_RGB_MATRIX_SPLASH
#undef ENABLE_RGB_MATRIX_MULTISPLASH
#undef ENABLE_RGB_MATRIX_SOLID_SPLASH
#undef ENABLE_RGB_MATRIX_SOLID_MULTISPLASH

View file

@ -1,221 +0,0 @@
// Correction automatique
#include "clever_keys.h"
bool process_clever_keys(uint16_t keycode, keyrecord_t* record) {
uint16_t next_keycode = get_next_keycode(keycode, record);
const uint8_t mods = get_mods();
if (next_keycode != KC_NO) {
uint16_t prev_keycode = recent[RECENT_SIZE - 1];
//const uint8_t mods = get_mods();
if (isLetter(next_keycode) || next_keycode == E_CIRC) {
switch (prev_keycode) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_2PTS:
// Add space between punctuation and letters.
process_next_key(KC_SPC, record);
case KC_SPC:
switch (recent[RECENT_SIZE - 2]) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_X:
// Add OS shift at the beginning of a sentence.
if (!is_caps_lock_on()) { set_oneshot_mods(MOD_BIT(KC_LSFT)); }
break;
}
}
}
// Ajout automatique du "u" après le "q"
if (prev_keycode == PG_Q) {
switch (next_keycode) {
case PG_E:
case PG_I:
case PG_A:
case PG_O:
case PG_U:
case E_CIRC:
case PG_APOS:
process_next_key(PG_L, record);
break;
// Raccourci pour "quelq"
case PG_Q:
clear_recent_keys(); // To prevent infinite loop
process_word((uint16_t[]) {PG_L, PG_E, PG_C}, 3, record);
break;
// Raccourci pour "quoi", ça évite un aller-retour sur la main gauche.
case PG_Z:
return finish_word((uint16_t[]) {PG_L, PG_O, PG_I}, 3, record);
// Raccourci pour "quand"
case PG_H:
process_word((uint16_t[]) {PG_L, PG_A, PG_S}, 3, record);
break;
}
} else if (next_keycode == PG_AROB && !isLetter(recent[RECENT_SIZE - 2])) {
switch (prev_keycode) {
case PG_N:
// "t@" -> "toujours"
return finish_word((uint16_t[]) {PG_O, PG_L, PG_J, PG_O, PG_L, PG_R, PG_T}, 7, record);
case PG_P:
// "p@" -> "peut-être"
return finish_word((uint16_t[]) {PG_E, PG_L, PG_N, PG_MOIN, PG_ACIR, PG_E, PG_N, PG_R, PG_E}, 9, record);
case PG_A:
// "a@" -> "aujourd'hui"
return finish_word((uint16_t[]) {PG_L, PG_J, PG_O, PG_L, PG_R, PG_H, PG_APOS, PG_F, PG_L, PG_I}, 10, record);
case PG_B:
// "b@" -> "beaucoup"
return finish_word((uint16_t[]) {PG_E, PG_A, PG_L, PG_D, PG_O, PG_L, PG_P}, 7, record);
case PG_E:
// "e@" -> "est-ce qu"
return finish_word((uint16_t[]) {PG_T, PG_N, PG_MOIN, PG_D, PG_E, KC_SPC, PG_Q}, 7, record);
case PG_H:
// "d@" -> "déjà"
return finish_word((uint16_t[]) {PG_U, PG_J, PG_AGRV}, 3, record);
}
} else if (prev_keycode == PG_P) {
switch (next_keycode) {
case PG_M:
// "pas"
return finish_word((uint16_t[]) {PG_A, PG_T}, 2, record);
case PG_APOS:
// "par"
return finish_word((uint16_t[]) {PG_A, PG_R}, 2, record);
case PG_X:
if (!isLetter(recent[RECENT_SIZE - 2])) {
// "pour"
return finish_word((uint16_t[]) {PG_O, PG_L, PG_R}, 3, record);
}
}
} else if (next_keycode == PG_A && prev_keycode == PG_O) {
// "oa" -> "oi"
process_next_key(PG_I, record);
return false;
} else if (next_keycode == PG_O && prev_keycode == PG_L && recent[RECENT_SIZE - 2] != PG_Q) {
// "uo" -> "un"
process_next_key(PG_S, record);
return false;
}
switch (next_keycode) {
case PG_QUES:
case PG_EXCL:
// On ajoute un espace insécable s'il n'a pas été entré avant le point d'exclamation.
// Il ne faut pas tester cette fonctionnalité avec Word, qui ajoute cet espace automatiquement.
if (isLetter(recent[RECENT_SIZE - 1])) {
if ((mods | get_oneshot_mods() | get_weak_mods()) & MOD_MASK_SHIFT) {
del_weak_mods(MOD_MASK_SHIFT);
del_oneshot_mods(MOD_MASK_SHIFT);
unregister_mods(MOD_MASK_SHIFT);
}
process_next_key(ALGR(KC_SPC), record);
set_mods(mods);
process_next_key(next_keycode, record);
return false;
}
break;
case MAGIC:
switch (prev_keycode) {
case PG_N:
process_next_key(PG_I, record);
case PG_I:
return finish_word((uint16_t[]) {PG_O, PG_S}, 2, record);
case PG_D:
return finish_word((uint16_t[]) {PG_APOS, PG_E, PG_T, PG_N}, 4, record);
case PG_H:
return finish_word((uint16_t[]) {PG_A, PG_S, PG_T}, 3, record);
case PG_P:
return finish_word((uint16_t[]) {PG_C, PG_L, PG_T}, 3, record);
case PG_A:
return finish_word((uint16_t[]) {PG_G, PG_E, PG_D}, 3, record);
case PG_T:
return finish_word((uint16_t[]) {PG_L, PG_R}, 2, record);
case PG_B:
process_word((uint16_t[]) {PG_O, PG_S, PG_J}, 3, record);
case PG_J:
return finish_word((uint16_t[]) {PG_O, PG_L, PG_R}, 3, record);
case PG_M:
// "même"
return finish_word((uint16_t[]) {PG_ACIR, PG_E, PG_M, PG_E}, 4, record);
default:
return false;
}
case PG_Q:
if (prev_keycode == PG_J) {
// "jq" -> "jusqu"
process_word((uint16_t[]) {PG_L, PG_T}, 2, record);
}
break;
case CA_CED:
return finish_word((uint16_t[]) {PG_CCED, PG_A}, 2, record);
case OU_GRV:
return finish_word((uint16_t[]) {PG_O, ALGR(PG_L)}, 2, record);
case AGRV_SPC:
return finish_word((uint16_t[]) {PG_AGRV, KC_SPC}, 2, record);
case E_CIRC:
return process_accent(PG_ACIR, PG_E, record);
case I_CIRC:
return process_accent(PG_ACIR, PG_I, record);
case A_CIRC:
return process_accent(PG_ACIR, PG_A, record);
case O_CIRC:
return process_accent(PG_ACIR, PG_O, record);
case U_CIRC:
return process_accent(PG_ACIR, PG_L, record);
case I_TREM:
return process_accent(PG_NREM, PG_I, record);
}
store_keycode(next_keycode, record);
}
return true; // Process all other keycodes normally
}

View file

@ -1,196 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "clever_keys_utilities.h"
uint16_t recent[RECENT_SIZE] = {KC_NO};
uint16_t deadline = 0;
//static unsigned short int bkspc_countdown = RECENT_SIZE + 1;
unsigned short int bkspc_countdown = RECENT_SIZE + 1;
// Copy of the record argument for the clever key.
static keyrecord_t mod_record;
static bool processingCK = false;
void clear_recent_keys(void) {
memset(recent, 0, sizeof(recent)); // Set all zeros (KC_NO).
bkspc_countdown = RECENT_SIZE + 1;
}
void recent_keys_task(void) {
if (recent[RECENT_SIZE - 1] && timer_expired(timer_read(), deadline)) {
clear_recent_keys(); // Timed out; clear the buffer.
}
}
// Handles one event. Returns false if the key was appended to `recent`.
uint16_t get_ongoing_keycode(uint16_t keycode, keyrecord_t* record) {
uint8_t mods = get_mods() | get_oneshot_mods();
if (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR))) {
clear_recent_keys(); // Avoid interfering with ctrl, left alt and gui.
return KC_NO;
}
// Sticky keys don't type anything on their own.
if (IS_QK_ONE_SHOT_MOD(keycode) || IS_QK_ONE_SHOT_LAYER(keycode)) { return KC_NO; }
// Handle backspace.
if (keycode == KC_BSPC) {
bkspc_countdown--;
if (bkspc_countdown == 0) {
// Clear the key buffers.
clear_recent_keys();
} else {
// Rewind the key buffers.
memmove(recent + 1, recent, (RECENT_SIZE - 1) * sizeof(uint16_t));
recent[0] = KC_NO;
// Setting the key to be repeated to match the key buffer.
set_last_keycode(recent[RECENT_SIZE - 1]);
}
return KC_NO;
}
// Extract keycode from regular tap-hold keys.
if (IS_QK_MOD_TAP(keycode) || IS_QK_LAYER_TAP(keycode)) {
if (record->tap.count == 0) { return KC_NO; }
// Get tapping keycode.
keycode = tap_hold_extractor(keycode);
}
// Handles custom keycodes.
if (isSendStringMacro(keycode)) { return keycode; }
//if (keycode == PG_CCED) { return PG_CCED; }
if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_K:
case PG_B:
case PG_AROB:
case PG_3PTS:
case KC_SPC: // In order to uppercase J after '?' for ex.
return keycode;
case PG_VIRG:
return PG_3PTS;
/* case PG_T:
return PG_MOIN; */
default:
clear_recent_keys();
return KC_NO;
}
}
uint8_t basic_keycode = keycode;
// Handle keys carrying a modifier, for ex on layers(! and ?).
if (IS_QK_MODS(keycode)) { basic_keycode = QK_MODS_GET_BASIC_KEYCODE(keycode); }
switch (basic_keycode) {
case KC_A ... KC_SLASH: // These keys type letters, digits, symbols.
case PG_E:
if (isLetter(basic_keycode) && (mods & ~MOD_BIT(KC_ALGR))) {
// Shift doesn't matter for letters.
return basic_keycode;
} else if (basic_keycode != keycode) {
// For keys carrying a modifier, for ex on layers.
return keycode;
} else {
// Convert 8-bit mods to the 5-bit format used in keycodes. This is lossy: if
// left and right handed mods were mixed, they all become right handed.
mods = ((mods & 0xf0) ? /* set right hand bit */ 0x10 : 0)
// Combine right and left hand mods.
| (((mods >> 4) | mods) & 0xf);
// Combine basic keycode with mods.
keycode = (mods << 8) | basic_keycode;
return keycode;
}
default: // Avoid acting otherwise, particularly on navigation keys.
clear_recent_keys();
return KC_NO;
}
return KC_NO;
}
void store_keycode(uint16_t keycode, keyrecord_t* record) {
// Slide the buffer left by one element.
memmove(recent, recent + 1, (RECENT_SIZE - 1) * sizeof(*recent));
recent[RECENT_SIZE - 1] = keycode;
bkspc_countdown++;
deadline = record->event.time + RECENT_KEYS_TIMEOUT;
}
void process_key(uint16_t keycode, keyrecord_t* record) {
mod_record = *record;
mod_record.keycode = keycode;
// Send the next keycode key down event
process_record(&mod_record);
// Send the next keycode key up event
mod_record.event.pressed = false;
process_record(&mod_record);
}
void invoke_key(uint16_t keycode, keyrecord_t* record) {
process_key(keycode, record);
//record->keycode = keycode;
bkspc_countdown = 1;
}
void replace_ongoing_key(uint16_t clever_keycode, uint16_t* ongoing_keycode, keyrecord_t* record) {
record->keycode = clever_keycode;
*ongoing_keycode = clever_keycode;
set_last_keycode(clever_keycode);
processingCK = true;
}
void process_word(uint16_t keycodes[], uint8_t num_keycodes, keyrecord_t* record) {
for (int i = 0; i < num_keycodes; ++i) {
process_key(keycodes[i], record); // Better solution, if there is enought space in the chip.
//tap_code(keycodes[i]);
}
bkspc_countdown = num_keycodes;
}
void finish_word(uint16_t keycodes[], uint8_t num_keycodes, uint16_t* ongoing_keycode, keyrecord_t* record) {
process_word(keycodes, num_keycodes - 1, record);
replace_ongoing_key(keycodes[num_keycodes - 1], ongoing_keycode, record);
}
bool process_clever_keys(uint16_t keycode, keyrecord_t* record) {
if (record->event.pressed) {
uint16_t ongoing_keycode = get_ongoing_keycode(keycode, record);
if (ongoing_keycode != KC_NO) {
get_clever_keycode(&ongoing_keycode, record);
store_keycode(ongoing_keycode, record);
}
//return true; // If no clever key was found, process keycode normally.
}
return true;
}
void end_CK(keyrecord_t* record) {
if (processingCK) {
processingCK = false;
record->event.pressed = false;
process_record(record);
}
}

View file

@ -1,51 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "keymap.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RECENT_SIZE 8 // Number of keys in `recent` buffer.
extern uint16_t recent[RECENT_SIZE];
uint16_t deadline;
extern unsigned short int bkspc_countdown;
void clear_recent_keys(void);
void recent_keys_task(void);
uint16_t get_ongoing_keycode(uint16_t keycode, keyrecord_t* record);
void store_keycode(uint16_t keycode, keyrecord_t* record);
void process_key(uint16_t keycode, keyrecord_t* record);
void invoke_key(uint16_t keycode, keyrecord_t* record);
void replace_ongoing_key(uint16_t clever_keycode, uint16_t* ongoing_keycode, keyrecord_t* record);
void process_word(uint16_t keycodes[], uint8_t num_keycodes, keyrecord_t* record);
void finish_word(uint16_t keycodes[], uint8_t num_keycodes, uint16_t* ongoing_keycode, keyrecord_t* record);
bool process_clever_keys(uint16_t keycode, keyrecord_t* record);
void end_CK(keyrecord_t* record);
//bool process_accent(uint16_t accent, uint16_t letter, keyrecord_t* record);
#ifdef __cplusplus
}
#endif

View file

@ -1,143 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
#include "keymap.h"
enum combos {
R_BKSPC,
DELETE,
BK_WORD,
DEL_WORD,
L_BKSPC,
HOME,
END,
ENTER,
TAB,
ESC,
HELP,
PANIC,
NUMWRD,
ALTTAB,
ALTESC
/* L_APOST,
D_APOST, */
};
const uint16_t PROGMEM del_combo_d[] = {PG_T, PG_S, COMBO_END};
const uint16_t PROGMEM bkspc_combo_d[] = {PG_S, PG_R, COMBO_END};
const uint16_t PROGMEM del_word_combo[] = {PG_M, PG_C, COMBO_END};
const uint16_t PROGMEM bk_word_combo[] = {PG_C, PG_J, COMBO_END};
const uint16_t PROGMEM enter_combo[] = {PG_P, PG_U, COMBO_END};
const uint16_t PROGMEM tab_combo[] = {PG_N, PG_I, COMBO_END};
const uint16_t PROGMEM esc_combo[] = {PG_N, PG_A, COMBO_END};
const uint16_t PROGMEM bkspc_combo_g[] = {PG_A, PG_I, COMBO_END};
const uint16_t PROGMEM home_combo[] = {PG_Z, PG_Y, COMBO_END};
const uint16_t PROGMEM end_combo[] = {PG_U, PG_EACU, COMBO_END};
const uint16_t PROGMEM help_combo[] = {PG_EACU, PG_J, COMBO_END};
const uint16_t PROGMEM panic_combo[] = {PG_U, PG_C, COMBO_END};
const uint16_t PROGMEM numword_combo[] = {PG_T, PG_R, COMBO_END};
const uint16_t PROGMEM alttab_combo[] = {PG_H, PG_Y, COMBO_END};
const uint16_t PROGMEM altesc_combo[] = {PG_A, PG_I, PG_N, COMBO_END};
/* const uint16_t PROGMEM l_apost_combo[] = {PG_X, PG_APOS, COMBO_END};
const uint16_t PROGMEM d_apost_combo[] = {PG_D, PG_F, COMBO_END}; */
combo_t key_combos[] = {
[R_BKSPC] = COMBO(bkspc_combo_d, KC_BSPC),
[DELETE] = COMBO(del_combo_d, KC_DEL),
[BK_WORD] = COMBO(bk_word_combo, LCTL(KC_BSPC)),
[DEL_WORD] = COMBO(del_word_combo, LCTL(KC_DEL)),
[L_BKSPC] = COMBO(bkspc_combo_g, KC_BSPC),
[HOME] = COMBO(home_combo, KC_HOME),
[END] = COMBO(end_combo, KC_END),
[ENTER] = COMBO(enter_combo, KC_ENT),
[TAB] = COMBO(tab_combo, KC_TAB),
[ESC] = COMBO(esc_combo, KC_ESC),
[HELP] = COMBO(help_combo, AIDE_MEM),
[PANIC] = COMBO(panic_combo, RAZ),
[NUMWRD] = COMBO(numword_combo, NUMWORD),
[ALTTAB] = COMBO(alttab_combo, KC_NO),
[ALTESC] = COMBO(altesc_combo, LALT(KC_ESC))
/* [L_APOST] = COMBO(l_apost_combo, L_APOS),
[D_APOST] = COMBO(d_apost_combo, D_APOS) */
};
/* uint16_t get_combo_term(uint16_t combo_index, combo_t *combo) {
switch (combo_index) {
case L_APOST:
case D_APOST:
return 100;
default:
return COMBO_TERM;
}
} */
bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) {
// Chorded mods shouldn't be considered as combos.
if (os4a_layer != 0) {
return (os4a_layer == _R_MODS) == on_left_hand(record->event.key);
}
// Some combos shouldn't be affected by global_quick_tap_timer.
switch (combo_index) {
case R_BKSPC:
case BK_WORD:
case ENTER:
case HOME:
case END:
/* case L_APOST:
case D_APOST: */
return true;
default:
//return timer_elapsed(global_quick_tap_timer) > TAP_INTERVAL;
if (timer_elapsed(global_quick_tap_timer) < TAP_INTERVAL) {
return false;
}
}
return true;
}
void process_combo_event(uint16_t combo_index, bool pressed) {
switch (combo_index) {
case ALTTAB:
if (pressed) {
register_mods(MOD_LALT);
tap_code(KC_TAB);
} else {
unregister_mods(MOD_LALT);
}
break;
}
}
bool process_combo_key_repress(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
switch (combo_index) {
case ALTTAB:
switch (keycode) {
case PG_Y:
tap_code16(S(KC_TAB));
return true;
case PG_H:
tap_code(KC_TAB);
return true;
}
break;
}
return false;
}

View file

@ -1,76 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "macros.h"
bool is_apos_dr = false;
bool process_macros(uint16_t keycode, keyrecord_t *record) {
//const uint8_t mods = get_mods();
if (record->event.pressed) { // Handling of other macros (on press).
switch (keycode) {
/* case ALT_TAB:
return process_swapper(KC_TAB);
case REV_TAB:
return process_swapper(S(KC_TAB)); */
case AIDE_MEM:
switch(get_highest_layer(layer_state|default_layer_state)) {
case _BASE:
tap_code(KC_F13);
return false;
/* case _SYMBOLS:
tap_code(KC_F14); */
return false;
case _SHORTNAV:
tap_code(KC_F15);
return false;
case _FUNCAPPS:
tap_code(KC_F16);
return false;
}
case RAZ:
//led_t led_usb_state = host_keyboard_led_state();
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
if (!host_keyboard_led_state().num_lock) { tap_code(KC_NUM_LOCK); }
layer_clear();
clear_oneshot_mods();
caps_word_off();
disable_num_word();
clear_recent_keys();
break;
case KC_CAPS:
caps_word_off();
return true;
case CAPSWORD:
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
// Deactivating Caps Lock when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
caps_word_toggle();
return false;
case TG_APOS:
is_apos_dr = !is_apos_dr;
return false;
}
}
return true; // Process all other keycodes normally
}

View file

@ -1,32 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "keymap.h"
#ifdef __cplusplus
extern "C" {
#endif
extern bool is_apos_dr;
bool process_macros(uint16_t keycode, keyrecord_t *record);
#ifdef __cplusplus
}
#endif

View file

@ -1,120 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "numword.h"
//static uint16_t num_word_timer = 0;
//static bool is_num_word_on = false;
bool is_num_word_on = false;
static bool exit_num_word = false;
bool is_num_word_enabled(void) {
return is_num_word_on;
}
void enable_num_word(void) {
//if (is_num_word_on) return;
is_num_word_on = true;
layer_on(_NUMBERS);
}
void disable_num_word(void) {
//if (!is_num_word_on) return;
is_num_word_on = false;
layer_off(_NUMBERS);
exit_num_word = false;
}
void toggle_num_word(void) {
if (is_num_word_on) {
disable_num_word();
}
else {
enable_num_word();
}
}
bool should_exit_num_word(uint16_t keycode, const keyrecord_t *record) {
switch (keycode) {
// Keycodes which should not disable num word mode.
// Numpad keycodes
case KC_1 ... KC_0:
case KC_PDOT:
case PG_X:
//case PG_EACU:
case PG_MOIN:
case PG_ASTX:
case PG_PLUS:
case PG_SLSH:
case PG_ACIR:
case PG_CARN:
// Misc
case KC_BSPC:
case PG_ODK: // Not to exit Numword when chording it with ODK
case NUMWORD: // For the combo NUMWORD to work
/*
case PG_EGAL:
case PG_BSLS:*/
return false;
}
return true;
}
bool process_numword(uint16_t keycode, const keyrecord_t *record) {
// Handle the custom keycodes that go with this feature
if (keycode == NUMWORD) {
if (record->event.pressed) {
toggle_num_word();
return false;
}
}
// Other than the custom keycodes, nothing else in this feature will activate
// if the behavior is not on, so allow QMK to handle the event as usual.
if (!is_num_word_on) { return true; }
// Get the base keycode of a mod or layer tap key
switch (keycode) {
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
// Earlier return if this has not been considered tapped yet
if (record->tap.count == 0) { return true; }
keycode = keycode & 0xFF;
break;
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys.
// Release event on a held layer-tap key when numword is on.
if (record->tap.count == 0 && !record->event.pressed && is_num_word_on) {
return false; // Skip default handling so that layer stays on.
} else {
keycode = keycode & 0xFF; // Get tapping keycode.
}
break;
/* default:
break; */
}
exit_num_word = should_exit_num_word(keycode, record);
return true;
}
void numword_exit_check(void) {
if (exit_num_word) { disable_num_word(); }
}

View file

@ -1,30 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include QMK_KEYBOARD_H
#include "keymap.h"
bool is_num_word_enabled(void);
//extern bool exit_num_word;
extern bool is_num_word_on;
void enable_num_word(void);
void disable_num_word(void);
void toggle_num_word(void);
bool process_numword(uint16_t keycode, const keyrecord_t *record);
void numword_exit_check(void);

View file

@ -1,91 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "odk_layer.h"
//static uint16_t odk_keycode = KC_NO;
bool process_odk_layer(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) { // On press
const uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods();
static bool is_shifted = false;
if (keycode == OS_ODK) {
// Handle the custom OSL that go with this feature
// It's timerless, to avoid problems when rolling with an other key, when shift is on.
// Custom behaviour when alt-gr
/* if (mods & MOD_BIT(KC_ALGR)) {
tap_code16(ALGR(PG_ODK));
return false;
} */
is_shifted = mods & MOD_MASK_SHIFT;
if (is_shifted) {
del_weak_mods(MOD_MASK_SHIFT);
del_oneshot_mods(MOD_MASK_SHIFT);
unregister_mods(MOD_MASK_SHIFT);
}
} else if (keycode == PG_ODK) {
// Special behaviour of FR_ODK when shifted
// Shift must apply to the next keycode
return true;
} else if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_3PTS: // For Clever Keys
case PG_AROB:
case PG_K:
case PG_B:
case PG_APOS:
//case PG_BL:
//case PG_ECIR:
//case J_APOS:
case OU_GRV:
//case PG_CCED:
case KC_SPC: // When space is added by Clever Keys
case CNL_ODK:
break;
default:
tap_code(PG_ODK);
}
if (!is_apos_dr) {
switch (keycode) {
case PG_M:
case PG_C:
is_shifted = true;
}
}
if (is_shifted) {
is_shifted = false;
//set_mods(mods);
set_oneshot_mods(MOD_BIT(KC_LSFT));
}
}
}
return true;
}
/* void odk_layer_exit_check(uint16_t keycode) {
if (keycode == odk_keycode) {
layer_off(_ODK);
odk_keycode = KC_NO;
}
} */

View file

@ -1,52 +0,0 @@
#include "oneshot.h"
void update_oneshot(oneshot_state *state, uint16_t mod, uint16_t trigger, uint16_t keycode, keyrecord_t *record) {
if (keycode == trigger) {
if (record->event.pressed) {
// Trigger keydown
if (*state == os_up_unqueued) {
register_code(mod);
}
*state = os_down_unused;
} else {
// Trigger keyup
switch (*state) {
case os_down_unused:
// If we didn't use the mod while trigger was held, queue it.
*state = os_up_queued;
break;
case os_down_used:
// If we did use the mod while trigger was held, unregister it.
*state = os_up_unqueued;
unregister_code(mod);
break;
default:
break;
}
}
} else {
if (record->event.pressed) {
if (is_oneshot_cancel_key(keycode) && *state != os_up_unqueued) {
// Cancel oneshot on designated cancel keydown.
*state = os_up_unqueued;
unregister_code(mod);
}
} else {
if (!is_oneshot_ignored_key(keycode)) {
// On non-ignored keyup, consider the oneshot used.
switch (*state) {
case os_down_unused:
*state = os_down_used;
break;
case os_up_queued:
*state = os_up_unqueued;
unregister_code(mod);
break;
default:
break;
}
}
}
}
}

View file

@ -1,31 +0,0 @@
#pragma once
#include QMK_KEYBOARD_H
// Represents the four states a oneshot key can be in
typedef enum {
os_up_unqueued,
os_up_queued,
os_down_unused,
os_down_used,
} oneshot_state;
// Custom oneshot mod implementation that doesn't rely on timers. If a mod is
// used while it is held it will be unregistered on keyup as normal, otherwise
// it will be queued and only released after the next non-mod keyup.
void update_oneshot(
oneshot_state *state,
uint16_t mod,
uint16_t trigger,
uint16_t keycode,
keyrecord_t *record
);
// To be implemented by the consumer. Defines keys to cancel oneshot mods.
bool is_oneshot_cancel_key(uint16_t keycode);
// To be implemented by the consumer. Defines keys to ignore when determining
// whether a oneshot mod has been used. Setting this to modifiers and layer
// change keys allows stacking multiple oneshot modifiers, and carrying them
// between layers.
bool is_oneshot_ignored_key(uint16_t keycode);

View file

@ -1,115 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "os4a.h"
oneshot_state os_shft_state = os_up_unqueued;
oneshot_state os_ctrl_state = os_up_unqueued;
oneshot_state os_alt_state = os_up_unqueued;
oneshot_state os_altgr_state = os_up_unqueued;
oneshot_state os_win_state = os_up_unqueued;
uint8_t os4a_layer = 0;
static bool exit_os4a_layer = false;
//static bool pending_OSL = false;
void os4a_layer_on(uint8_t layer) {
layer_on(layer);
os4a_layer = layer;
}
void os4a_layer_off(uint8_t layer) {
layer_off(layer);
os4a_layer = 0;
exit_os4a_layer = false;
}
void os4a_tap(uint16_t keycode) {
if (os4a_layer == 0) {
// Activate OS4A layer
os4a_layer_on(get_os4a_layer(keycode));
} else {
// Press again an OS4A key to exit the OS4A layer and clear the OS mods.
os4a_layer_off(os4a_layer);
}
}
bool process_os4a_keys(uint16_t keycode, keyrecord_t *record) {
// tap action
if (record->event.pressed && record->tap.count) {
os4a_tap(keycode);
return false;
}
// normal processing if held
return true;
}
bool process_os4a_layers(uint16_t keycode, keyrecord_t *record) {
// Should keycode exit the OS4A layer ?
if (os4a_layer_changer(keycode)) { return true; }
if (is_oneshot_ignored_key(keycode)) { return false; }
// Add OS Shift when no other mods are active.
// Testing exit_os4a_layer is necessary to prevent OS shift to be added when other features create keyrecords
// to be processed (ex: custom altgr, clever keys).
uint8_t mods = get_mods() | get_oneshot_mods();
if (!exit_os4a_layer && to_be_shifted(keycode, record) && mods == 0) {
set_oneshot_mods(MOD_BIT(KC_LSFT));
}
return true;
}
void mouse_mods_key_up(uint16_t keycode, keyrecord_t *record) {
// The OS4A layer must be exited only when ctrl or shift are registered,
// not when the OSM are released without having being held.
//if (get_mods() & QK_ONE_SHOT_MOD_GET_MODS(keycode)) {
// When ctrl or shift are released after being held, exit the OS4A layer.
if (!record->event.pressed && !record->tap.count) {
os4a_layer_off(os4a_layer);
}
}
bool process_mods(uint16_t keycode, keyrecord_t *record) {
// Handling Callum's OSM on OS4A layers
update_oneshot(&os_shft_state, KC_LSFT, OS_SHFT, keycode, record);
update_oneshot(&os_ctrl_state, KC_LCTL, OS_CTRL, keycode, record);
update_oneshot(&os_alt_state, KC_LALT, OS_LALT, keycode, record);
update_oneshot(&os_altgr_state, KC_RALT, OS_RALT, keycode, record);
update_oneshot(&os_win_state, KC_LWIN, OS_WIN, keycode, record);
// Handling OS4A keys
if (IS_OS4A_KEY(keycode)) { return process_os4a_keys(keycode, record); }
// Behaviour of the OS4A layers
if (os4a_layer != 0) { exit_os4a_layer = process_os4a_layers(keycode, record); }
// Updating OSL status on OS4A layers
//pending_OSL = os4a_layer_changer(keycode);
// When Ctrl or Shift are released, for mouse use.
//if (mods_for_mouse(keycode)) { mouse_mods_key_up(keycode, record); }
return true;
}
void os4a_layer_exit_check(void) {
if (os4a_layer != 0 && exit_os4a_layer) { os4a_layer_off(os4a_layer); }
}

View file

@ -1,50 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "keymap.h"
#ifdef __cplusplus
extern "C" {
#endif
extern uint8_t os4a_layer;
//extern bool exit_os4a_layer;
//extern bool pending_OSL;
void os4a_layer_off(uint8_t layer);
void os4a_layer_on(uint8_t layer);
void os4a_tap(uint16_t keycode);
bool process_os4a_keys(uint16_t keycode, keyrecord_t *record);
void update_osl(uint16_t keycode);
bool process_os4a_layers(uint16_t keycode, keyrecord_t *record);
void mouse_mods_key_up(uint16_t keycode, keyrecord_t *record);
bool process_mods(uint16_t keycode, keyrecord_t *record);
void os4a_layer_exit_check(void);
#ifdef __cplusplus
}
#endif

View file

@ -1,97 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "tap_hold_utilities.h"
void tap_converter(uint16_t keycode, keyrecord_t *record) {
if (IS_OS4A_KEY(keycode)) {
// Instant OS4A processing
os4a_tap(keycode);
} else {
if (IS_QK_MOD_TAP(keycode) || IS_QK_LAYER_TAP(keycode)) {
// Tranform the record to send the tap event
//record->keycode = tap_hold_extractor(keycode);
record->keycode = (keycode &= 0xff);
}
process_record(record);
}
// Send the base keycode key up event
record->event.pressed = false;
process_record(record);
}
// Returns true if `pos` on the left hand of the keyboard, false if right.
bool on_left_hand(keypos_t pos) {
#ifdef SPLIT_KEYBOARD
return pos.row < MATRIX_ROWS / 2;
#else
return (MATRIX_COLS > MATRIX_ROWS) ? pos.col < MATRIX_COLS / 2
: pos.row < MATRIX_ROWS / 2;
#endif
}
bool same_side_combination(const keyrecord_t* tap_hold_record, const keyrecord_t* other_record) {
return on_left_hand(tap_hold_record->event.key) == on_left_hand(other_record->event.key);
}
// By default, use the BILATERAL_COMBINATIONS rule to consider the tap-hold key
// "held" only when it and the other key are on opposite hands.
__attribute__((weak)) bool forbidden_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record,
uint16_t other_keycode, keyrecord_t* other_record) {
return same_side_combination(tap_hold_record, other_record);
}
static bool process_tap_hold(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) { // On press
tap_code16(keycode);
return false;
}
return true;
}
bool process_custom_tap_hold(uint16_t keycode, keyrecord_t *record) {
if (record->tap.count) { // Handling of special tap-hold keys (on tap).
switch (keycode) {
/* case ALGR_T(PG_CACL):
return process_tap_hold(PG_CACL, record); */
case RCTL_T(FEN_B):
return process_tap_hold(LWIN(KC_DOWN), record);
case SFT_T(COPY):
return process_tap_hold(C(PG_C), record);
case LT_NUMWORD:
return process_numword(NUMWORD, record);
case LT_REPT:
repeat_key_invoke(&record->event);
return false;
case LT_MGC:
alt_repeat_key_invoke(&record->event);
return false;
}
}
return true; // Process all other keycodes normally
}

View file

@ -1,36 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "keymap.h"
#ifdef __cplusplus
extern "C" {
#endif
bool on_left_hand(keypos_t pos);
bool same_side_combination(const keyrecord_t* tap_hold_record, const keyrecord_t* other_record);
void tap_converter(uint16_t keycode, keyrecord_t *record);
bool process_custom_tap_hold(uint16_t keycode, keyrecord_t *record);
#ifdef __cplusplus
}
#endif

View file

@ -1,244 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "features_conf.h"
bool is_caps_lock_on(void) { return host_keyboard_led_state().caps_lock; }
bool isLetter(uint16_t keycode) {
switch (keycode) {
case KC_A ... KC_F:
case KC_H ... KC_N:
case KC_R ... KC_Z:
case PG_L:
case PG_X:
case PG_E:
//case PG_AGR:
//case PG_ECIR:
case KC_GRV ... KC_DOT:
return true;
default:
return false;
}
}
bool isSendStringMacro(uint16_t keycode) {
switch (keycode) {
//case AGRV_SPC:
//case CA_CED:
/* case L_APOS:
case D_APOS: */
case OU_GRV:
//case J_APOS:
//case PG_BL:
case MAGIC:
return true;
default:
return false;
}
}
// This function extracts the base keycode of MT and LT,
// even if the tap/hold key is a custom one, with non-basic tap keycode.
uint16_t tap_hold_extractor(uint16_t keycode) {
switch (keycode) {
default:
return keycode &= 0xff;
}
}
// Caps Word
bool caps_word_press_user(uint16_t keycode) {
// Caps Word shouldn't be applied with Alt-gr
// Managing underscore and slash on alt gr + E/T.
// Underscore and slash must continue Caps Word, without shifting.
if ((get_mods() & MOD_BIT(KC_ALGR))) {
switch (keycode) {
case PG_E:
case PG_T:
return true;
default:
return false;
}
}
if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_EACU:
case PG_B:
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
case PG_I:
case PG_F:
case PG_T:
return true;
case PG_L:
case PG_H:
case PG_VIRG:
case PG_V:
case PG_M:
case PG_C:
//case PG_T:
case PG_S:
return false;
}
}
// Keycodes that continue Caps Word, with shift applied.
// @ must be shifted, bc of CleverKeys using it.
if (isLetter(keycode) || isSendStringMacro(keycode) || keycode == PG_AROB) {
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
}
switch (keycode) {
// Keycodes that continue Caps Word, without shifting.
case PG_ODK:
//case PG_GRV:
case PG_UNDS:
case PG_MOIN:
case KC_KP_1 ... KC_KP_0:
case KC_LEFT:
case KC_RIGHT:
case KC_BSPC:
case KC_DEL:
case PG_APOS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
// One-shot 4 all configuration
uint8_t get_os4a_layer(uint16_t keycode) {
switch (keycode) {
case L_OS4A: return _L_MODS;
case R_OS4A: return _R_MODS;
default: return 0;
}
}
bool os4a_layer_changer(uint16_t keycode) {
switch (keycode) {
case OS_FA:
case NUMWORD:
case TG_FA:
//case TG_APOD:
return true;
default:
return false;
}
}
bool to_be_shifted(uint16_t keycode, keyrecord_t *record) {
// Combos and encoder events.
if (!IS_KEYEVENT(record->event)) { return true; }
switch (keycode) {
case KC_CAPS:
case CAPSWORD:
return false;
default:
return (os4a_layer == _R_MODS) == on_left_hand(record->event.key);
}
}
// Callum mods
bool is_oneshot_cancel_key(uint16_t keycode) {
switch (keycode) {
case L_OS4A:
case R_OS4A:
return true;
default:
return false;
}
}
bool is_oneshot_ignored_key(uint16_t keycode) {
// Alt-gr et shift s'appliquent à la touche typo, pour permettre de faire les majuscules plus facilement ainsi que ] avec.
// Autrement, la touche typo est ignorée par les Callum mods.
// Ça permet de transmettre les mods à la touche suivante, par ex pour faire Ctrl + K.
uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods();
//if (keycode == OS_ODK && (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR)))) { return true;}
if (keycode == OS_ODK && (mods & ~MOD_BIT(KC_ALGR))) { return true;}
switch (keycode) {
//case OS_ODK: /!\ A ne pas remettre, sous peine de ne pas pouvoir faire shift + typo + touche de l'autre côté
case L_OS4A:
case R_OS4A:
case OS_SHFT:
case OS_CTRL:
case OS_RALT:
case OS_LALT:
case OS_WIN:
case OS_FA:
case NUMWORD:
case TG_FA:
//case PG_ODK:
return true;
default:
return false;
}
}
// Repeat and Magic keys
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record, uint8_t* remembered_mods) {
switch (keycode) {
case KC_BSPC:
case LT_REPT:
case LT_MGC:
return false;
}
return true;
}
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
switch (keycode) {
case C(PG_Z):
return C(PG_Y);
case C(PG_Y):
return C(PG_Z);
}
/* if ((get_mods() | get_weak_mods()) & MOD_BIT(KC_ALGR)) {
return KC_SPC;
} */
if (recent[RECENT_SIZE - 1] != KC_NO) { return MAGIC; }
/* keycode = tap_hold_extractor(keycode);
if (isLetter(keycode)) { return MAGIC; }
switch (keycode) {
case PG_APOS:
case KC_SPC:
case
} */
return KC_TRNS; // Defer to default definitions.
}

View file

@ -1,30 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "keymap.h"
bool isLetter(uint16_t keycode);
bool isSendStringMacro(uint16_t keycode);
bool is_caps_lock_on(void);
uint16_t tap_hold_extractor(uint16_t keycode);
uint8_t get_os4a_layer(uint16_t keycode);
bool os4a_layer_changer(uint16_t keycode);
bool to_be_shifted(uint16_t keycode, keyrecord_t *record);
//bool mods_for_mouse(uint16_t keycode);

View file

@ -1,326 +0,0 @@
/* Copyright 2019 Thomas Baart <thomas@splitkb.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
#include "keymap.h"
#include "features/layer_lock.h"
bool is_caps_lock_on(void) { return host_keyboard_led_state().caps_lock; }
bool isLetter(uint16_t keycode) {
switch (keycode) {
case KC_A ... KC_L:
case PG_M:
case KC_N ... KC_Z:
case PG_AGRV:
case PG_U:
case PG_EGRV:
case PG_CCED:
return true;
default:
return false;
}
}
// Achordion
uint16_t achordion_timeout(uint16_t tap_hold_keycode) { return 500; }
bool achordion_eager_mod(uint8_t mod) {
switch (mod) {
case MOD_LSFT:
case MOD_RSFT:
case MOD_LCTL:
case MOD_RCTL:
return true; // Eagerly apply Shift and Ctrl mods.
default:
return false;
}
}
// Caps Word
bool caps_word_press_user(uint16_t keycode) {
// Keycodes that continue Caps Word, with shift applied.
if (isLetter(keycode)) {
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
} else {
switch (keycode) {
// Keycodes that continue Caps Word, without shifting.
case PG_MOIN:
case KC_KP_1 ... KC_KP_0:
case KC_LEFT:
case KC_RIGHT:
case KC_BSPC:
case KC_DEL:
case PG_APOS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
}
// Combo
combo_t key_combos[] = {};
uint16_t COMBO_LEN = 0;
// Custom altGr keys
const custom_altgr_key_t custom_altgr_keys[] = {
{PG_AGRV, PG_AE},
{PG_B, PG_TS},
{PG_A, PG_CDAQ},
{PG_I, PG_RDAQ},
{PG_N, PG_ESPR},
{PG_T, PG_AROB},
{ALGR_T(PG_A), PG_CDAQ},
{LCTL_T(PG_I), PG_RDAQ},
{RCTL_T(PG_N), PG_ESPR},
{ALGR_T(PG_T), PG_AROB},
{PG_POIN, PG_NM},
{KC_KP_8, PG_INFN},
{PG_F, PG_HASH},
{PG_G, PG_HEG},
{PG_CCED, PG_DEDL},
{PG_Q, PG_TECT},
{PG_X, PG_PVIR},
{PG_D, PG_DOPY},
};
uint8_t NUM_CUSTOM_ALTGR_KEYS =
sizeof(custom_altgr_keys) / sizeof(custom_altgr_key_t);
void matrix_scan_user(void) {
//achordion_task();
recent_keys_task();
swapper_task();
}
// Tap-hold configuration
// Handle keyrecord before quantum processing
static uint16_t next_keycode;
static keyrecord_t next_record;
bool pre_process_record_user(uint16_t keycode, keyrecord_t *record) {
static uint16_t prev_keycode;
static bool tap_condition;
if (record->event.pressed) {
// Store the previous keycode for instant tap decision
prev_keycode = next_keycode;
// Cache the next input for mod-tap decisions
next_keycode = keycode;
next_record = *record;
}
// Match mod-tap keys. Tweak this to limit conditions that matches your keyboard and habits.
tap_condition = ((IS_LAYER_ON(_BASE)) && IS_QK_MOD_TAP(keycode) && !IS_QK_LAYER_TAP(prev_keycode) && !is_mod_tap_control(prev_keycode));
return process_instant_tap(keycode, record, prev_keycode, tap_condition);
}
bool forbidden_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record, uint16_t other_keycode, keyrecord_t* other_record) {
switch (tap_hold_keycode) {
case LT_VIRG:
case OSM(MOD_LSFT):
case OSM(MOD_RSFT):
return false;
default:
// Otherwise, follow the opposite hands rule.
return same_side_combination(tap_hold_record, other_record);
}
}
bool first_of_chorded_mods(uint16_t keycode) {
switch (keycode) {
case LT_TAB: // Pour pouvoir faire OSM shift + LT_TAB (win + shift + flèche).
case PG_CCED: // Pour pouvoir faire Alt + F4, Alt + F11.
case LCTL_T(PG_I):
case RCTL_T(PG_N):
case OSM(MOD_LSFT): // Pour pouvoir faire OSM shift + LT_TAB (win + shift + flèche).
return true;
default:
return false;
}
}
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
if (record->event.key.col != next_record.event.key.col) {
// Sinon on a des effets de bord quand on veut taper des chiffres.
if (IS_LAYER_ON(_BASE)) {
// When a mod-tap key overlaps with another non-Ctrl key on the same hand, send its base keycode
if (forbidden_chord(keycode, record, next_keycode, &next_record) && !first_of_chorded_mods(keycode)) {
tap_converter(keycode, record);
}
}
}
return false;
}
bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
if (forbidden_chord(keycode, record, next_keycode, &next_record)) {
tap_converter(keycode, record);
return false;
}
return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// Achordion
//if (!process_achordion(keycode, record)) { return false; }
// Custom alt gr
if (!process_custom_altgr_keys(keycode, record)) { return false; }
// Recent keys
if (!process_clever_keys(keycode, record)) { return false; }
// Numword
if (!process_numword(keycode, record)) { return false; }
// Layer lock
if (!process_layer_lock(keycode, record, LAYER_LCK)) { return false; }
// Select word
if (!process_select_word(keycode, record, SELWORD)) { return false; }
// Macros
if (!process_macros(keycode, record)) { return false; }
return true; // Process all other keycodes normally
}
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/*
* Base Layer: ALPHAS
*»\
* ,-------------------------------------------. ,-------------------------------------------.
* | Helpsc | À | B | É | . | - | | ^ | V | L | M | X | W |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|0
* | Enter | O | U |A/AltG|I/Ctrl| J | | G | T | S | N | R | F |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | Tab | Q | Y | È |P/Win | "" | Bksp | End | | Home |Delete| K | D | Z | H | C | Ç/Alt |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* |NavNum| Space|Shift | E | , | | ' | Space|Shift| Win | Mute |
* | | | |NavNum|Symb. | |Funct.|NavNum| | | |
* `----------------------------------' `----------------------------------'
*/
[_BASE] = LAYOUT(
KC_ESC, PG_AGRV, PG_B, PG_U, PG_X, PG_MOIN, PG_ACIR, PG_G, PG_C, PG_M, PG_POIN, PG_W,
KC_ENT, ALT_T(PG_O), SFT_T(PG_L), ALGR_T(PG_A), LCTL_T(PG_I), PG_J, PG_VIRG, RCTL_T(PG_N), ALGR_T(PG_T), RSFT_T(PG_S), ALT_T(PG_R), PG_V,
LT_TAB, PG_Q, PG_Y, PG_EGRV, LWIN_T(PG_P), PG_HQUO, KC_BSPC, KC_END, KC_HOME, KC_DEL, PG_K, RWIN_T(PG_H), PG_Z, PG_F, PG_D, PG_CCED,
TG(_SYMBOLS), KC_SPC, OSM(MOD_LSFT), LT(_SYMBOLS,PG_E), LT_VIRG, LT_APOS, LT(_SYMBOLS,KC_SPC), OSM(MOD_RSFT), KC_RGUI, KC_MUTE
),
/*
* Layer 1 : Numpad + symbols
*
* ,-------------------------------------------. ,-------------------------------------------.
* | Helpsc | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) | LOCK | | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | |Expos.| 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_SYMBOLS] = LAYOUT(
KC_ESC, PG_EXCL, PG_QUES, PG_ESPR, PG_PVIR, PG_PIPE, PG_MOIN, KC_P7, KC_P8, KC_P9, PG_ASTX, KC_NUM,
_______, PG_CACL, SFT_T(PG_RACL), ALGR_T(PG_LPRN), PG_RPRN, LAYER_LCK, PG_EGAL, RCTL_T(KC_P4), ALGR_T(KC_P5), KC_P6, PG_TLSH, PG_BSLS,
_______, PG_CBKT, PG_RBKT, PG_INF, PG_SUP, PG_CARN, _______, _______, _______, _______, PG_ACIR, KC_P1, KC_P2, KC_P3, PG_PLUS, PG_PERC,
_______, _______, _______, KC_SPC, PG_EACU, NUMWORD, KC_P0, KC_PDOT, _______ , _______
),
/*
* Layer 2 : Symbols + function keys
*
* ,-------------------------------------------. ,-------------------------------------------.
* | Helpsc | F1 | F2 | F3 | F4 | F5 | | | ; | ! | # | ° | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | |Ctrl A|Ctrl X|Ctrl V|Ctrl C| LOCK | | Mute | ( | ) | @ | & | Mute |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | F6 | F7 | F8 | F9 | F10 | | | | | | |Ctrl Z|Ctrl Y| F11 | F12 | |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | | | | |
* | | | | | | | !!! | , | | | |
* `----------------------------------' `----------------------------------'
*/
[_SHORTNAV] = LAYOUT(
KC_ESC, A(KC_F4), ALT_TAB, LWIN(PG_G), _______, _______, _______, C(KC_LEFT), KC_UP, C(KC_RIGHT), _______, _______,
_______, C(PG_A), C(PG_POIN), C(PG_G), C(PG_D), LAYER_LCK, KC_MUTE, RCTL_T(KC_LEFT), KC_DOWN, KC_RIGHT, KC_F2 , KC_MUTE,
_______, SELWORD, LWIN(KC_TAB), REV_TAB, ALT_TAB, _______, _______, S(KC_END), S(KC_HOME), _______, _______, C(PG_Z), C(PG_Y), _______, _______, _______,
_______, _______, _______, QUES_PT, QUES_PT, EXCL_PT, EXCL_PT, _______, _______, _______
),
/*
* Layer 3 : Function keys + windows management
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | F12 | F7 | F8 | F9 | | | | | | | | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | F11 | F4 | F5 | F6 | LOCK | | | | | | | |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | F10 | F1 | F2 | F3 | | | | | | | | | | | | |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* `----------------------------------' `----------------------------------'
*/
[_FUNCAPPS] = LAYOUT(
KC_ESC, KC_F12, KC_F9, KC_F8, KC_F7, C(KC_PAUS), _______, SWIN(KC_LEFT), LWIN(KC_UP), SWIN(KC_RIGHT), _______, QK_BOOT,
_______, ALT_T(KC_F11), SFT_T(KC_F6), KC_F5, KC_F4, LAYER_LCK, _______, RCTL_T(FEN_G), LWIN(KC_DOWN), LWIN(KC_RIGHT), _______, _______,
_______, KC_F10, KC_F3, KC_F2, KC_F1, _______, _______, _______, _______, _______, _______, LWIN(PG_H), LWIN(KC_HOME), _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______
),
// /*
// * Layer template
// *
// * ,-------------------------------------------. ,-------------------------------------------.
// * | | | | | | | | | | | | | |
// * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
// * | | | | | | | | | | | | | |
// * |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
// * | | | | | | | | | | | | | | | | | |
// * `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
// * | | | | | | | | | | | |
// * | | | | | | | | | | | |
// * `----------------------------------' `----------------------------------'
// */
// [_LAYERINDEX] = LAYOUT(
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
// ),
};

View file

@ -1,318 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
#include "keymap.h"
uint16_t global_quick_tap_timer = 0;
// Tap-hold configuration
bool forbidden_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record, uint16_t other_keycode, keyrecord_t* other_record) {
switch (tap_hold_keycode) {
case LT_REPT:
case LT_MGC:
return false;
}
// Otherwise, follow the opposite hands rule.
return same_side_combination(tap_hold_record, other_record);
}
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
if (record->event.key.col != next_record.event.key.col) {
// La ligne suivante n'est nécessaire que si on a besoin de doubler rapidement un caractère présent sur la moitié droite du clavier.
// Ce n'est pas nécessaire pour l'instant, vu que les guillemets sont passés à gauche.
//if (keycode == OS_ODK) { return true; }
if (forbidden_chord(keycode, record, next_keycode, &next_record)) {
// When a layer-tap key overlaps with another key on the same hand, send its base keycode.
tap_converter(keycode, record);
}
}
return false;
}
/* bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
return !forbidden_chord(keycode, record, next_keycode, &next_record);
} */
// Matrix scan
void matrix_scan_user(void) {
recent_keys_task();
//swapper_task();
}
// Key processing
uint16_t next_keycode;
keyrecord_t next_record;
bool pre_process_record_user(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
// Cache the next input for mod-tap decisions
next_keycode = keycode;
next_record = *record;
}
return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// Global quick tap for combos.
// IS_KEYEVENT prevents combos from updating global_quick_tap_timer, to allow combos to be chained.
if ((IS_KEYEVENT(record->event) && get_highest_layer(layer_state) == _BASE) && !IS_OS4A_KEY(keycode)) {
global_quick_tap_timer = timer_read();
}
// Multi One-Shot Mods
if (!process_mods(keycode, record)) { return false; }
// Numword
if (!process_numword(keycode, record)) { return false; }
// Custom tap-hold keys
if (!process_custom_tap_hold(keycode, record)) { return false; }
// Macros
if (!process_macros(keycode, record)) { return false; }
// Custom behaviour of the typo dead-key
if (!process_odk_layer(keycode, record)) { return false; }
// Clever keys
if (!process_clever_keys(keycode, record)) { return false; }
// Process all other keycodes normally
return true;
}
void post_process_record_user(uint16_t keycode, keyrecord_t* record) {
//if (os4a_layer != 0 && exit_os4a_layer) { os4a_layer_off(os4a_layer); }
os4a_layer_exit_check();
numword_exit_check();
//odk_layer_exit_check(keycode);
end_CK(record);
}
// Keymap
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/*
* Base Layer: ALPHAS
*»\
* ,-------------------------------------------. ,-------------------------------------------.
* | | X | È | É | . | K | | V | B | L | M | X | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | Enter | O | U | A | I | J | | G | T | S | N | R | F |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | Tab | Q | Z | W | P | | | | | | | | D | Y | H | C | Ç |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | |Shift | E | , | | ' | Space| Shift| | |
* | | | |NavNum|Symb. | |Funct.|NavNum| | | |
* `----------------------------------' `----------------------------------'
*/
[_BASE] = LAYOUT(
KC_NO, PG_POIN, PG_EACU, PG_U, PG_P, PG_APOS, PG_V, PG_M, PG_C, PG_J, PG_X, KC_NO,
KC_NO, PG_O, PG_A, PG_I, PG_N, PG_VIRG, PG_G, PG_T, PG_S, PG_R, PG_L, KC_NO,
KC_NO, PG_Q, PG_Z, PG_Y, PG_H, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, PG_D, PG_F, PG_W, OS_ODK, KC_NO,
KC_NO, KC_SPC, L_OS4A, LT_E, LT_MGC, LT_REPT, LT_SPC, R_OS4A, KC_RGUI, KC_NO
),
/*
* Layer 1 : Mods gauche
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) | LOCK | | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | |Expos.| 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_L_MODS] = LAYOUT(
KC_NO, KC_NO, KC_NO, OS_WIN, KC_RGUI, KC_NO, _______, _______, _______, _______, _______, _______,
KC_NO, OS_RALT, OS_FA, OS_CTRL, OS_SHFT, KC_NO, _______, _______, _______, _______, _______, _______,
KC_NO, OS_LALT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, _______, _______, _______, _______, _______, _______, _______, _______,
KC_NO, KC_NO, _______, _______, _______, CAPSWORD, _______, KC_CAPS, _______, _______
),
/*
* Layer : Mods droite
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) | LOCK | | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | |Expos.| 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_R_MODS] = LAYOUT(
_______, _______, _______, _______, _______, _______, KC_NO, KC_RGUI, OS_WIN, TG_APOS, KC_NO, KC_NO,
_______, _______, _______, _______, _______, _______, TG_FA, OS_SHFT, OS_CTRL, NUMWORD, PG_ODK, KC_NO,
_______, _______, _______, _______, _______, _______, _______, _______, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, OS_FA, OS_LALT, KC_NO,
_______, _______, _______, _______, _______, _______, _______, _______, KC_NO, KC_NO
),
/*
* Layer : Symbols
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ^ | { | } | $ | # | | % | " | = | ! | ` | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | ? | ( | ) | ; | : | | \ | / | - | + | * | |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | < | [ | ] | > | | | | | | | | ' | & | | | ~ | |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* `----------------------------------' `----------------------------------'
*/
[_SYMBOLS] = LAYOUT(
_______, PG_ACIR, PG_LCBR, PG_RCBR, PG_DLR, PG_HASH, PG_PERC, PG_DQUO, PG_EGAL, ALGR(PG_APOS), PG_GRV, _______,
_______, ALGR(PG_O), PG_LPRN, PG_RPRN, PG_PVIR, ALGR(PG_VIRG), PG_BSLS, MT_SLSH, PG_MOIN, PG_PLUS, PG_ASTX, _______,
_______, PG_INF, PG_LSBR, PG_RSBR, PG_SUP, _______, _______, _______, _______, _______, _______, PG_APOD, PG_ESPR, PG_PIPE, PG_TILD, _______,
_______, _______, _______, PG_UNDS, KC_SPC, PG_APOS, _______, _______, _______, _______
),
/*
* Layer 1 : Numpad
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) | LOCK | | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | |Expos.| 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_NUMBERS] = LAYOUT(
_______, PG_DLR, PG_MOIN, PG_PLUS, KC_7, S(PG_ACIR), PG_PERC, _______, PG_EGAL, PG_ASTX, _______, _______,
_______, KC_4, KC_3, KC_2, MT_1, PG_CARN, _______, MT_SLSH, KC_6, KC_7, KC_8, _______,
_______, _______, _______, _______, KC_5, _______, _______, _______, _______, _______, _______, KC_9, KC_6, _______, PG_ODK, _______,
_______, _______, KC_PDOT, KC_0 , LT_NUMWORD, LT_REPT, KC_SPC, KC_PDOT, _______, _______
),
/*
* Layer 2 : Symbols
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) |Expos.| | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | | | 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_ODK] = LAYOUT(
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, OU_GRV, _______, _______, PG_T, _______, _______, PG_R, _______, PG_AROB, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, PG_K, CNL_ODK, _______,
_______, _______, _______, _______, PG_O, PG_APOS, PG_B, _______, _______, _______
),
/*
* Layer 3 : Symbols + function keys
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | F1 | F2 | F3 | F4 | F5 | | | ; | ! | # | ° | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | |Ctrl A|Ctrl X|Ctrl V|Ctrl C| LOCK | | Mute | ( | ) | @ | & | Mute |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | F6 | F7 | F8 | F9 | F10 | | | | | | |Ctrl Z|Ctrl Y| F11 | F12 | |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | | | | |
* | | | | | | | !!! | , | | | |
* `----------------------------------' `----------------------------------'
*/
[_SHORTNAV] = LAYOUT(
_______, KC_BSPC, LWIN(KC_TAB), LWIN(PG_V), RCS(PG_V), KC_VOLU, KC_PGUP, C(KC_LEFT), KC_UP, C(KC_RGHT), _______, _______,
_______, C(PG_A), C(PG_X), C(PG_V), SFT_T(COPY), KC_VOLD, KC_PGDN, KC_LEFT, KC_DOWN, KC_RIGHT, KC_F2 , _______,
_______, KC_SPC, KC_SPC, KC_MUTE, C(PG_Z), C(PG_Y), _______, _______, _______, _______, _______, C(KC_PGUP), C(KC_PGDN), C(PG_W), _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______
),
/*
* Layer 4 : Function keys + windows management
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | F12 | F7 | F8 | F9 | | | | | | | | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | F11 | F4 | F5 | F6 | LOCK | | | | | | | |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | F10 | F1 | F2 | F3 | | | | | | | | | | | | |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | | | | |au
* | | | | | | | | | | | |
* `----------------------------------' `----------------------------------'
*/
[_FUNCAPPS] = LAYOUT(
_______, KC_F12, KC_F9, KC_F8, KC_F7, QK_BOOT, _______, SWIN(KC_LEFT), LWIN(KC_UP), SWIN(KC_RIGHT), KC_NUM, _______,
_______, KC_F11, KC_F6, KC_F5, SFT_T(KC_F4), C(KC_PAUS), TG_FA, LWIN(KC_LEFT), RCTL_T(FEN_B), LWIN(KC_RIGHT), A(KC_ESC), _______,
_______, ALT_T(KC_F10), KC_F3, KC_F2, KC_F1, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______
),
// /*
// * Layer template
// *
// * ,-------------------------------------------. ,-------------------------------------------.
// * | | | | | | | | | | | | | |
// * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
// * | | | | | | | | | | | | | |
// * |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
// * | | | | | | | | | | | | | | | | | |
// * `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
// * | | | | | | | | | | | |
// * | | | | | | | | | | | |
// * `----------------------------------' `----------------------------------'
// */
// [_LAYERINDEX] = LAYOUT(
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
// ),
};

View file

@ -1,100 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include QMK_KEYBOARD_H
#include "keymap_french_propergol.h"
#include "features_conf.h"
#include "clever_keys.h"
#include "features/tap_hold_utilities.h"
#include "features/clever_keys_utilities.h"
#include "features/numword.h"
#include "features/macros.h"
#include "features/os4a.h"
#include "features/oneshot.h"
#include "features/odk_layer.h"
enum layers {
_BASE = 0,
//_APOS_DR,
// OS4A layers should be as closed as base layer as possible
_L_MODS,
_R_MODS,
_ODK,
_SYMBOLS,
_NUMBERS,
_SHORTNAV,
_FUNCAPPS,
};
enum custom_keycodes {
NUMWORD = SAFE_RANGE,
FEN_B,
COPY,
AIDE_MEM,
OS4A,
RAZ,
CAPSWORD,
OU_GRV,
//J_APOS,
//E_CIRC,
/* I_CIRC,
A_CIRC,
O_CIRC,
U_CIRC,
I_TREM,*/
MAGIC,
OS_SHFT,
OS_CTRL,
OS_RALT,
OS_LALT,
OS_WIN,
//OS_ODK,
CNL_ODK,
TG_APOS,
//PG_BL
/* L_APOS,
D_APOS */
};
// Layer taps
#define LT_SPC LT(_SYMBOLS, KC_SPC)
#define LT_E LT(_SYMBOLS, PG_E)
#define LT_REPT LT(_NUMBERS, KC_1)
#define LT_MGC LT(_SHORTNAV, KC_1)
#define OS_FA OSL(_FUNCAPPS)
#define TG_FA TT(_FUNCAPPS)
//#define TG_APOD TG(_APOS_DR)
#define MT_SLSH SFT_T(PG_SLSH)
#define MT_1 SFT_T(KC_1)
#define LT_NUMWORD LT(_SHORTNAV, NUMWORD)
#define E_CIRC S(FG_0)
#define OS_ODK OSL(_ODK)
// One shot mods
#define L_OS4A LSFT_T(OS4A)
#define R_OS4A RSFT_T(OS4A)
#define IS_OS4A_KEY(keycode) (get_os4a_layer(keycode) != 0)
bool forbidden_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record, uint16_t other_keycode, keyrecord_t* other_record);
extern uint16_t global_quick_tap_timer;
extern uint16_t next_keycode;
extern keyrecord_t next_record;

View file

@ -1,232 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "keycodes.h"
//#include "keymap.h"
// clang-format off
/*
*
*  `  1  2  3  4  5  6  7  8  9  0  /  =        
*
*       .  É  U  P  B  V  M  C    X  '  -      
*     
*        O  A  I  N  ,  G  T  S  R  L  [  ]     
*
*      E  Q  Z  Y  H  J  K  D  F  W  **          
*
*                                                     
*
*/
// Row 1
#define PG_GRV KC_GRV // `
#define FG_1 KC_1 // 1
#define FG_2 KC_2 // 2
#define FG_3 KC_3 // 3
#define FG_4 KC_4 // 4
#define FG_5 KC_5 // 5
#define FG_6 KC_6 // 6
#define FG_7 KC_7 // 7
#define FG_8 KC_8 // 8
#define FG_9 KC_9 // 9
#define FG_0 KC_0 // 0
#define PG_SLSH KC_MINS // /
#define PG_EGAL KC_EQL // =
// Row 2
#define PG_POIN KC_Q // .
#define PG_EACU KC_W // É
#define PG_U KC_E // U
#define PG_P KC_R // P
#define PG_B KC_T // B
#define PG_V KC_Y // V
#define PG_M KC_U // M
#define PG_C KC_I // C
#define PG_APOS KC_O //
#define PG_X KC_P // X
#define PG_APOD KC_LBRC // '
#define PG_MOIN KC_RBRC // -
// Row 3
#define PG_O KC_A // O
#define PG_A KC_S // A
#define PG_I KC_D // I
#define PG_N KC_F // N
#define PG_VIRG KC_G // ,
#define PG_G KC_H // G
#define PG_T KC_J // T
#define PG_S KC_K // S
#define PG_R KC_L // R
#define PG_L KC_SCLN // L
#define PG_LSBR KC_QUOT // [
#define PG_RSBR KC_NUHS // ]
// Row 4
#define PG_E KC_NUBS // E
#define PG_Q KC_Z // Q
#define PG_Z KC_X // Z
#define PG_Y KC_C // Y
#define PG_H KC_V // H
#define PG_J KC_B // J
#define PG_K KC_N // K
#define PG_D KC_M // C
#define PG_F KC_COMM // H
#define PG_W KC_DOT // W
#define PG_ODK KC_SLSH // **
/* Shifted symbols
*
*  ~  |  <  >  $  %  ^  &  _  #  @  *  \        
*
*       ?                       !     " │ + │     │
*     
*                    :                          
*
*                                    ;           
*
*                                                     
*
*/
// Row 1
#define PG_TILD S(KC_GRV) // ~
#define PG_PIPE S(KC_1) // |
#define PG_INF S(KC_2) // <
#define PG_SUP S(KC_3) // >
#define PG_DLR S(KC_4) // $
#define PG_PERC S(KC_5) // %
#define PG_ACIR S(KC_6) // ^
#define PG_ESPR S(KC_7) // &
#define PG_UNDS S(KC_8) // _
#define PG_HASH S(KC_9) // #
#define PG_AROB S(KC_0) // @
#define PG_ASTX S(PG_SLSH) // *
#define PG_BSLS S(PG_EGAL) // '\'
// Row 2
#define PG_QUES S(PG_POIN) // ?
#define PG_EXCL S(PG_APOS) // !
#define PG_DQUO S(PG_APOD) // "
#define PG_PLUS S(PG_MOIN) // +
//#define PG_DIFF S(PG_EGAL) // ≠
// Row 3
#define PG_2PTS S(PG_VIRG) // :
// Row 4
#define PG_PVIR S(PG_ODK)
// Row 5
#define PG_NBSP S(KC_SPC) // Espace insecable
/* AltGr symbols
*
*                                    
*
*       ^  {  }  $  #  %  " │ = │ ! │ ` │   │   │     │
*     
*        ?  (  )  ;  :  \  /  -  +  *           
*
*      _  <  [  ]  >  @     '  &  |  ~           
*
*                                                     
*
*/
// Row 1
#define PG_3PTS ALGR(KC_GRV) // …
//#define PG_ECIR ALGR(PG_ASTX)
// Row 2
//#define PG_ACIR ALGR(PG_POIN) // ^
//#define PG_EXCL ALGR(PG_EACU) // !
//#define PG_PVIR ALGR(PG_M) // ;
//#define PG_QUES ALGR(PG_APOS) // ?
//#define PG_2PTS ALGR(PG_X) // :
// Row 3
/*
#define PG_PLUS ALGR(PG_A) // +
#define PG_SLSH ALGR(PG_N) // /
#define PG_MOIN ALGR(PG_I) // -
#define PG_BSLS ALGR(PG_VIRG) // '\'
#define PG_GRV ALGR(PG_G) // `*/
#define PG_LPRN ALGR(PG_A) // (
#define PG_RPRN ALGR(PG_I) // )
//#define PG_INF ALGR(PG_R) // <
//#define PG_SUP ALGR(PG_L) // >
//#define PG_HQUO ALGR(PG_L) // "
//#define PG_AROB ALGR(PG_J)
// Row 4
//#define PG_UNDS ALGR(PG_E) // _
//#define PG_TILD ALGR(PG_Q) // ~
//#define PG_PIPE ALGR(PG_Z) // |
//#define PG_ESPR ALGR(PG_Y) // &
//#define PG_DQUO ALGR(PG_H) // "
#define PG_LCBR ALGR(PG_EACU) // {
#define PG_RCBR ALGR(PG_U) // }
//#define PG_LSBR ALGR(PG_W) // [
//#define PG_RSBR ALGR(PG_ODK) // ]
/* Shift+AltGr symbols
*
*   ̑                  ̏                          
*
*       *^ ¬    *¤ *˚           *ˇ           
*     
*        ×  ±  *¯ ÷    *` *´    *˘ *          
*
*           *~ ¦           *¸ *, *˛             
*
*                                                     
*
*/
#define PG_CARN S(ALGR(PG_X)) // ˇ (dead)
/* // Row 1
#define PG_IBRV S(ALGR(PG_AROB)) //  ̑ (dead)
#define PG_HACU S(ALGR(PG_LPRN)) // ˝ (dead)
#define PG_HGRV S(ALGR(PG_RPRN)) //  ̏ (dead)
#define PG_MDSH S(ALGR(PG_RSQU)) // —
#define PG_CSAQ S(ALGR(PG_CDAQ)) //
#define PG_RSAQ S(ALGR(PG_RDAQ)) //
#define PG_IQUE S(ALGR(PG_APOS)) // ¿
// Row 2
#define PG_NM S(ALGR(PG_N)) // ™
#define PG_HOTB S(ALGR(PG_I)) //  ̣ (dead)
#define PG_PERM S(ALGR(PG_P)) // ‰
#define PG_SBHY S(ALGR(PG_MOIN)) // (non-breaking hyphen)
#define PG_HDAG S(ALGR(PG_PLUS)) // ‡
// Row 3
#define PG_MACB S(ALGR(PG_F)) // ˍ (dead)
#define PG_TQRT S(ALGR(PG_SLSH)) // √
#define PG_QRTR S(ALGR(PG_ASTX)) // ¼
// Row 4
#define PG_VIRGEQL S(ALGR(PG_INF)) // ≥
#define PG_OGON S(ALGR(PG_G)) // ˛ (dead)
#define PG_IEXL S(ALGR(PG_EACU)) //  ̦ (dead)
//#define PG_SEQL S(ALGR(PG_EGAL)) // ≠ */

View file

@ -1,163 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
#include "keymap.h"
oled_rotation_t oled_init_user(oled_rotation_t rotation) { return OLED_ROTATION_180; }
bool oled_task_user(void) {
if (is_keyboard_master()) {
// QMK Logo and version information
// clang-format off
static const char PROGMEM qmk_logo[] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
// clang-format on
oled_write_P(qmk_logo, false);
oled_write_P(PSTR("\n"), false);
//oled_write_P(PSTR("Kyria rev2.1\n"), false);
// Host Keyboard Layer Status
oled_write_P(PSTR("Layer: "), false);
switch (get_highest_layer(layer_state|default_layer_state)) {
case _BASE:
oled_write_P(PSTR("Propergol\n"), false);
break;
case _L_MODS:
oled_write_P(PSTR("Mods G\n"), false);
break;
case _R_MODS:
oled_write_P(PSTR("Mods D\n"), false);
break;
case _SYMBOLS:
oled_write_P(PSTR("Symboles\n"), false);
break;
case _NUMBERS:
oled_write_P(PSTR("Nombres\n"), false);
break;
case _SHORTNAV:
oled_write_P(PSTR("ShortNav\n"), false);
break;
case _FUNCAPPS:
oled_write_P(PSTR("FuncApps\n"), false);
break;
case _ODK:
oled_write_P(PSTR("1DK\n"), false);
break;
default:
oled_write_P(PSTR("Undefined\n"), false);
}
// Statut des mods
const uint8_t mods = (get_mods() | get_oneshot_mods());
//bool is_shift_active = ((mods | get_oneshot_mods()) & MOD_MASK_SHIFT);
//oled_write_P(is_shift_active ? PSTR("SHIFT ") : PSTR(" "), false);
oled_write_P((mods & MOD_MASK_SHIFT) ? PSTR("SHIFT ") : PSTR(" "), false);
oled_write_P((mods & MOD_MASK_CTRL) ? PSTR("CTRL ") : PSTR(" "), false);
oled_write_P(((mods & MOD_BIT(KC_RALT)) == MOD_BIT(KC_RALT)) ? PSTR("ALT GR ") : PSTR(" "), false);
oled_write_P(((mods & MOD_BIT(KC_LALT)) == MOD_BIT(KC_LALT)) ? PSTR("ALT ") : PSTR(" "), false);
oled_write_P(is_caps_word_on() ? PSTR("CAPSWORD\n") : PSTR(" \n"), false);
oled_write_P(is_num_word_on ? PSTR("NUMWORD\n") : PSTR(" \n"), false);
// Write host Keyboard LED Status to OLEDs
led_t led_usb_state = host_keyboard_led_state();
oled_write_P(led_usb_state.num_lock ? PSTR("NUMLCK ") : PSTR(" "), false);
oled_write_P(led_usb_state.caps_lock ? PSTR("CAPLCK ") : PSTR(" "), false);
oled_write_P(led_usb_state.scroll_lock ? PSTR("SCRLCK ") : PSTR(" "), false);
} else {
// clang-format off
static const char PROGMEM Gentleman_logo[] = {
// 'Gentleman', 128x64px
// 'OLED', 128x64px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xe0, 0xf0, 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0,
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfe,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf0,
0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xce, 0xce, 0xce, 0x0e, 0x0e, 0x4e, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0xc3,
0xf9, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xf9, 0xe3, 0x07, 0x3f,
0xff, 0xff, 0xff, 0xff, 0xfc, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0x0f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x1f,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xe0, 0x87,
0x9f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x1f, 0x8f, 0xe0, 0xf8,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0xfe, 0xff, 0x07, 0x03, 0x03, 0x7f, 0x7f, 0x3f, 0x3f, 0x1f, 0x8f, 0x87, 0xc3, 0xe3, 0xff, 0xff,
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x3f, 0x3f, 0x3f,
0x3f, 0x3f, 0x3e, 0x7e, 0x7c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
0xff, 0xff, 0xc0, 0x80, 0x80, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xe1, 0xc3, 0xc7, 0x8f, 0xff, 0xff,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x1f, 0x7f, 0xff, 0xff, 0xf3, 0xe1, 0xcf, 0x8f, 0x8f, 0x87,
0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xc0, 0x80,
0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x87, 0x8f, 0x8f, 0x8f, 0xc5, 0xe1, 0xff,
0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xe0, 0xf1, 0x71, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x31, 0xf1, 0xe0,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x3f,
0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x1f, 0x0f, 0x07,
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x0f, 0x1f, 0x1c, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x18, 0x1f, 0x0f,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// clang-format on
oled_write_raw_P(Gentleman_logo, sizeof(Gentleman_logo));
}
return false;
}

View file

@ -1,249 +0,0 @@
# Kyria's Default Keymap
![KLE render of the default Kyria keymap with QWERTY as the base layer. Layers are shown in sublegends.](https://i.ibb.co/RQZx2dY/default-kyria2.jpg)
The default keymap contains 5 layers which allows it to include all keys found on an ANSI layout TKL keyboard plus media keys.
Hardware features of the Kyria such as OLEDs, rotary encoders and underglow are also supported.
The five different layers are the following:
1. Base layer (QWERTY, Colemak-DH or Dvorak)
2. Navigation layer
3. Symbols/Numbers layer
4. Function layer
5. Adjust layer
## Base layer(s)
```
Base Layer: -
,-------------------------------------------. ,-------------------------------------------.
| Tab | - | - | - | - | - | | - | - | - | - | - | Bksp |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
|Ctrl/Esc| - | - | - | - | - | | - | - | - | - | - |Ctrl/ - |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| LShift | - | - | - | - | - | [ { |CapsLk| |F-Keys| ] } | - | - | - | - | - | RShift |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
|Adjust| LGUI | LAlt/| Space| Nav | | Sym | Space| AltGr| RGUI | Menu |
| | | Enter| | | | | | | | |
`----------------------------------' `----------------------------------'
```
Three different well-known keyboard layouts are provided to fill in the placeholder `-` keys: QWERTY, Colemak-DH, and Dvorak. The default layer can be changed at runtime, more info on that in the section on the [adjust layer](#adjust-layer).
For the rest of this write-up, the base layer will be assumed to be QWERTY and will be used as a reference to describe physical keys, e.g. “<kbd>B</kbd> key” vs, the much more verbose, “lower inner index key”.
```
Base Layer: QWERTY
,-------------------------------------------. ,-------------------------------------------.
| Tab | Q | W | E | R | T | | Y | U | I | O | P | Bksp |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
|Ctrl/Esc| A | S | D | F | G | | H | J | K | L | ; : |Ctrl/' "|
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| LShift | Z | X | C | V | B | [ { |CapsLk| |F-keys| ] } | N | M | , < | . > | / ? | RShift |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
|Adjust| LGUI | LAlt/| Space| Nav | | Sym | Space| AltGr| RGUI | Menu |
| | | Enter| | | | | | | | |
`----------------------------------' `----------------------------------'
```
Aside from variations in the alpha cluster, the rest of the base keys remain the same and are designed to feel familiar.
![Step-by-step animation of the transformation of an ortholinear TKL to a Kyria](https://i.imgur.com/uVDCOek.gif)
<details>
After making transformations to the classic ANSI US QWERTY TKL 60% to arrive to the layout of the Kyria, as illustrated in the animation above, the result looks like this:
```
,-------------------------------------------. ,-------------------------------------------.
| Tab | Q | W | E | R | T | | Y | U | I | O | P | Bksp |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
| Cap Lk | A | S | D | F | G | | H | J | K | L | ; : | ' " |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| LShift | Z | X | C | V | B | | | | | | N | M | , < | . > | / ? | RShift |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
| LCtrl| LGUI | LAlt | Space| | | | Space| AltGr| RGUI | Menu |
| | | | | | | | | | | |
`----------------------------------' '----------------------------------'
```
First thing to notice is the presence of blank keys. To fill in the blank keys above the <kbd>Space</kbd> keys, we can take inspiration from other split keyboards featuring an extra inner index column on each half. A common mapping for those kind of keys are the bracket keys that got removed in the fourth step of the animated transformation. The thumb keys besides <kbd>Space</kbd>s is prime real estate for dedicated layer-switching keys. It doesn't matter on which side is assigned the sym-layer-switch key but it helps to keep the nav-layer-switch on the left in order to keep the arrow keys on the right side like on a classic keyboard, so we'll put nav on the left and sym on the right. We'll address the remaining blank thumb keys later.
The base layer is starting to form but there remains some flaws. One glaring issue is the position of Control. Control is a very commonly used function but the key on which it sits right now is way too tucked in under the hand to be able to press it comfortably with either the thumb or the pinky from resting position. In fact, installing a rotary encoder there is a common move among Kyria users and I guarantee you that activating Control by holding down a rotary encoder does not spark joy. Instead, let's employ a popular trick that involves remapping the current Caps Lock key, which is positioned at a comfortable position on the keyboard, to Control.
We can go further though; a variant of this trick makes the Control key produce Escape when tapped. This is called a “modtap”. There is no use to tapping Control by itself without chording it with another key and there is no use to holding down the Esc key so why not combine the two into a single key?
All of this leaves us with three blank keys.
```
,-------------------------------------------. ,-------------------------------------------.
| Tab | Q | W | E | R | T | | Y | U | I | O | P | Bksp |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
|Ctrl/Esc| A | S | D | F | G | | H | J | K | L | ; : | ' " |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| LShift | Z | X | C | V | B | [ { | | | | ] } | N | M | , < | . > | / ? | RShift |
`--------+-------------+--------------------+------+------| |------+------+--------------------+------+---------------'
| | LGUI | LAlt | Space| Nav | | Sym | Space| AltGr| RGUI | Menu |
| | | | | | | | | | | |
`----------------------------------' '----------------------------------'
```
These keys are not easily reachable while touch typing (that is, not reachable without picking up your hand) and should thus be associated with functions that you are not likely to be typed within a stream of text. The idea is that if you have to pick up your hand to hit a key, you want it to be at a time when you are likely to be pausing your interaction with the machine, rather than in the midst of a flurry of typing. They're thus well suited for accessing the adjust layer and the function layer. We can also toss in Caps Lock even though it is an editing-type function that gets used within a stream of text because shouting in ALL-CAPS should be a deliberate action.
```
,-------------------------------------------. ,-------------------------------------------.
| Tab | Q | W | E | R | T | | Y | U | I | O | P | Bksp |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
|Ctrl/Esc| A | S | D | F | G | | H | J | K | L | ; : | ' " |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| LShift | Z | X | C | V | B | [ { |CapsLk| |F-keys| ] } | N | M | , < | . > | / ? | RShift |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
|Adjust| LGUI | LAlt | Space| Nav | | Sym | Space| AltGr| RGUI | Menu |
| | | | | | | | | | | |
`----------------------------------' `----------------------------------'
```
The next glaring issue is the absence of an Enter key on the current base layer this far. Enter is a very frequently used key so it deserves to be placed at a good spot in the keymap. The best way to insert it in the keymap with minimal changes to the current layout is to use modtaps. A tempting solution is to turn the <kbd>RShift</kbd> key into a <kbd>RShift/Enter</kbd> modtap but that can result in chat messages sent too frustratingly early when you're not used to it. Using GUI is also sub-optimal because tapping the GUI modifier actually has a use as opposed to taps of the Control or the Shift key. Pressing and releasing the GUI key by itself opens the App menu in many desktop environments. The natural choice is thus <kbd>LAlt/Enter</kbd>. That way, Enter is 1u away from resting thumb position and is unlikely to get accidentally activated because Alt is very rarely used in the midst of prose.
Finally, we're one Quality-Of-Life update away from the actual base layer. <kbd>Ctrl/' "</kbd> not only preserves symmetry in the keymap with <kbd>Ctrl/Esc</kbd> but also helps balance the load between your pinkies and invites you to use both hands instead of contortions. Perhaps more importantly, it also frees you from the necessity of picking up your hand, breaking touch typing position and pressing a pinky key with your ring finger in order to execute Ctrl+A or Ctrl+Z. That becomes even more important on a board with such an aggressive pinky columnar stagger like the Kyria.
```
,-------------------------------------------. ,-------------------------------------------.
| Tab | Q | W | E | R | T | | Y | U | I | O | P | Bksp |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
|Ctrl/Esc| A | S | D | F | G | | H | J | K | L | ; : |Ctrl/' "|
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| LShift | Z | X | C | V | B | [ { |CapsLk| |F-keys| ] } | N | M | , < | . > | / ? | RShift |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
|Adjust| LGUI | LAlt/| Space| Nav | | Sym | Space| AltGr| RGUI | Menu |
| | | Enter| | | | | | | | |
`----------------------------------' `----------------------------------'
```
</details>
## Navigation layer
```
Nav Layer: Media, navigation
,-------------------------------------------. ,-------------------------------------------.
| | | | | | | | PgUp | Home | ↑ | End | VolUp| Delete |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
| | GUI | Alt | Ctrl | Shift| | | PgDn | ← | ↓ | → | VolDn| Insert |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| | | | | | | |ScLck | | | | Pause|M Prev|M Play|M Next|VolMut| PrtSc |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
| | | | | | | | | | | |
| | | | | | | | | | | |
`----------------------------------' `----------------------------------'
```
This is where you'll find all the keys that are generally between the main block of a classic keyboard and the numpad in addition to media controls and modifiers on easy access on the home row for fast and comfortable chording with navigation keys.
Useful mnemonics:
- “GACS” to remember the order of the modifiers on the left-hand home row
- <kbd>Scroll Lock</kbd> is on the same key as <kbd>Caps Lock</kbd> because they're both locks
- <kbd>Delete</kbd> is on the same key as <kbd>Backspace</kbd> because they both erase characters
- <kbd>Home</kbd> is the leftmost position on the current line so it is above <kbd>←</kbd>. Same logic applies for <kbd>End</kbd>.
- <kbd>Media Previous</kbd> = ⏮, <kbd>Media Next</kbd> = ⏭
- <kbd>Page Up</kbd>, <kbd>Page Down</kbd> and <kbd>Volume Up</kbd>, <kbd>Volume Down</kbd> are positioned like the main <kbd>Up</kbd> and <kbd>Down</kbd> keys.
## Sym layer
```
Sym Layer: Numbers, symbols
,-------------------------------------------. ,-------------------------------------------.
| ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | = |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
| ~ | ! | @ | # | $ | % | | ^ | & | * | ( | ) | + |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| | | \ | : | ; | - | [ | { | | | | } | ] | _ | , | . | / | ? |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
| | | | | | | | | | | |
| | | | | | | | | | | |
`----------------------------------' `----------------------------------'
```
The top row is the unshifted num row, the home row of the layer is the shifted num row and the bottom row contains the hyphen `-` and the underscore `_` on the best lower row spot because of how frequent they are as well as redundant symbols that are already present on the base layer but are reproduced here to avoid juggling back and forth between base, shift, and sym when typing a string of symbols.
The layout of the first two rows needs no introduction, you're already used to them but it's worth looking into the structure of the bottom row.
The two halves are mirrored in a sense. On the right, you can find <kbd>,</kbd> <kbd>.</kbd> <kbd>/</kbd> at their usual spots with the addition of <kbd>Shift</kbd>+<kbd>/</kbd>=<kbd>?</kbd> to the right of the <kbd>/</kbd> key to remove the need to press simultaneously <kbd>Sym</kbd> and a <kbd>Shift</kbd> key to access `?`.
Now, if you look at the left side, you'll notice that the mirror of <kbd>,</kbd> is <kbd>;</kbd>, the mirror of <kbd>.</kbd> is <kbd>:</kbd> and the mirror of <kbd>/</kbd> is <kbd>\\</kbd>. The same logic used for <kbd>Shift</kbd>+<kbd>/</kbd>=<kbd>?</kbd> also applies to <kbd>Shift</kbd>+<kbd>\\</kbd>=<kbd>|</kbd>.
In case you wish to combine <kbd>Shift</kbd> with a symbol key anyways, you can hold down <kbd>Shift</kbd> on the base layer with your pinky, activate <kbd>Sym</kbd> with your right thumb and while still holding down the <kbd>Shift</kbd> key, tap your desired symbol key. Same thing if you need <kbd>Ctrl</kbd>+<kbd>Digit</kbd>.
## Function layer
```
Function Layer: Function keys
,-------------------------------------------. ,-------------------------------------------.
| | F9 | F10 | F11 | F12 | | | | | | | | |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
| | F5 | F6 | F7 | F8 | | | | Shift| Ctrl | Alt | GUI | |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| | F1 | F2 | F3 | F4 | | | | | | | | | | | | |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
| | | | | | | | | | | |
| | | | | | | | | | | |
`----------------------------------' `----------------------------------'
```
In a similar fashion to the nav layer, pressing down `FKEYS` with the right thumb enables a numpad of function keys on the opposite hand and modifiers on the right-hand home row. Once again, mirror symmetry is leveraged in this keymap for the order of the right-hand modifiers.
The <kbd>Alt</kbd> modifier, despite being situated on the right half of the keyboard is *not* `KC_RALT`, it is `KC_LALT`. `KC_RALT` is actually the <kbd>AltGr</kbd> key which generally acts very differently to the left <kbd>Alt</kbd> key. Keyboard shortcuts involving <kbd>AltGr</kbd>+<kbd>F#</kbd> are rare and infrequent as opposed to the much more common <kbd>Alt</kbd>+<kbd>F#</kbd> shortcuts. Consequently, `KC_LALT` was chosen for the function layer.
Since there are more than 10 function keys, the cluster of F-keys does not follow the usual 3×3+1 numpad arrangement.
## Adjust layer
```
Adjust Layer: Default layer settings, RGB
,-------------------------------------------. ,-------------------------------------------.
| | | |QWERTY| | | | | | | | | |
|--------+------+------+------+------+------| |------+------+------+------+------+--------|
| | | |Dvorak| | | | TOG | SAI | HUI | VAI | MOD | |
|--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
| | | |Colmak| | | | | | | | | SAD | HUD | VAD | RMOD | |
`----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
| | | | | | | | | | | |
| | | | | | | | | | | |
`----------------------------------' `----------------------------------'
```
Default layer settings on the left and various RGB underglow controls on the right.
The default layer settings are lined up on the middle finger column because the home middle finger key is <kbd>D</kbd> on QWERTY (like the “D” in “Dvorak”) and the lower middle finger key is <kbd>C</kbd> on QWERTY (like the “C” in “Colemak”). I can hear you say that “QWERTY” doesn't start with “E” but Dvorak and Colemak were already aligned in a column so the QWERTY may as well join the formation.
NOTE: The default layer settings set by those keys are *NOT* stored in EEPROM and thus do not persist through boots. If you wish to change the default layer in a non-volatile manner, either change the order of the layers in the firmware, for example like so if you want to set Dvorak as the new default:
```c
enum layers {
_DVORAK = 0,
_QWERTY,
_COLEMAK_DH,
_NAV,
_SYM,
_FUNCTION,
_ADJUST
};
```
or re-define the `QWERTY`, `COLEMAK` and `DVORAK` keys to point to custom keycodes starting on `SAFE_RANGE` and calling the `set_single_persistent_default_layer` function inside of `process_record_user`.
## Hardware Features
### Rotary Encoder
The left rotary encoder is programmed to control the volume whereas the right encoder sends <kbd>PgUp</kbd> or <kbd>PgDn</kbd> on every turn.
### OLEDs
The OLEDs display the current layer at the top of the active layers stack, the Kyria logo and lock status (caps lock, num lock, scroll lock).
### Underglow
The underglow LEDs should be red.
## Going further…
This default keymap can be used as is, unchanged, as a daily driver for your Kyria but you're invited to treat your keymap like a bonsai. At the beginning, it's just like the default keymap but from time to time, you can tweak it a little. Cut a little key here, let another combo grow there. Slowly but surely it will be a unique keymap that will fit you like a glove.
Check out the #keymap-ideas channel on the official SplitKB Discord server for inspiration.

View file

@ -1,44 +0,0 @@
OLED_ENABLE = yes
ENCODER_ENABLE = no # Enables the use of one or more encoders
RGB_MATRIX_ENABLE = no # Disable keyboard RGB matrix, as it is enabled by default on rev3
RGBLIGHT_ENABLE = no # Disable keyboard RGB underglow
#SPLIT_KEYBOARD = yes
#OLED_DRIVER = ssd1306 # Enables the use of OLED displays
#OLED_DRIVER_ENABLE = yes # Enables the use of OLED displays
#CONSOLE_ENABLE = yes
LTO_ENABLE = yes
ENCODER_MAP_ENABLE = no
TAP_DANCE_ENABLE = no
DEFERRED_EXEC_ENABLE = no
KEY_OVERRIDE_ENABLE = no
CAPS_WORD_ENABLE = yes
COMBO_ENABLE = yes
REPEAT_KEY_ENABLE = yes
SRC += features/tap_hold_utilities.c
SRC += features/os4a.c
#SRC += features/custom_altgr_keys.c
#SRC += encoder.c
SRC += oled.c
SRC += features/clever_keys_utilities.c
SRC += clever_keys.c
SRC += features/numword.c
SRC += features/macros.c
SRC += features/oneshot.c
SRC += features_conf.c
SRC += features/odk_layer.c
INTROSPECTION_KEYMAP_C = features/combos.c
MUSIC_ENABLE = no
SPACE_CADET_ENABLE = no
GRAVE_ESC_ENABLE = no

View file

@ -19,59 +19,46 @@
#include "clever_keys.h"
void get_clever_keycode(uint16_t* next_keycode, keyrecord_t* record) {
void get_clever_keycode(uint16_t* ongoing_keycode, keyrecord_t* record) {
uint16_t prev_keycode = recent[RECENT_SIZE - 1];
//static bool is_shifted = false;
uint16_t prev_keycode = get_recent_keycode(-1);
// Apostrophe
if (is_followed_by_apos(*next_keycode, prev_keycode)) {
if (is_followed_by_apos(*ongoing_keycode, prev_keycode)) {
set_last_keycode(PG_APOS);
//apostrophe = true;
}
//if (is_caps_lock_on()) {
/* if (is_letter(*next_keycode) || is_send_string_macro(*next_keycode)) {
if (recent[RECENT_SIZE - 3] == PG_E && recent[RECENT_SIZE - 2] == PG_T && prev_keycode == KC_SPC) {
caps_word_on();
}
if (recent[RECENT_SIZE - 2] == PG_VIRG && prev_keycode == KC_SPC && is_letter(*next_keycode)) {
caps_word_on();
}
} */
//}
switch (prev_keycode) {
case NNB_SPC:
switch (*next_keycode) {
switch (*ongoing_keycode) {
// Shift auto de la ponctuation après une espace fine insécable
case PG_POIN:
process_word((uint16_t[]) {KC_BSPC, SAGR(KC_SPC)}, 2, record);
// uses less space than process_word
tap_code(KC_BSPC);
process_key(SAGR(KC_SPC), record);
case PG_TIRE:
case PG_VIRG:
return replace_ongoing_key(S(*next_keycode), next_keycode, record);
return replace_ongoing_key(S(*ongoing_keycode), ongoing_keycode, record);
}
break;
case KC_SPC:
switch (recent[RECENT_SIZE - 2]) {
switch (get_recent_keycode(-2)) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_POIN:
// Shift the letter at the beginning of sentences.
if (is_letter(*next_keycode) || is_send_string_macro(*next_keycode)) {
//if (!is_caps_lock_on()) { add_weak_mods(MOD_BIT(KC_LSFT)); }
add_weak_mods(MOD_BIT(KC_LSFT));
if (is_letter(*ongoing_keycode) || is_send_string_macro(*ongoing_keycode)) {
set_oneshot_mods(MOD_BIT(KC_LSFT)); // Don't use weak mods!
}
break;
}
break;
case PG_Q:
switch (*next_keycode) {
switch (*ongoing_keycode) {
// Ajout automatique du "u" après le "q"
case PG_E:
@ -81,133 +68,132 @@ void get_clever_keycode(uint16_t* next_keycode, keyrecord_t* record) {
case PG_EACU:
case PG_APOS:
invoke_key(PG_U, record);
set_last_keycode(*next_keycode);
set_last_keycode(*ongoing_keycode);
break;
// Raccourci pour "quoi"
case PG_H:
finish_word((uint16_t[]) {PG_U, PG_O, PG_I}, 3, next_keycode, record);
finish_word((uint16_t[]) {PG_U, PG_O, PG_I}, 3, ongoing_keycode, record);
break;
// Raccourci pour "quand"
case PG_N:
return finish_word((uint16_t[]) {PG_U, PG_A, PG_N, PG_D}, 4, next_keycode, record);
return finish_word((uint16_t[]) {PG_U, PG_A, PG_N, PG_D}, 4, ongoing_keycode, record);
}
break;
case PG_P:
switch (*next_keycode) {
switch (*ongoing_keycode) {
case PG_C:
// "pas"
return finish_word((uint16_t[]) {PG_A, PG_S}, 2, next_keycode, record);
return finish_word((uint16_t[]) {PG_A, PG_S}, 2, ongoing_keycode, record);
case PG_J:
// "pour"
return finish_word((uint16_t[]) {PG_O, PG_U, PG_R}, 3, next_keycode, record);
return finish_word((uint16_t[]) {PG_O, PG_U, PG_R}, 3, ongoing_keycode, record);
case PG_X:
// "plus"
return finish_word((uint16_t[]) {PG_L, PG_U, PG_S}, 3, next_keycode, record);
return finish_word((uint16_t[]) {PG_L, PG_U, PG_S}, 3, ongoing_keycode, record);
}
break;
}
switch (*next_keycode) {
switch (*ongoing_keycode) {
case MAGIC:
switch (prev_keycode) {
case PG_O:
// oui
invoke_key(PG_U, record);
process_key(PG_U, record);
case PG_U:
// ui SFB
return replace_ongoing_key(PG_I, next_keycode, record);
/* case PG_L:
// là
return finish_word((uint16_t[]) {PG_ODK, PG_A}, 2, next_keycode, record); */
return replace_ongoing_key(PG_I, ongoing_keycode, record);
case PG_EACU:
// éa SFB
return replace_ongoing_key(PG_A, next_keycode, record);
return replace_ongoing_key(PG_A, ongoing_keycode, record);
case PG_S:
// sc SFB
return replace_ongoing_key(PG_C, next_keycode, record);
return replace_ongoing_key(PG_C, ongoing_keycode, record);
case PG_C:
// cs SFB
return replace_ongoing_key(PG_S, next_keycode, record);
return replace_ongoing_key(PG_S, ongoing_keycode, record);
case PG_N:
// n. SFB
return replace_ongoing_key(PG_POIN, next_keycode, record);
return replace_ongoing_key(PG_POIN, ongoing_keycode, record);
case PG_P:
// ph SFB
return replace_ongoing_key(PG_H, next_keycode, record);
return replace_ongoing_key(PG_H, ongoing_keycode, record);
case PG_G:
// gt SFB
return replace_ongoing_key(PG_T, next_keycode, record);
return replace_ongoing_key(PG_T, ongoing_keycode, record);
case PG_Q:
// qué scissor
return finish_word((uint16_t[]) {PG_U, PG_EACU}, 2, next_keycode, record);
//return finish_word((uint16_t[]) {PG_U, PG_EACU}, 2, ongoing_keycode, record);
process_key(PG_U,record);
return replace_ongoing_key(PG_EACU, ongoing_keycode, record);
case PG_Y:
// you bad redirection
return finish_word((uint16_t[]) {PG_O, PG_U}, 2, next_keycode, record);
//return finish_word((uint16_t[]) {PG_O, PG_U}, 2, ongoing_keycode, record);
process_key(PG_O,record);
return replace_ongoing_key(PG_U, ongoing_keycode, record);
case PG_T:
// "the"
return finish_word((uint16_t[]) {PG_H, PG_E}, 2, next_keycode, record);
//return finish_word((uint16_t[]) {PG_H, PG_E}, 2, ongoing_keycode, record);
process_key(PG_H,record);
return replace_ongoing_key(PG_E, ongoing_keycode, record);
case PG_I:
return finish_word((uint16_t[]) {PG_O, PG_N}, 2, next_keycode, record);
//return finish_word((uint16_t[]) {PG_O, PG_N}, 2, ongoing_keycode, record);
process_key(PG_O,record);
return replace_ongoing_key(PG_N, ongoing_keycode, record);
case PG_M:
if (is_letter(recent[RECENT_SIZE - 2])) {
if (is_letter(get_recent_keycode(-2))) {
// "ment"
return finish_word((uint16_t[]) {PG_E, PG_N, PG_T}, 3, next_keycode, record);
return finish_word((uint16_t[]) {PG_E, PG_N, PG_T}, 3, ongoing_keycode, record);
} else {
// "même"
return finish_word((uint16_t[]) {PG_ODK, PG_O, PG_M, PG_E}, 4, next_keycode, record);
return finish_word((uint16_t[]) {PG_ODK, PG_O, PG_M, PG_E}, 4, ongoing_keycode, record);
}
case PG_B:
// "beaucoup"
return finish_word((uint16_t[]) {PG_E, PG_A, PG_U, PG_C, PG_O, PG_U, PG_P}, 7, next_keycode, record);
return finish_word((uint16_t[]) {PG_E, PG_A, PG_U, PG_C, PG_O, PG_U, PG_P}, 7, ongoing_keycode, record);
case PG_D:
// "déjà"
return finish_word((uint16_t[]) {PG_EACU, PG_J, PG_ODK, PG_A}, 4, next_keycode, record);
return finish_word((uint16_t[]) {PG_EACU, PG_J, PG_ODK, PG_A}, 4, ongoing_keycode, record);
default:
// "à"
process_key(PG_ODK,record);
if (is_shifted) {
is_shifted = false;
add_weak_mods(MOD_BIT(KC_LSFT));
}
return replace_ongoing_key(PG_A, next_keycode, record);
process_key(PG_ODK, record);
return replace_ongoing_key(PG_A, ongoing_keycode, record);
}
case PG_AROB:
if (!is_letter(recent[RECENT_SIZE - 2])) {
if (!is_letter(get_recent_keycode(-2))) {
switch (prev_keycode) {
case PG_P:
// "p@" -> "problème"
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_R, PG_O, PG_B, PG_L, PG_ODK, PG_E, PG_M, PG_E}, 8, next_keycode, record);
return finish_word((uint16_t[]) {PG_R, PG_O, PG_B, PG_L, PG_ODK, PG_E, PG_M, PG_E}, 8, ongoing_keycode, record);
case PG_A:
// "a@" -> "aujourd'hui"
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_U, PG_J, PG_O, PG_U, PG_R, PG_D, PG_APOS, PG_H, PG_U, PG_I}, 10, next_keycode, record);
return finish_word((uint16_t[]) {PG_U, PG_J, PG_O, PG_U, PG_R, PG_D, PG_APOS, PG_H, PG_U, PG_I}, 10, ongoing_keycode, record);
}
}
break;
@ -215,45 +201,59 @@ void get_clever_keycode(uint16_t* next_keycode, keyrecord_t* record) {
case PG_M:
if (prev_keycode == PG_C) {
// "cm" -> "ch"
bkspc_countdown = 0;
return replace_ongoing_key(PG_H, next_keycode, record);
update_bkspc_countdown(0);
return replace_ongoing_key(PG_H, ongoing_keycode, record);
}
break;
case PG_H:
if (prev_keycode == PG_M) {
switch (prev_keycode) {
case PG_M:
case PG_R:
case PG_A:
case PG_E:
case PG_I:
case PG_O:
update_bkspc_countdown(0);
return replace_ongoing_key(PG_B, ongoing_keycode, record);
}
/* if (prev_keycode == PG_M) {
// "mh" -> "mb"
bkspc_countdown = 0;
return replace_ongoing_key(PG_B, next_keycode, record);
update_bkspc_countdown(0);
return replace_ongoing_key(PG_B, ongoing_keycode, record);
} else if (prev_keycode == PG_I) {
// "ih" -> "ique"
return finish_word((uint16_t[]) {PG_Q, PG_U, PG_E}, 3, next_keycode, record);
}
return finish_word((uint16_t[]) {PG_Q, PG_U, PG_E}, 3, ongoing_keycode, record);
} */
break;
/* case PG_R:
if (prev_keycode == PG_L) {
// "lr" -> "l" + 1DK
//bkspc_countdown = 0;
return replace_ongoing_key(OS_ODK, next_keycode, record);
}
break; */
case OU_GRV:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_O, PG_ODK, PG_N}, 3, next_keycode, record);
/* case PG_BL:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_B, PG_L}, 2, next_keycode, record); */
/* case J_APOS:
layer_off(_ODK);
return finish_word((uint16_t[]) {PG_J, PG_APOS}, 2, next_keycode, record); */
return finish_word((uint16_t[]) {PG_O, PG_ODK, PG_N}, 3, ongoing_keycode, record);
case PG_APOS:
if (is_apos_dr) { return replace_ongoing_key(PG_APOD, next_keycode, record); }
if (replace_apos()) { return replace_ongoing_key(PG_APOD, ongoing_keycode, record); }
break;
}
}
}
/* Boucle de CapsWord :
on press:
clear_weak_mods();
if (caps_word_press_user(keycode)) {
send_keyboard_report();
return true;
}
}
caps_word_off();
return true;
*/
/* record->keycode = S(ongoing_keycode);
processingCK = true;
if (caps_word_press_user(ongoing_keycode, record)) { processingCK = true; } */

View file

@ -25,7 +25,7 @@
extern "C" {
#endif
void get_clever_keycode(uint16_t* next_keycode, keyrecord_t* record);
void get_clever_keycode(uint16_t* ongoing_keycode, keyrecord_t* record);
#ifdef __cplusplus

View file

@ -33,7 +33,7 @@
# define RGBLIGHT_LIMIT_VAL 150
#endif
//#define TAPPING_TOGGLE 1
#define TAPPING_TOGGLE 1
// combo
#define COMBO_TERM 50

View file

@ -1,24 +1,51 @@
#include "capslist.h"
//static bool caps_word_active = false;
static bool caps_list_active = false;
static unsigned short int capslist_countdown = 0;
static unsigned short int countdown_end = 5;
static signed char capslist_countdown = 1;
static unsigned char countdown_end = 6;
//bool is_caps_word_on(void) { return caps_word_active; }
bool is_caps_list_on(void) { return caps_list_active; }
/* void caps_word_on(void) {
if (caps_word_active) { return; }
clear_mods();
clear_oneshot_mods();
caps_word_active = true;
} */
void enable_caps_list(void) {
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
caps_word_on();
caps_list_active = true;
capslist_countdown = 0;
countdown_end = 5;
capslist_countdown = 1;
countdown_end = 6;
}
/* void caps_word_off(void) {
if (!caps_word_active) { return; }
unregister_weak_mods(MOD_BIT(KC_LSFT)); // Make sure weak shift is off.
caps_word_active = false;
} */
void disable_caps_list(void) {
caps_word_off();
caps_list_active = false;
}
/* void caps_word_toggle(void) {
if (caps_word_active) {
caps_word_off();
} else {
caps_word_on();
}
} */
void toggle_caps_list(void) {
if (caps_list_active) {
disable_caps_list();
@ -27,14 +54,100 @@ void toggle_caps_list(void) {
}
}
bool update_capslist_countdown(signed char i) {
capslist_countdown = capslist_countdown + i;
return true;
}
bool word_check(uint16_t keycodes[], uint8_t num_keycodes, unsigned char new_countdown_end) {
for (int i = 0; i < num_keycodes; ++i) {
if (get_recent_keycode(- 2 - i) != keycodes[num_keycodes - 1 - i]) { return false; }
}
countdown_end = new_countdown_end;
return true;
}
/* bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
if (keycode == CAPSWORD) {
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
if (record->event.pressed) {
// Deactivating Caps Lock and Caps List when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
if (is_caps_list_on()) { disable_caps_list(); }
caps_word_toggle();
}
return false;
} else if (keycode == KC_CAPS) {
if (record->event.pressed) {
caps_word_off();
disable_caps_list();
}
return true;
}
if (!caps_word_active) { return true; }
// Caps word is active //
clear_weak_mods();
if (record->event.pressed) {
// if (!IS_LAYER_ON(_ODK)) {
// keycode = get_recent_keycode(-1);
// } else {
switch (keycode) {
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
return true;
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
// Earlier return if this has not been considered tapped yet
if (record->tap.count == 0) { return true; }
keycode = tap_hold_extractor(keycode); // Get tapping keycode.
break;
}
//}
//clear_weak_mods();
if (caps_word_press_user(keycode)) { return true; }
caps_word_off();
} else { // On release
}
return true;
} */
bool process_caps_list(uint16_t keycode, keyrecord_t *record) {
// Handle the custom keycodes that go with this feature
if (keycode == CAPSLIST) {
if (record->event.pressed) {
toggle_caps_list();
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
toggle_caps_list();
}
return false;
}
if (keycode == CAPSWORD) {
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
if (record->event.pressed) {
// Deactivating Caps Lock and Caps List when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
if (is_caps_list_on()) { disable_caps_list(); }
caps_word_toggle();
}
return false;
} else if (keycode == KC_CAPS) {
if (record->event.pressed) {
caps_word_off();
disable_caps_list();
}
return true;
}
// Other than the custom keycodes, nothing else in this feature will activate
// if the behavior is not on, so allow QMK to handle the event as usual.
@ -57,58 +170,14 @@ bool process_caps_list(uint16_t keycode, keyrecord_t *record) {
}
if (should_continue_caps_list(keycode)) {
if (caps_word_reactivation()) {
caps_word_on(); // Reactivate Caps Word for a new word
capslist_countdown = 0;
capslist_countdown = 1;
return true;
}
if (capslist_countdown < countdown_end) { return true; }
}
disable_caps_list();
return true;
}
bool should_continue_caps_list(uint16_t keycode) {
if (keycode == KC_BSPC) {
capslist_countdown--;
return true;
}
if (is_letter(keycode) || is_send_string_macro(keycode) || keycode == PG_AROB) {
capslist_countdown++;
return true;
}
if (caps_word_press_user(keycode)) {
capslist_countdown++;
return true;
}
// Keycodes that continue Caps List, but not Caps Word.
// These keycodes trigger the countdown to end Caps List.
switch (keycode) {
case PG_VIRG:
case KC_SPC:
capslist_countdown++;
return true;
}
return false; // Deactivate Caps List.
}
bool caps_word_reactivation(void) {
// Words that continue Caps List.
if (recent[RECENT_SIZE - 1] == KC_SPC) {
if (recent[RECENT_SIZE - 4] == KC_SPC && recent[RECENT_SIZE - 3] == PG_E && recent[RECENT_SIZE - 2] == PG_T) {
countdown_end = 1;
return true;
}
if (recent[RECENT_SIZE - 4] == KC_SPC && recent[RECENT_SIZE - 3] == PG_O && recent[RECENT_SIZE - 2] == PG_U) {
countdown_end = 1;
return true;
}
if (recent[RECENT_SIZE - 2] == PG_VIRG) {
return true;
}
}
return false;
}
}

View file

@ -3,13 +3,203 @@
#include "quantum.h"
#include "keymap.h"
bool is_caps_list_on(void);
void enable_caps_list(void);
void disable_caps_list(void);
void toggle_caps_list(void);
bool update_capslist_countdown(signed char i);
bool word_check(uint16_t keycodes[], uint8_t num_keycodes, unsigned char new_countdown_end);
bool process_caps_list(uint16_t keycode, keyrecord_t *record);
bool should_continue_caps_list(uint16_t keycode);
bool caps_word_reactivation(void);
bool caps_word_reactivation(void);
// Copyright 2021-2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @file caps_word.h
* @brief Caps Word, a modern alternative to Caps Lock
*
* Overview
* --------
*
* @note Caps Word is now a core QMK feature! See
* <https://docs.qmk.fm/features/caps_word>
*
* This library implements "Caps Word", which is like conventional Caps Lock,
* but automatically disables itself at the end of the word. This is useful for
* typing all-caps identifiers like `MOD_MASK_ALT`.
*
* Caps Word is activated by pressing the left and right shift keys at the same
* time. This way you don't need a dedicated key for using Caps Word. I've
* tested that this works as expected with one-shot mods and Space Cadet Shift.
* If your shift keys are mod-taps, activate Caps Word by holding both shift
* mod-tap keys until the tapping term, release them, then begin typing.
* Alternatively, you can call `caps_word_on()` to activate Caps Word from a
* combo, tap dance, or other means.
*
* Configuration
* -------------
*
* Word-breaking keys:
* Use the `caps_word_press_user()` callback to define whether a key should
* continue Caps Word or "break the word" and stop Caps Word.
*
* Representing state:
* Use `caps_word_set_user()` callback to know when Caps Word turns on and off,
* for instance to use an LED to indicate when Caps Word is active.
*
* Idle timout:
* Optionally, Caps Word may be configured to deactivate if the keyboard is idle
* for some time. This is useful to mitigate unintended shifting when you get
* interrupted or switch to the mouse while Caps Word is active. In your
* config.h, define `CAPS_WORD_IDLE_TIMEOUT` with a time in milliseconds:
*
* #define CAPS_WORD_IDLE_TIMEOUT 5000 // Turn off after 5 seconds.
*
* and in your keymap.c, define (or add to) `housekeeping_task_user()` as
*
* void housekeeping_task_user(void) {
* caps_word_task();
* // Other tasks...
* }
*
* For full documentation, see
* <https://getreuer.info/posts/keyboards/caps-word>
*/
/**
* Handler function for Caps Word.
*
* Call this function from `process_record_user()` to implement Caps Word.
*/
bool process_caps_word(uint16_t keycode, keyrecord_t* record);
// If CAPS_WORD_IDLE_TIMEOUT is set, call `caps_word_task()` from
// `housekeeping_task_user()` as described above.
//
// If CAPS_WORD_IDLE_TIMEOUT isn't set, calling this function has no effect (but
// will still compile).
#if CAPS_WORD_IDLE_TIMEOUT > 0
void caps_word_task(void);
#else
static inline void caps_word_task(void) {}
#endif
/**
* Turns on Caps Word.
*
* For instance activate Caps Word with a combo by defining a `COMBO_ACTION`
* that calls `caps_word_on()`:
*
* void process_combo_event(uint16_t combo_index, bool pressed) {
* switch(combo_index) {
* case CAPS_COMBO:
* if (pressed) {
* caps_word_on();
* }
* break;
*
* // Other combos...
* }
* }
*/
void caps_word_on(void);
/** Turns off Caps Word. */
void caps_word_off(void);
/** Toggles Caps Word. */
void caps_word_toggle(void);
/** Returns true if Caps Word is currently on. */
bool is_caps_word_on(void);
/**
* Optional callback that gets called when Caps Word turns on or off.
*
* This callback is useful to represent the current Caps Word state, e.g. by
* setting an LED or playing a sound. In your keymap, define
*
* void caps_word_set_user(bool active) {
* if (active) {
* // Do something when Caps Word activates.
* } else {
* // Do something when Caps Word deactivates.
* }
* }
*/
void caps_word_set_user(bool active);
/**
* Optional callback, called on each key press while Caps Word is active.
*
* When the key should be shifted (that is, a letter key), the callback should
* call `add_weak_mods(MOD_BIT(KC_LSFT))` to shift the key. The callback also
* determines whether the key should continue Caps Word. Returning true
* continues the current "word", while returning false is "word breaking" and
* deactivates Caps Word. The default callback is
*
* bool caps_word_press_user(uint16_t keycode) {
* switch (keycode) {
* // Keycodes that continue Caps Word, with shift applied.
* case KC_A ... KC_Z:
* case KC_MINS:
* add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key.
* return true;
*
* // Keycodes that continue Caps Word, without shifting.
* case KC_1 ... KC_0:
* case KC_BSPC:
* case KC_DEL:
* case KC_UNDS:
* return true;
*
* default:
* return false; // Deactivate Caps Word.
* }
* }
*
* To customize, copy the above function into your keymap and add/remove
* keycodes to the above cases.
*
* @note Outside of this callback, you can use `caps_word_off()` to deactivate
* Caps Word.
*/
bool caps_word_press_user(uint16_t keycode);
// Deprecated APIs.
/** @deprecated Use `caps_word_on()` and `caps_word_off()` instead. */
static inline void caps_word_set(bool active) {
if (active) {
caps_word_on();
} else {
caps_word_off();
}
}
/** @deprecated Use `is_caps_word_on()` instead. */
static inline bool caps_word_get(void) { return is_caps_word_on(); }
#ifdef __cplusplus
}
#endif

View file

@ -1,221 +0,0 @@
// Correction automatique
#include "clever_keys.h"
bool process_clever_keys(uint16_t keycode, keyrecord_t* record) {
uint16_t next_keycode = get_next_keycode(keycode, record);
const uint8_t mods = get_mods();
if (next_keycode != KC_NO) {
uint16_t prev_keycode = recent[RECENT_SIZE - 1];
//const uint8_t mods = get_mods();
if (is_letter(next_keycode) || next_keycode == E_CIRC) {
switch (prev_keycode) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_2PTS:
// Add space between punctuation and letters.
process_next_key(KC_SPC, record);
case KC_SPC:
switch (recent[RECENT_SIZE - 2]) {
case PG_EXCL:
case PG_QUES:
case PG_3PTS:
case PG_X:
// Add OS shift at the beginning of a sentence.
if (!is_caps_lock_on()) { set_oneshot_mods(MOD_BIT(KC_LSFT)); }
break;
}
}
}
// Ajout automatique du "u" après le "q"
if (prev_keycode == PG_Q) {
switch (next_keycode) {
case PG_E:
case PG_I:
case PG_A:
case PG_O:
case PG_U:
case E_CIRC:
case PG_APOS:
process_next_key(PG_L, record);
break;
// Raccourci pour "quelq"
case PG_Q:
clear_recent_keys(); // To prevent infinite loop
process_word((uint16_t[]) {PG_L, PG_E, PG_C}, 3, record);
break;
// Raccourci pour "quoi", ça évite un aller-retour sur la main gauche.
case PG_Z:
return finish_word((uint16_t[]) {PG_L, PG_O, PG_I}, 3, record);
// Raccourci pour "quand"
case PG_H:
process_word((uint16_t[]) {PG_L, PG_A, PG_S}, 3, record);
break;
}
} else if (next_keycode == PG_AROB && !is_letter(recent[RECENT_SIZE - 2])) {
switch (prev_keycode) {
case PG_N:
// "t@" -> "toujours"
return finish_word((uint16_t[]) {PG_O, PG_L, PG_J, PG_O, PG_L, PG_R, PG_T}, 7, record);
case PG_P:
// "p@" -> "peut-être"
return finish_word((uint16_t[]) {PG_E, PG_L, PG_N, PG_MOIN, PG_ACIR, PG_E, PG_N, PG_R, PG_E}, 9, record);
case PG_A:
// "a@" -> "aujourd'hui"
return finish_word((uint16_t[]) {PG_L, PG_J, PG_O, PG_L, PG_R, PG_H, PG_APOS, PG_F, PG_L, PG_I}, 10, record);
case PG_B:
// "b@" -> "beaucoup"
return finish_word((uint16_t[]) {PG_E, PG_A, PG_L, PG_D, PG_O, PG_L, PG_P}, 7, record);
case PG_E:
// "e@" -> "est-ce qu"
return finish_word((uint16_t[]) {PG_T, PG_N, PG_MOIN, PG_D, PG_E, KC_SPC, PG_Q}, 7, record);
case PG_H:
// "d@" -> "déjà"
return finish_word((uint16_t[]) {PG_U, PG_J, PG_AGRV}, 3, record);
}
} else if (prev_keycode == PG_P) {
switch (next_keycode) {
case PG_M:
// "pas"
return finish_word((uint16_t[]) {PG_A, PG_T}, 2, record);
case PG_APOS:
// "par"
return finish_word((uint16_t[]) {PG_A, PG_R}, 2, record);
case PG_X:
if (!is_letter(recent[RECENT_SIZE - 2])) {
// "pour"
return finish_word((uint16_t[]) {PG_O, PG_L, PG_R}, 3, record);
}
}
} else if (next_keycode == PG_A && prev_keycode == PG_O) {
// "oa" -> "oi"
process_next_key(PG_I, record);
return false;
} else if (next_keycode == PG_O && prev_keycode == PG_L && recent[RECENT_SIZE - 2] != PG_Q) {
// "uo" -> "un"
process_next_key(PG_S, record);
return false;
}
switch (next_keycode) {
case PG_QUES:
case PG_EXCL:
// On ajoute un espace insécable s'il n'a pas été entré avant le point d'exclamation.
// Il ne faut pas tester cette fonctionnalité avec Word, qui ajoute cet espace automatiquement.
if (is_letter(recent[RECENT_SIZE - 1])) {
if ((mods | get_oneshot_mods() | get_weak_mods()) & MOD_MASK_SHIFT) {
del_weak_mods(MOD_MASK_SHIFT);
del_oneshot_mods(MOD_MASK_SHIFT);
unregister_mods(MOD_MASK_SHIFT);
}
process_next_key(ALGR(KC_SPC), record);
set_mods(mods);
process_next_key(next_keycode, record);
return false;
}
break;
case MAGIC:
switch (prev_keycode) {
case PG_N:
process_next_key(PG_I, record);
case PG_I:
return finish_word((uint16_t[]) {PG_O, PG_S}, 2, record);
case PG_D:
return finish_word((uint16_t[]) {PG_APOS, PG_E, PG_T, PG_N}, 4, record);
case PG_H:
return finish_word((uint16_t[]) {PG_A, PG_S, PG_T}, 3, record);
case PG_P:
return finish_word((uint16_t[]) {PG_C, PG_L, PG_T}, 3, record);
case PG_A:
return finish_word((uint16_t[]) {PG_G, PG_E, PG_D}, 3, record);
case PG_T:
return finish_word((uint16_t[]) {PG_L, PG_R}, 2, record);
case PG_B:
process_word((uint16_t[]) {PG_O, PG_S, PG_J}, 3, record);
case PG_J:
return finish_word((uint16_t[]) {PG_O, PG_L, PG_R}, 3, record);
case PG_M:
// "même"
return finish_word((uint16_t[]) {PG_ACIR, PG_E, PG_M, PG_E}, 4, record);
default:
return false;
}
case PG_Q:
if (prev_keycode == PG_J) {
// "jq" -> "jusqu"
process_word((uint16_t[]) {PG_L, PG_T}, 2, record);
}
break;
case CA_CED:
return finish_word((uint16_t[]) {PG_CCED, PG_A}, 2, record);
case OU_GRV:
return finish_word((uint16_t[]) {PG_O, ALGR(PG_L)}, 2, record);
case AGRV_SPC:
return finish_word((uint16_t[]) {PG_AGRV, KC_SPC}, 2, record);
case E_CIRC:
return process_accent(PG_ACIR, PG_E, record);
case I_CIRC:
return process_accent(PG_ACIR, PG_I, record);
case A_CIRC:
return process_accent(PG_ACIR, PG_A, record);
case O_CIRC:
return process_accent(PG_ACIR, PG_O, record);
case U_CIRC:
return process_accent(PG_ACIR, PG_L, record);
case I_TREM:
return process_accent(PG_NREM, PG_I, record);
}
store_keycode(next_keycode, record);
}
return true; // Process all other keycodes normally
}

View file

@ -16,14 +16,22 @@
#include "clever_keys_utilities.h"
uint16_t recent[RECENT_SIZE] = {KC_NO};
static uint16_t recent[RECENT_SIZE] = {KC_NO};
uint16_t deadline = 0;
unsigned short int bkspc_countdown = RECENT_SIZE + 1;
static unsigned char bkspc_countdown = RECENT_SIZE + 1;
// Copy of the record argument for the clever key.
static keyrecord_t mod_record;
static bool processingCK = false;
uint16_t get_recent_keycode(signed char i) {
return recent[RECENT_SIZE + i];
}
void update_bkspc_countdown(unsigned char i) {
bkspc_countdown = i;
}
void clear_recent_keys(void) {
memset(recent, 0, sizeof(recent)); // Set all zeros (KC_NO).
bkspc_countdown = RECENT_SIZE + 1;
@ -40,8 +48,9 @@ uint16_t get_ongoing_keycode(uint16_t keycode, keyrecord_t* record) {
uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods();
if (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR))) {
clear_recent_keys(); // Avoid interfering with ctrl, left alt and gui.
//if (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR))) {
if (mods & ~MOD_MASK_SHIFT) {
clear_recent_keys(); // Avoid interfering with ctrl, alt, alt-gr and gui.
return KC_NO;
}
@ -75,22 +84,6 @@ uint16_t get_ongoing_keycode(uint16_t keycode, keyrecord_t* record) {
uint16_t custom_keycode = get_ongoing_keycode_user(keycode);
if (custom_keycode != KC_TRNS) { return custom_keycode; }
/* if (is_send_string_macro(keycode)) { return keycode; }
if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_K:
case PG_B:
case PG_AROB:
case PG_3PTS:
case KC_SPC: // In order to uppercase J after '?' for ex.
return keycode;
default:
clear_recent_keys();
return KC_NO;
}
} */
uint8_t basic_keycode = keycode;
// Handle keys carrying a modifier, for ex on layers(! and ?).
@ -100,7 +93,8 @@ uint16_t get_ongoing_keycode(uint16_t keycode, keyrecord_t* record) {
case KC_A ... KC_SLASH: // These keys type letters, digits, symbols.
case PG_E:
if (is_letter(basic_keycode) && (mods & ~MOD_BIT(KC_ALGR))) {
//if (is_letter(basic_keycode) && (mods & ~MOD_BIT(KC_ALGR))) {
if (is_letter(basic_keycode)) {
// Shift doesn't matter for letters.
return basic_keycode;
@ -146,9 +140,7 @@ void process_key(uint16_t keycode, keyrecord_t* record) {
}
void invoke_key(uint16_t keycode, keyrecord_t* record) {
tap_code(keycode);
//process_key(keycode, record);
//record->keycode = keycode;
process_key(keycode, record); // tap_code doesn't work with caps word.
bkspc_countdown = 1;
}
@ -161,13 +153,17 @@ void replace_ongoing_key(uint16_t clever_keycode, uint16_t* ongoing_keycode, key
void process_word(uint16_t keycodes[], uint8_t num_keycodes, keyrecord_t* record) {
for (int i = 0; i < num_keycodes; ++i) {
//process_key(keycodes[i], record); // Better solution, if there is enought space in the chip.
tap_code(keycodes[i]);
process_key(keycodes[i], record); // tap_code doesn't work with caps word.
}
bkspc_countdown = num_keycodes;
}
void finish_word(uint16_t keycodes[], uint8_t num_keycodes, uint16_t* ongoing_keycode, keyrecord_t* record) {
process_word(keycodes, num_keycodes - 1, record);
bkspc_countdown = num_keycodes - 1;
replace_ongoing_key(keycodes[num_keycodes - 1], ongoing_keycode, record);
}
void finish_magic(uint16_t keycodes[], uint8_t num_keycodes, uint16_t* ongoing_keycode, keyrecord_t* record) {
process_word(keycodes, num_keycodes - 1, record);
replace_ongoing_key(keycodes[num_keycodes - 1], ongoing_keycode, record);
}

View file

@ -26,9 +26,10 @@ extern "C" {
#define RECENT_SIZE 8 // Number of keys in `recent` buffer.
extern uint16_t recent[RECENT_SIZE];
uint16_t deadline;
extern unsigned short int bkspc_countdown;
uint16_t get_recent_keycode(signed char);
void update_bkspc_countdown(unsigned char i);
void clear_recent_keys(void);
void recent_keys_task(void);
@ -40,6 +41,7 @@ void invoke_key(uint16_t keycode, keyrecord_t* record);
void replace_ongoing_key(uint16_t clever_keycode, uint16_t* ongoing_keycode, keyrecord_t* record);
void process_word(uint16_t keycodes[], uint8_t num_keycodes, keyrecord_t* record);
void finish_word(uint16_t keycodes[], uint8_t num_keycodes, uint16_t* ongoing_keycode, keyrecord_t* record);
void finish_magic(uint16_t keycodes[], uint8_t num_keycodes, uint16_t* ongoing_keycode, keyrecord_t* record);
bool process_clever_keys(uint16_t keycode, keyrecord_t* record);
void end_CK(keyrecord_t* record);

View file

@ -31,7 +31,7 @@ enum combos {
ESC,
HELP,
PANIC,
NUMWRD,
//NUMWRD,
ALTTAB,
ALTESC
};
@ -48,7 +48,7 @@ const uint16_t PROGMEM home_combo[] = {PG_Z, PG_Y, COMBO_END};
const uint16_t PROGMEM end_combo[] = {PG_U, PG_EACU, COMBO_END};
const uint16_t PROGMEM help_combo[] = {PG_EACU, PG_J, COMBO_END};
const uint16_t PROGMEM panic_combo[] = {PG_U, PG_C, COMBO_END};
const uint16_t PROGMEM numword_combo[] = {PG_T, PG_R, COMBO_END};
//const uint16_t PROGMEM numword_combo[] = {PG_T, PG_R, COMBO_END};
const uint16_t PROGMEM alttab_combo[] = {PG_H, PG_Y, COMBO_END};
const uint16_t PROGMEM altesc_combo[] = {PG_A, PG_I, PG_N, COMBO_END};
@ -65,25 +65,16 @@ combo_t key_combos[] = {
[ESC] = COMBO(esc_combo, KC_ESC),
[HELP] = COMBO(help_combo, AIDE_MEM),
[PANIC] = COMBO(panic_combo, RAZ),
[NUMWRD] = COMBO(numword_combo, NUMWORD),
//[NUMWRD] = COMBO(numword_combo, NUMWORD),
[ALTTAB] = COMBO(alttab_combo, KC_NO),
[ALTESC] = COMBO(altesc_combo, LALT(KC_ESC))
};
/* uint16_t get_combo_term(uint16_t combo_index, combo_t *combo) {
switch (combo_index) {
case L_APOST:
case D_APOST:
return 100;
default:
return COMBO_TERM;
}
} */
bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) {
// Chorded mods shouldn't be considered as combos.
if (os4a_layer != 0) {
return (os4a_layer == _R_MODS) == on_left_hand(record->event.key);
if (get_os4a_layer() != 0) {
return (get_os4a_layer() == _R_MODS) == on_left_hand(record->event.key);
}
// Some combos shouldn't be affected by global_quick_tap_timer.
switch (combo_index) {
@ -95,10 +86,8 @@ bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode
return true;
default:
//return timer_elapsed(global_quick_tap_timer) > TAP_INTERVAL;
if (timer_elapsed(global_quick_tap_timer) < TAP_INTERVAL) {
return false;
}
//return enough_time_before_combo(); // takes more space
if (!enough_time_before_combo()) { return false; }
}
return true;
}
@ -107,29 +96,28 @@ bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode
void process_combo_event(uint16_t combo_index, bool pressed) {
switch (combo_index) {
case ALTTAB:
if (pressed) {
register_mods(MOD_LALT);
tap_code(KC_TAB);
} else {
unregister_mods(MOD_LALT);
}
break;
if (pressed) {
register_mods(MOD_LALT);
tap_code(KC_TAB);
} else {
unregister_mods(MOD_LALT);
}
break;
}
}
bool process_combo_key_repress(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
switch (combo_index) {
case ALTTAB:
switch (keycode) {
case PG_Y:
tap_code16(S(KC_TAB));
return true;
case PG_H:
tap_code(KC_TAB);
return true;
}
break;
switch (keycode) {
case PG_Y:
tap_code16(S(KC_TAB));
return true;
case PG_H:
tap_code(KC_TAB);
return true;
}
break;
}
return false;
}

View file

@ -16,11 +16,13 @@
#include "macros.h"
bool is_apos_dr = false;
static bool is_apos_dr = false;
bool replace_apos(void) {
return is_apos_dr;
}
bool process_macros(uint16_t keycode, keyrecord_t *record) {
//const uint8_t mods = get_mods();
//static bool is_shifted = false;
if (record->event.pressed) { // Handling of other macros (on press).
switch (keycode) {
@ -40,9 +42,9 @@ bool process_macros(uint16_t keycode, keyrecord_t *record) {
case _SHORTNAV:
tap_code(KC_F15);
return false;
case _FUNCAPPS:
/* case _FUNCAPPS:
tap_code(KC_F16);
return false;
return false; */
}
case RAZ:
@ -52,42 +54,16 @@ bool process_macros(uint16_t keycode, keyrecord_t *record) {
layer_clear();
clear_oneshot_mods();
clear_weak_mods();
//clear_weak_mods();
caps_word_off();
disable_num_word();
clear_recent_keys();
break;
case KC_CAPS:
caps_word_off();
return true;
case CAPSWORD:
// I can't use CW_TOGG because QMK dosn't reach process_record_user when processing it.
// Deactivating Caps Lock when Caps Word activates.
if (is_caps_lock_on()) { tap_code(KC_CAPS); }
caps_word_toggle();
return false;
case TG_APOS:
is_apos_dr = !is_apos_dr;
return false;
case NUM_ODK:
bool is_shifted = (get_mods() | get_weak_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT;
if (is_shifted) {
del_weak_mods(MOD_MASK_SHIFT);
del_oneshot_mods(MOD_MASK_SHIFT);
unregister_mods(MOD_MASK_SHIFT);
}
tap_code(PG_ODK);
if (is_shifted) {
is_shifted = false;
set_oneshot_mods(MOD_BIT(KC_LSFT));
}
return true;
case PG_DEG:
tap_code(PG_ODK);
tap_code(KC_9);

View file

@ -23,8 +23,7 @@
extern "C" {
#endif
extern bool is_apos_dr;
bool replace_apos(void);
bool process_macros(uint16_t keycode, keyrecord_t *record);
#ifdef __cplusplus

View file

@ -1,122 +0,0 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "numword.h"
//static uint16_t num_word_timer = 0;
//static bool is_num_word_on = false;
bool is_num_word_on = false;
static bool exit_num_word = false;
bool is_num_word_enabled(void) {
return is_num_word_on;
}
void enable_num_word(void) {
//if (is_num_word_on) return;
is_num_word_on = true;
layer_on(_NUMBERS);
}
void disable_num_word(void) {
//if (!is_num_word_on) return;
is_num_word_on = false;
layer_off(_NUMBERS);
exit_num_word = false;
}
void toggle_num_word(void) {
if (is_num_word_on) {
disable_num_word();
} else {
enable_num_word();
}
}
bool should_exit_num_word(uint16_t keycode, const keyrecord_t *record) {
switch (keycode) {
// Keycodes which should not disable num word mode.
// Numpad keycodes
case KC_1 ... KC_0:
case KC_PDOT:
//case PG_X:
//case PG_EACU:
case PG_MOIN:
case PG_ASTX:
case PG_PLUS:
case PG_SLSH:
case PG_EXP:
case PG_IND:
case PG_H:
case PG_2PTS:
case LT_EURO:
case NNB_SPC:
// Misc
case KC_BSPC:
case PG_ODK: // Not to exit Numword when chording it with ODK
case NUMWORD: // For the combo NUMWORD to work
/*
case PG_EGAL:
case PG_BSLS:*/
return false;
}
return true;
}
bool process_numword(uint16_t keycode, const keyrecord_t *record) {
// Handle the custom keycodes that go with this feature
if (keycode == NUMWORD) {
if (record->event.pressed) { toggle_num_word(); }
return false;
}
// Other than the custom keycodes, nothing else in this feature will activate
// if the behavior is not on, so allow QMK to handle the event as usual.
if (!is_num_word_on) { return true; }
// Nothing else acts on key release, either
if (!record->event.pressed) { return true; }
// Get the base keycode of a mod or layer tap key
switch (keycode) {
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
// Earlier return if this has not been considered tapped yet
if (record->tap.count == 0) { return true; }
keycode = keycode & 0xFF;
break;
/* case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys.
// Release event on a held layer-tap key when numword is on.
if (record->tap.count == 0 && !record->event.pressed) {
return false; // Skip default handling so that layer stays on.
} else {
keycode = keycode & 0xFF; // Get tapping keycode.
}
break; */
}
exit_num_word = should_exit_num_word(keycode, record);
return true;
}
void numword_exit_check(void) {
if (exit_num_word) { disable_num_word(); }
}

View file

@ -18,7 +18,7 @@
//static uint16_t num_word_timer = 0;
//static bool is_num_word_on = false;
bool is_num_word_on = false;
static bool is_num_word_on = false;
static bool exit_num_word = false;
bool is_num_word_enabled(void) {
@ -26,13 +26,13 @@ bool is_num_word_enabled(void) {
}
void enable_num_word(void) {
//if (is_num_word_on) return;
if (is_num_word_on) return;
is_num_word_on = true;
layer_on(_NUMBERS);
}
void disable_num_word(void) {
//if (!is_num_word_on) return;
if (!is_num_word_on) return;
is_num_word_on = false;
layer_off(_NUMBERS);
exit_num_word = false;
@ -46,42 +46,6 @@ void toggle_num_word(void) {
}
}
bool should_exit_num_word(uint16_t keycode, const keyrecord_t *record) {
switch (keycode) {
// Keycodes which should not disable num word mode.
// Numpad keycodes
case KC_1 ... KC_0:
case KC_PDOT:
//case PG_X:
//case PG_EACU:
case PG_MOIN:
case PG_ASTX:
case PG_PLUS:
case PG_SLSH:
case PG_EXP:
case PG_IND:
case PG_H:
case PG_2PTS:
case PG_EURO:
//case LT_NBSPC:
case NNB_SPC:
// Misc
case KC_BSPC:
case PG_ODK: // Not to exit Numword when chording it with ODK
case NUMWORD: // For the combo NUMWORD to work
/*
case PG_EGAL:
case PG_BSLS:*/
return false;
}
return true;
}
bool process_numword(uint16_t keycode, const keyrecord_t *record) {
// Handle the custom keycodes that go with this feature
@ -93,8 +57,13 @@ bool process_numword(uint16_t keycode, const keyrecord_t *record) {
// Other than the custom keycodes, nothing else in this feature will activate
// if the behavior is not on, so allow QMK to handle the event as usual.
if (!is_num_word_on) { return true; }
// Nothing else acts on key release, either
if (record->event.pressed) {
// Should exit num word on key release
// in case of rolled keys as well (take the press of the 2nd one into account!)
if (exit_num_word) {
disable_num_word();
} else if (record->event.pressed) {
// Get the base keycode of a mod or layer tap key
switch (keycode) {
@ -115,8 +84,8 @@ bool process_numword(uint16_t keycode, const keyrecord_t *record) {
}
exit_num_word = should_exit_num_word(keycode, record);
} else if (exit_num_word) {
disable_num_word();
} else { // On keyrelease
}
return true;
}

View file

@ -19,8 +19,6 @@
#include "keymap.h"
bool is_num_word_enabled(void);
//extern bool exit_num_word;
extern bool is_num_word_on;
void enable_num_word(void);
void disable_num_word(void);

View file

@ -16,15 +16,13 @@
#include "odk_layer.h"
bool is_shifted = false;
bool process_odk_layer(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) { // On press
const uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods();
bool invoke_odk = false;
//const uint8_t mods = get_mods() | get_oneshot_mods();
//static bool is_shifted = false;
if (keycode == OS_ODK) {
// Custom behaviour when alt-gr
@ -32,48 +30,71 @@ bool process_odk_layer(uint16_t keycode, keyrecord_t *record) {
tap_code16(ALGR(PG_ODK));
return false;
}
return true;
} else if (keycode == PG_ODK) {
invoke_odk = true;
//return deferred_shift_after_dead_key(keycode, mods);
} else if (keycode == NUM_ODK) {
invoke_odk = true;
//return deferred_shift_after_dead_key(keycode, mods);
} else if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_PVIR:
case PG_AROB:
case PG_K:
case PG_B:
case PG_APOS:
case OU_GRV:
case KC_SPC: // When space is added by Clever Keys
case CNL_ODK:
return true;
default:
invoke_odk = true;
//return deferred_shift_after_dead_key(keycode, mods);
}
}
if (invoke_odk) {
// Special behaviour of PG_ODK when shifted
// Shift must apply to the next keycode
is_shifted = mods & MOD_MASK_SHIFT;
if (is_shifted) {
//invoke_odk = false;
bool is_shifted = false;
if (mods & MOD_MASK_SHIFT) {
del_weak_mods(MOD_MASK_SHIFT);
del_oneshot_mods(MOD_MASK_SHIFT);
unregister_mods(MOD_MASK_SHIFT);
is_shifted = true;
}
} else {
if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_3PTS: // For Clever Keys
case PG_PVIR:
case PG_AROB:
case PG_K:
case PG_B:
case PG_APOS:
case OU_GRV:
case KC_SPC: // When space is added by Clever Keys
case CNL_ODK:
break;
default:
tap_code(PG_ODK);
}
}
tap_code(PG_ODK);
if (is_shifted) {
is_shifted = false;
//set_mods(mods);
add_weak_mods(MOD_BIT(KC_LSFT));
set_oneshot_mods(MOD_BIT(KC_LSFT)); // Don't use weak mods!
}
if (keycode == PG_ODK) { return false; }
}
}
return true;
}
/* void odk_layer_exit_check(uint16_t keycode) {
if (keycode == odk_keycode) {
layer_off(_ODK);
odk_keycode = KC_NO;
bool deferred_shift_after_dead_key(uint16_t keycode, uint8_t mods) {
bool is_shifted = false;
if (mods & MOD_MASK_SHIFT) {
del_weak_mods(MOD_MASK_SHIFT);
del_oneshot_mods(MOD_MASK_SHIFT);
unregister_mods(MOD_MASK_SHIFT);
is_shifted = true;
}
} */
tap_code(PG_ODK);
if (is_shifted) { set_oneshot_mods(MOD_BIT(KC_LSFT)); } // Don't use weak mods!
return !(keycode == PG_ODK);
}

View file

@ -24,10 +24,8 @@
extern "C" {
#endif
extern bool is_shifted;
bool process_odk_layer(uint16_t keycode, keyrecord_t *record);
//void odk_layer_exit_check(uint16_t keycode);
bool deferred_shift_after_dead_key(uint16_t keycode, uint8_t mods);
#ifdef __cplusplus
}

View file

@ -23,9 +23,13 @@ oneshot_state os_alt_state = os_up_unqueued;
oneshot_state os_altgr_state = os_up_unqueued;
oneshot_state os_win_state = os_up_unqueued;
uint8_t os4a_layer = 0;
static uint8_t os4a_layer = 0;
static bool exit_os4a_layer = false;
uint8_t get_os4a_layer(void) {
return (os4a_layer);
}
void os4a_layer_on(uint8_t layer) {
layer_on(layer);
os4a_layer = layer;
@ -40,7 +44,7 @@ void os4a_layer_off(uint8_t layer) {
void os4a_tap(uint16_t keycode) {
if (os4a_layer == 0) {
// Activate OS4A layer
os4a_layer_on(get_os4a_layer(keycode));
os4a_layer_on(os4a_layer_from_trigger(keycode));
} else {
// Press again an OS4A key to exit the OS4A layer and clear the OS mods.
os4a_layer_off(os4a_layer);
@ -57,23 +61,27 @@ bool process_os4a_keys(uint16_t keycode, keyrecord_t *record) {
return true;
}
bool process_os4a_layers(uint16_t keycode, keyrecord_t *record) {
// Should keycode exit the OS4A layer ?
if (os4a_layer_changer(keycode)) { return true; }
if (is_oneshot_ignored_key(keycode)) { return false; }
bool add_shift(uint16_t keycode, keyrecord_t *record) {
// Add OS Shift when no other mods are active.
// Testing exit_os4a_layer is necessary to prevent OS shift to be added when other features create keyrecords
// to be processed (ex: custom altgr, clever keys).
uint8_t mods = get_mods() | get_oneshot_mods();
if (!exit_os4a_layer && to_be_shifted(keycode, record) && mods == 0) {
// Don't use weak mods, it interferes with Capsword.
set_oneshot_mods(MOD_BIT(KC_LSFT));
}
return true;
// Testing exit_os4a_layer is necessary to prevent OS shift to be added in case of rolled keys
// or when other features invoke keycodes to be processed (ex: custom altgr, clever keys).
//if (exit_os4a_layer) { return false; }
// Shift shouldn't be added if other mods are active
if ((get_mods() | get_oneshot_mods()) != 0) { return false; }
// Combos and encoder events.
if (!IS_KEYEVENT(record->event)) { return true; }
// Specific exceptions
if (not_to_be_shifted(keycode)) { return false; }
// Otherwise, add shift if the key is on the other side of the keyboard.
return (os4a_layer == _R_MODS) == on_left_hand(record->event.key);
}
void mouse_mods_key_up(uint16_t keycode, keyrecord_t *record) {
// The OS4A layer must be exited only when ctrl or shift are registered,
@ -81,7 +89,7 @@ void mouse_mods_key_up(uint16_t keycode, keyrecord_t *record) {
//if (get_mods() & QK_ONE_SHOT_MOD_GET_MODS(keycode)) {
// When ctrl or shift are released after being held, exit the OS4A layer.
if (!record->event.pressed && !record->tap.count) {
if (!record->tap.count) {
os4a_layer_off(os4a_layer);
}
}
@ -92,21 +100,30 @@ bool process_mods(uint16_t keycode, keyrecord_t *record) {
update_oneshot(&os_shft_state, KC_LSFT, OS_SHFT, keycode, record);
update_oneshot(&os_ctrl_state, KC_LCTL, OS_CTRL, keycode, record);
update_oneshot(&os_alt_state, KC_LALT, OS_LALT, keycode, record);
update_oneshot(&os_altgr_state, KC_RALT, OS_RALT, keycode, record);
update_oneshot(&os_win_state, KC_LWIN, OS_WIN, keycode, record);
//update_oneshot(&os_altgr_state, KC_RALT, OS_RALT, keycode, record);
// Handling OS4A keys
if (IS_OS4A_KEY(keycode)) { return process_os4a_keys(keycode, record); }
if (os4a_layer == 0) { return true; }
// Behaviour of the OS4A layers
if (os4a_layer != 0) { exit_os4a_layer = process_os4a_layers(keycode, record); }
if (exit_os4a_layer) {
os4a_layer_off(os4a_layer);
// When Ctrl or Shift are released, for mouse use.
//if (mods_for_mouse(keycode)) { mouse_mods_key_up(keycode, record); }
} else if (record->event.pressed) {
if (!record->event.pressed) {
if (os4a_layer != 0 && exit_os4a_layer) { os4a_layer_off(os4a_layer); }
if (!should_stay_os4a_layer(keycode)) {
if (add_shift(keycode, record)) { set_oneshot_mods(MOD_BIT(KC_LSFT)); }
exit_os4a_layer = true;
}
} else { // On release
// When Ctrl or Shift are released, for mouse use.
//if (mods_for_mouse(keycode)) { mouse_mods_key_up(keycode, record); }
}
return true;
}

View file

@ -24,20 +24,15 @@
extern "C" {
#endif
extern uint8_t os4a_layer;
//extern bool exit_os4a_layer;
//extern bool pending_OSL;
uint8_t get_os4a_layer(void);
void os4a_layer_off(uint8_t layer);
void os4a_layer_on(uint8_t layer);
void os4a_tap(uint16_t keycode);
bool process_os4a_keys(uint16_t keycode, keyrecord_t *record);
void update_osl(uint16_t keycode);
bool process_os4a_layers(uint16_t keycode, keyrecord_t *record);
bool add_shift(uint16_t keycode, keyrecord_t *record);
void mouse_mods_key_up(uint16_t keycode, keyrecord_t *record);

View file

@ -26,8 +26,7 @@ void tap_converter(uint16_t keycode, keyrecord_t *record) {
} else {
if (IS_QK_MOD_TAP(keycode) || IS_QK_LAYER_TAP(keycode)) {
// Tranform the record to send the tap event
//record->keycode = tap_hold_extractor(keycode);
record->keycode = (keycode &= 0xff);
record->keycode = tap_hold_extractor(keycode);
}
process_record(record);
}

View file

@ -16,54 +16,9 @@
#include "features_conf.h"
bool is_caps_lock_on(void) { return host_keyboard_led_state().caps_lock; }
bool is_letter(uint16_t keycode) {
switch (keycode) {
case KC_A ... KC_F:
case KC_H ... KC_P:
case KC_R ... KC_S:
case KC_U ... KC_Z:
case PG_L:
case PG_E:
case KC_GRV ... KC_DOT:
return true;
default:
return false;
}
}
bool is_send_string_macro(uint16_t keycode) {
switch (keycode) {
case OU_GRV:
case MAGIC:
//case PG_DEG:
return true;
default:
return false;
}
}
bool is_followed_by_apos(uint16_t keycode, uint16_t prev_keycode) {
switch (keycode) {
case PG_Q:
return true;
case PG_L:
case PG_T:
case PG_D:
case PG_C:
case PG_N:
case PG_S:
case PG_M:
case PG_Y:
case PG_J:
if (!is_letter(prev_keycode)) { return true; }
}
return false;
}
// This function extracts the base keycode of MT and LT,
// even if the tap/hold key is a custom one, with non-basic tap keycode.
@ -72,7 +27,7 @@ uint16_t tap_hold_extractor(uint16_t keycode) {
case LT_NBSPC:
return NNB_SPC;
default:
return keycode &= 0xff;
return keycode &= 0xff; //QK_MOD_TAP_GET_TAP_KEYCODE(keycode)
}
}
@ -103,68 +58,6 @@ bool process_custom_tap_hold(uint16_t keycode, keyrecord_t *record) {
}
// Caps Word
bool caps_word_press_user(uint16_t keycode) {
// Caps Word shouldn't be applied with Alt-gr
// Managing underscore and slash on alt gr + E/T.
// Underscore and slash must continue Caps Word, without shifting.
/* if ((get_mods() & MOD_BIT(KC_ALGR))) {
switch (keycode) {
case PG_E:
case PG_T:
return true;
default:
return false;
}
} */
if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_VIRG:
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
case PG_Y:
case PG_T:
return true;
case PG_POIN:
return false;
}
}
// Keycodes that continue Caps Word, with shift applied.
// @ must be shifted, bc of CleverKeys using it.
if (is_letter(keycode) || is_send_string_macro(keycode) || keycode == PG_AROB) {
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
}
switch (keycode) {
// Keycodes that continue Caps Word, without shifting.
case PG_ODK:
//case PG_GRV:
case PG_UNDS:
case PG_TIRE:
case PG_SLSH:
case KC_KP_1 ... KC_KP_0:
//case KC_LEFT:
//case KC_RIGHT:
case KC_BSPC:
case LCTL(KC_BSPC):
case KC_DEL:
case PG_APOS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
// Clever keys configuration
uint16_t get_ongoing_keycode_user(uint16_t keycode) {
@ -176,11 +69,12 @@ uint16_t get_ongoing_keycode_user(uint16_t keycode) {
switch (keycode) {
case PG_K:
case PG_B:
case PG_AROB:
case PG_3PTS:
case KC_SPC: // In order to uppercase J after '?' for ex.
case KC_SPC: // When space is added by clever keys, for ex. in order to uppercase K after '?' for ex.
return keycode;
case PG_POIN:
return PG_3PTS;
default:
clear_recent_keys();
return KC_NO;
@ -189,9 +83,10 @@ uint16_t get_ongoing_keycode_user(uint16_t keycode) {
return KC_TRNS;
}
// One-shot 4 all configuration
uint8_t get_os4a_layer(uint16_t keycode) {
uint8_t os4a_layer_from_trigger(uint16_t keycode) {
switch (keycode) {
case L_OS4A: return _L_MODS;
case R_OS4A: return _R_MODS;
@ -199,32 +94,31 @@ uint8_t get_os4a_layer(uint16_t keycode) {
}
}
bool os4a_layer_changer(uint16_t keycode) {
bool should_stay_os4a_layer(uint16_t keycode) {
// keycodes that stay on os4a layers w/o being shifted
switch (keycode) {
case OS_FA:
case NUMWORD:
case TG_FA:
case OS_RSA:
case NUM_ODK:
case OS_SHFT:
case OS_CTRL:
case OS_RALT:
case OS_LALT:
case OS_WIN:
return true;
default:
return false;
}
}
bool to_be_shifted(uint16_t keycode, keyrecord_t *record) {
// Combos and encoder events.
if (!IS_KEYEVENT(record->event)) { return true; }
bool not_to_be_shifted(uint16_t keycode) {
// keycodes that exit os4a layers w/o being shifted
switch (keycode) {
case OS_ODK:
is_shifted = true;
case KC_CAPS:
case CAPSWORD:
case CAPSLIST:
return false;
default:
return (os4a_layer == _R_MODS) == on_left_hand(record->event.key);
case KC_CAPS:
case CAPSWORD:
case CAPSLIST:
return true;
default:
return false;
}
}
@ -242,16 +136,19 @@ bool is_oneshot_cancel_key(uint16_t keycode) {
}
bool is_oneshot_ignored_key(uint16_t keycode) {
// On veut que la touche typo soit ignorée par tous les Callum mods sauf Alt-gr.
// Ça permet de transmettre les mods à la touche suivante, par ex pour faire Ctrl + K.
// Alt-gr et shift s'appliquent à la touche typo, pour permettre de faire les majuscules plus facilement ainsi que ] avec.
uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods();
//if (keycode == OS_ODK && (mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_ALGR)))) { return true; }
if (keycode == OS_ODK && (mods & ~MOD_BIT(KC_ALGR))) { return true; }
const uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods();
//if (keycode == OS_ODK && (mods & ~MOD_BIT(KC_ALGR))) { return true; }
switch (keycode) {
//case OS_ODK: /!\ A ne pas remettre, sous peine de ne pas pouvoir faire shift + typo + touche de l'autre côté
case OS_ODK:
// On veut que la touche typo soit ignorée par tous les Callum mods sauf Alt-gr.
// Ça permet de transmettre les mods à la touche suivante, par ex pour faire Ctrl + K.
// Alt-gr doit pouvoir sappliquer à la touche typo, pour permettre de faire la touche morte "~" avec.
// OS_ODK ne doit être ignored_key que lorsquelle est employée avec Alt-gr
// sous peine de ne pas pouvoir faire shift + typo + touche de l'autre côté
if (mods & ~MOD_BIT(KC_ALGR)) { return true; }
break;
case L_OS4A:
case R_OS4A:
case OS_SHFT:
@ -259,14 +156,13 @@ bool is_oneshot_ignored_key(uint16_t keycode) {
case OS_RALT:
case OS_LALT:
case OS_WIN:
case OS_FA:
case NUMWORD:
case OS_FA: // to be combined with Alt
case TG_FA:
//case NUM_ODK: // Ne sert à rien, car NUM_ODK est un vrai one-shot : les mods sont transmis même sans paramétrage.
return true;
default:
return false;
case NUMWORD: // to combine numbers with mods
//case NUM_ODK: // NUM_ODK sends PG_ODK when pressed. When shifted, PG_ODK sends one-shot shift.
return true;
}
return false;
}
@ -291,9 +187,8 @@ uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
return C(PG_Z);
}
if (recent[RECENT_SIZE - 1] != KC_NO) { return MAGIC; }
if (get_recent_keycode(-1) != KC_NO) { return MAGIC; }
if (get_last_keycode() == KC_NO) { return MAGIC; }
return KC_TRNS; // Defer to default definitions.
}

View file

@ -20,16 +20,13 @@
#include "keymap.h"
bool is_caps_lock_on(void);
bool is_letter(uint16_t keycode);
bool is_send_string_macro(uint16_t keycode);
bool is_followed_by_apos(uint16_t keycode, uint16_t prev_keycode);
uint16_t tap_hold_extractor(uint16_t keycode);
bool process_custom_tap_hold(uint16_t keycode, keyrecord_t *record);
uint16_t get_ongoing_keycode_user(uint16_t keycode);
uint8_t get_os4a_layer(uint16_t keycode);
bool os4a_layer_changer(uint16_t keycode);
bool to_be_shifted(uint16_t keycode, keyrecord_t *record);
uint8_t os4a_layer_from_trigger(uint16_t keycode);
bool should_stay_os4a_layer(uint16_t keycode);
bool not_to_be_shifted(uint16_t keycode);
//bool mods_for_mouse(uint16_t keycode);

View file

@ -20,7 +20,14 @@
#include "keymap.h"
uint16_t global_quick_tap_timer = 0;
static uint16_t global_quick_tap_timer = 0;
bool enough_time_before_combo(void) {
return timer_elapsed(global_quick_tap_timer) > TAP_INTERVAL;
}
static uint16_t next_keycode;
static keyrecord_t next_record;
// Tap-hold configuration
@ -40,9 +47,9 @@ bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
if (record->event.key.col != next_record.event.key.col) {
// La ligne suivante n'est nécessaire que si on a besoin de doubler rapidement un caractère présent sur la moitié droite du clavier.
// Ce n'est pas nécessaire pour l'instant, vu que les guillemets sont passés à gauche.
//if (keycode == OS_ODK) { return true; }
// Permet de doubler rapidement un caractère présent sur la moitié droite du clavier.
// Fait également gagner pas mal de place sur le FW.
if (keycode == OS_ODK) { return true; }
if (forbidden_chord(keycode, record, next_keycode, &next_record)) {
// When a layer-tap key overlaps with another key on the same hand, send its base keycode.
@ -55,24 +62,16 @@ bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
return false;
}
/* bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
return !forbidden_chord(keycode, record, next_keycode, &next_record);
} */
// Matrix scan
void matrix_scan_user(void) {
recent_keys_task();
//swapper_task();
}
// Key processing
uint16_t next_keycode;
keyrecord_t next_record;
bool pre_process_record_user(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
@ -112,14 +111,15 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// Clever keys
if (!process_clever_keys(keycode, record)) { return false; }
//if (!process_caps_word(keycode, record)) {return false; }
// Process all other keycodes normally
return true;
}
void post_process_record_user(uint16_t keycode, keyrecord_t* record) {
//os4a_layer_exit_check();
//numword_exit_check();
if (is_caps_word_on()) { clear_weak_mods(); }
end_CK(record);
}
@ -131,7 +131,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
* Base Layer: ALPHAS
*»\
* ,-------------------------------------------. ,-------------------------------------------.
* | | X | È | É | . | K | | V | B | L | M | X | |
* | | À | È | É | . | K | | V | B | L | M | X | |
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | Enter | O | U | A | I | J | | G | T | S | N | R | F |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
@ -190,7 +190,29 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
_______, _______, KC_CAPS, _______, MAGIC, TG_APOS, _______, _______, KC_NO, KC_NO
),
/*
* Layer 1 : Numpad
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) | LOCK | | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | |Expos.| 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_NUMBERS] = LAYOUT(
// S(KC_4), S(KC_3) and S(PG_EGAL) are here to give easy access to ⅔, ¾ and ≠.
_______, PG_DLR, PG_MOIN, PG_PLUS, PG_EURO, PG_PERC, PG_EXP, S(PG_EGAL), PG_EGAL, PG_ASTX, _______, _______,
_______, KC_4, KC_3, KC_2, MT_1, PG_2PTS, PG_IND, MT_SLSH, KC_6, KC_7, KC_8, _______,
_______, S(KC_4), S(KC_3), PG_H, KC_5, _______, _______, _______, _______, _______, _______, KC_9, PG_DEG, _______, PG_ODK, _______,
_______, _______, KC_PDOT, LT_0 , LT_NBSPC, _______, KC_SPC, _______, _______, _______
),
/*
* Layer : Symbols
*
@ -213,28 +235,6 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
),
/*
* Layer 1 : Numpad
*
* ,-------------------------------------------. ,-------------------------------------------.
* | | ! | ? | & | ; | | | | | 7 | 8 | 9 | * |NumLock|
* |--------+------+------+------+------+------| |------+------+------+------+------+--------|
* | | { | } | ( | ) | LOCK | | = | 4 | 5 | 6 | / | \ |
* |--------+------+------+------+------+------+-------------. ,-------------+------+------+------+------+------+--------|
* | | [ | ] | < | > |Indice| | | | | |Expos.| 1 | 2 | 3 | + | % |
* `----------------------+------+------+------+------+------| |------+------+------+------+------+----------------------'
* | | | | | | | | 0 | . | | |
* | | | | | | | , | | | | |
* `----------------------------------' `----------------------------------'
*/
[_NUMBERS] = LAYOUT(
_______, PG_DLR, PG_MOIN, PG_PLUS, PG_EURO, PG_PERC, PG_EXP, _______, PG_EGAL, PG_ASTX, _______, _______,
_______, KC_4, KC_3, KC_2, MT_1, PG_2PTS, PG_IND, MT_SLSH, KC_6, KC_7, KC_8, _______,
_______, _______, _______, PG_H, KC_5, _______, _______, _______, _______, _______, _______, KC_9, PG_DEG, _______, PG_ODK, _______,
_______, _______, KC_PDOT, KC_0 , LT_NBSPC, _______, KC_SPC, _______, _______, _______
),
/*
* Layer 2 : Symbols
*
@ -251,7 +251,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
*/
[_ODK] = LAYOUT(
_______, _______, _______, _______, _______, PG_T, _______, _______, _______, _______, _______, _______,
_______, OU_GRV, _______, _______, PG_PVIR, PG_3PTS, _______, PG_K, _______, _______, _______, _______,
_______, OU_GRV, _______, _______, PG_PVIR, _______, _______, PG_K, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, PG_AROB, CNL_ODK, _______,
_______, _______, _______, _______, PG_O, PG_APOS, PG_B, _______, _______, _______
),

View file

@ -20,6 +20,7 @@
#include "keymap_french_propergol.h"
#include "features_conf.h"
#include "word_conf.h"
#include "clever_keys.h"
#include "features/tap_hold_utilities.h"
#include "features/clever_keys_utilities.h"
@ -37,8 +38,8 @@ enum layers {
_L_MODS,
_R_MODS,
_ODK,
_SYMBOLS,
_NUMBERS,
_SYMBOLS,
_SHORTNAV,
_FUNCAPPS,
};
@ -64,29 +65,28 @@ enum custom_keycodes {
PG_DEG
};
// Layer taps
// Layer changers
#define LT_SPC LT(_SYMBOLS, KC_SPC)
#define LT_E LT(_SYMBOLS, PG_E)
#define LT_REPT LT(_NUMBERS, KC_1)
#define LT_MGC LT(_SHORTNAV, KC_1)
#define LT_0 LT(_SYMBOLS, KC_0)
#define LT_NBSPC LT(_SHORTNAV, NNB_SPC)
#define OS_ODK OSL(_ODK)
#define NUM_ODK OSL(_NUMBERS)
#define OS_FA OSL(_FUNCAPPS)
#define TG_FA TG(_FUNCAPPS)
#define TG_FA TT(_FUNCAPPS)
// Mods
#define MT_SLSH SFT_T(PG_SLSH)
#define MT_1 SFT_T(KC_1)
#define LT_NBSPC LT(_SHORTNAV, NNB_SPC)
#define E_CIRC S(FG_0)
#define OS_ODK OSL(_ODK)
#define OS_RSA OSM(MOD_RALT | MOD_LSFT)
#define NUM_ODK OSL(_NUMBERS)
// One shot mods
// OS4A
#define L_OS4A LSFT_T(OS4A)
#define R_OS4A RSFT_T(OS4A)
#define IS_OS4A_KEY(keycode) (get_os4a_layer(keycode) != 0)
#define IS_OS4A_KEY(keycode) (os4a_layer_from_trigger(keycode) != 0)
bool forbidden_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record, uint16_t other_keycode, keyrecord_t* other_record);
extern uint16_t global_quick_tap_timer;
extern uint16_t next_keycode;
extern keyrecord_t next_record;
bool enough_time_before_combo(void);
bool forbidden_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record, uint16_t other_keycode, keyrecord_t* other_record);

View file

@ -79,7 +79,7 @@ bool oled_task_user(void) {
oled_write_P(((mods & MOD_BIT(KC_LALT)) == MOD_BIT(KC_LALT)) ? PSTR("ALT ") : PSTR(" "), false);
oled_write_P(is_caps_word_on() ? PSTR("CAPSWORD\n") : PSTR(" \n"), false);
oled_write_P(is_num_word_on ? PSTR("NUMWORD\n") : PSTR(" \n"), false);
oled_write_P(is_num_word_enabled() ? PSTR("NUMWORD\n") : PSTR(" \n"), false);
// Write host Keyboard LED Status to OLEDs
led_t led_usb_state = host_keyboard_led_state();

View file

@ -14,9 +14,6 @@ RGBLIGHT_ENABLE = no # Disable keyboard RGB underglow
#CONSOLE_ENABLE = yes
LTO_ENABLE = yes
CONSOLE_ENABLE = no
COMMAND_ENABLE = no
MOUSEKEY_ENABLE = no
ENCODER_MAP_ENABLE = no
@ -39,12 +36,11 @@ SRC += features/capslist.c
SRC += features/macros.c
SRC += features/oneshot.c
SRC += features_conf.c
SRC += word_conf.c
SRC += features/odk_layer.c
INTROSPECTION_KEYMAP_C = features/combos.c
MUSIC_ENABLE = no
SPACE_CADET_ENABLE = no
GRAVE_ESC_ENABLE = no
MAGIC_ENABLE = no
GRAVE_ESC_ENABLE = no

View file

@ -0,0 +1,190 @@
/* Copyright 2025 @Kawamashi
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "word_conf.h"
bool is_letter(uint16_t keycode) {
switch (keycode) {
case KC_A ... KC_F:
case KC_H ... KC_P:
case KC_R ... KC_S:
case KC_U ... KC_Z:
case PG_L:
case PG_E:
case KC_GRV ... KC_DOT:
return true;
default:
return false;
}
}
bool is_send_string_macro(uint16_t keycode) {
switch (keycode) {
case OU_GRV:
case MAGIC:
case PG_AROB: // because of Clever Keys
return true;
default:
return false;
}
}
bool is_followed_by_apos(uint16_t keycode, uint16_t prev_keycode) {
switch (keycode) {
case PG_Q:
return true;
case PG_L:
case PG_T:
case PG_D:
case PG_C:
case PG_N:
case PG_S:
case PG_M:
case PG_Y:
case PG_J:
if (!is_letter(prev_keycode)) { return true; }
}
return false;
}
// Caps Word
bool caps_word_press_user(uint16_t keycode) {
if (IS_LAYER_ON(_ODK)) {
switch (keycode) {
case PG_VIRG:
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
case PG_Y: // pour le tréma
case PG_T: // pour le trait dunion insécable
return true;
}
}
// Keycodes that continue Caps Word, with shift applied.
// @ must be shifted, bc of CleverKeys using it.
if (is_letter(keycode) || is_send_string_macro(keycode)) {
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
}
switch (keycode) {
// Keycodes that continue Caps Word, without shifting.
case PG_ODK:
case PG_UNDS:
case PG_TIRE:
case PG_SLSH:
case KC_1 ... KC_0:
//case KC_LEFT:
//case KC_RIGHT:
case KC_BSPC:
case LCTL(KC_BSPC):
case KC_DEL:
case PG_APOS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
// Num Word
bool should_exit_num_word(uint16_t keycode, const keyrecord_t *record) {
switch (keycode) {
// Keycodes which should not disable num word mode.
// Numpad keycodes
case KC_1 ... KC_0:
case KC_PDOT:
case PG_MOIN:
case PG_ASTX:
case PG_PLUS:
case PG_SLSH:
case PG_EGAL:
case PG_EXP:
case PG_IND:
case PG_H:
case PG_2PTS:
case NNB_SPC:
// Misc
case KC_BSPC:
case PG_ODK: // Not to exit Numword when chording it with ODK
//case NUMWORD: // For the combo NUMWORD to work
return false;
}
return true;
}
// Caps List
bool should_continue_caps_list(uint16_t keycode) {
if (keycode == KC_BSPC) { return update_capslist_countdown(-1); }
if (is_letter(keycode) || is_send_string_macro(keycode)) { return update_capslist_countdown(1); }
// This condition can't be merged with the previous one
// because caps_word_press_user adds shift to letters and send-string macros.
if (caps_word_press_user(keycode)) { return update_capslist_countdown(1); }
// Keycodes that continue Caps List, but not Caps Word.
// These keycodes trigger the countdown to end Caps List.
switch (keycode) {
case PG_VIRG:
case KC_SPC:
return update_capslist_countdown(1);
}
return false; // Deactivate Caps List.
}
bool caps_word_reactivation(void) {
// Words that continue Caps List.
if (get_recent_keycode(-1) == KC_SPC) {
if (get_recent_keycode(-2) == PG_VIRG) { return true; }
if (word_check((uint16_t[]) {KC_SPC, PG_E, PG_T}, 3, 2)) { return true; }
if (word_check((uint16_t[]) {KC_SPC, PG_O, PG_U}, 3, 2)) { return true; }
/* if (get_recent_keycode(-4) == KC_SPC && get_recent_keycode(-3) == PG_E && get_recent_keycode(-2) == PG_T) {
countdown_end = 2;
return true;
}
if (get_recent_keycode(-4) == KC_SPC && get_recent_keycode(-3) == PG_O && get_recent_keycode(-2) == PG_U) {
countdown_end = 2;
return true;
} */
}
return false;
}

View file

@ -20,13 +20,8 @@
#include "quantum.h"
#include "keymap.h"
#ifdef __cplusplus
extern "C" {
#endif
bool is_letter(uint16_t keycode);
bool is_send_string_macro(uint16_t keycode);
bool is_followed_by_apos(uint16_t keycode, uint16_t prev_keycode);
bool process_odk_layer(uint16_t keycode, keyrecord_t *record);
//void odk_layer_exit_check(uint16_t keycode);
#ifdef __cplusplus
}
#endif
bool should_exit_num_word(uint16_t keycode, const keyrecord_t *record);