Corne keyboard v4
Recently, I purchased the Corne Keyboard V4, and it has been a game-changer for my typing posture. I absolutely love it! As soon as I got it, I dived into customizing it with the Vial software to suit my preferences.
However, I quickly ran into a challenge. There was a specific feature I wished Vial could support: HOLD_ON_OTHER_KEY_PRESS_PER_KEY. Let me explain why this is important to me.
Rolling Keys and My Typing Habit
I have a natural habit of typing in a "rolling" manner, especially with my pinky finger. This is referred to as "rolling keys," and it looks something like the example below.
Example: Rolling Keys (ABAB)
Time | Physical Key Event | Default Output | With | With |
0 |
| |||
110 |
| B | ||
130 |
| ab | ab | B |
140 |
| ab | ab | B |
Another scenario:
Time | Physical Key Event | Default Output | With | With |
0 |
| |||
110 |
| B | ||
200 |
| B | B | B |
205 |
| B | B | B |
210 |
| B | B | B |
The Issue with My Ctrl Key
I had configured my Ctrl
key using LCTRL_T(KC_ESC)
. However, I often type the sequence Ctrl + E
. My natural typing flow is as follows:
Press
Ctrl
down.Press
E
down.Release
Ctrl
.Release
E
.
Unfortunately, this sequence was being interpreted as "Esc, E" instead of "Ctrl + E," which completely disrupted my workflow. It was frustrating and slowed me down significantly.
Discovering the Solution: QMK Firmware
After extensive research, I found that QMK Firmware supports the HOLD_ON_OTHER_KEY_PRESS_PER_KEY feature, which directly addresses the issue I was facing. Unfortunately, this option isn’t available in Vial. While Vial is an excellent tool for casual users—it allows instant configuration changes without the need for flashing—it lacks some of the advanced features that power users, like me, require. From my investigation of the Vial GitHub repository, it also seems the project isn’t actively maintained, further limiting its functionality.
To better understand and debug my typing behavior, I even created a website: keylogger.krsn.xyz. This tool logs every keystroke I type, giving me a clear view of my habits and helping me fine-tune my keyboard configurations more effectively.
After spending a few days trying to resolve the issue within Vial without success, I made the decision to switch to QMK Firmware. Although QMK requires flashing the keyboard to apply changes, it offers the flexibility and advanced features I needed. I downloaded the necessary tools, configured my keyboard in QMK, and after some effort, it worked perfectly!
Why This Matters
Having a feature like HOLD_ON_OTHER_KEY_PRESS_PER_KEY
would solve this problem. It ensures that when another key is pressed while a mod-tap key (like LCTRL_T
) is held, the modifier behavior takes precedence, preventing accidental misinterpretation. This would be a huge quality-of-life improvement for anyone with similar typing habits.
Configuration Files
Below are the configuration files I used to set up my keyboard with QMK.
config.h
#pragma once
#define QUICK_TAP_TERM 100
#define QUICK_TAP_TERM_PER_KEY
#define TAPPING_TERM 160
#define TAPPING_TERM_PER_KEY
#define PERMISSIVE_HOLD_PER_KEY
#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
#define MOUSEKEY_DELAY 4
#define MOUSEKEY_INTERVAL 12
#define MOUSEKEY_MOVE_DELTA 4
#define MOUSEKEY_MAX_SPEED 10
#define MOUSEKEY_TIME_TO_MAX 30
#define MOUSEKEY_WHEEL_DELAY 4
#define MOUSEKEY_WHEEL_INTERVAL 40
#define MOUSEKEY_WHEEL_MAX_SPEED 8
#define MOUSEKEY_WHEEL_TIME_TO_MAX 30
keymap.c
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT_split_3x6_3_ex2(
//,--------------------------------------------------------------. ,-------------------------------------------------------------.
KC_TAB, KC_Q, KC_W, KC_E,LT(3,KC_R), KC_T, XXXXXXX, TO(0), KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
//|--------+--------+--------+--------+--------+--------+--------| |-------+--------+--------+--------+--------+--------+--------|
CTL_T(KC_ESC),SFT_T(KC_A),OPT_T(KC_S),GUI_T(KC_D),LT(1,KC_F),KC_G,XXXXXXX,TO(5),KC_H, KC_J, KC_K,OPT_T(KC_L),KC_SCLN,MEH_T(KC_QUOT),
//|--------+--------+--------+--------+--------+--------+--------' `-------+--------+--------+--------+--------+--------+--------|
KC_LSFT,MEH_T(KC_Z),LT(5, KC_X), KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_HYPR,
//|--------+--------+--------+--------+--------+--------+--------. ,--------+--------+--------+--------+--------+--------+--------|
MO(3), KC_LGUI, MO(2), LT(1, KC_ENT),KC_SPC, MO(4)
//`--------------------------' `--------------------------'
),
[1] = LAYOUT_split_3x6_3_ex2(
//,--------------------------------------------------------------. ,-------------------------------------------------------------.
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______, _______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------| |-------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, XXXXXXX, _______, _______, KC_LEFT, KC_DOWN, KC_UP,KC_RIGHT, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------' `-------+--------+--------+--------+--------+--------+--------|
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_HOME, KC_PGUP, KC_PGDN, KC_END, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------. ,--------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, _______
//`--------------------------' `--------------------------'
),
[2] = LAYOUT_split_3x6_3_ex2(
//,--------------------------------------------------------------. ,-------------------------------------------------------------.
_______, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, _______, _______, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC,
//|--------+--------+--------+--------+--------+--------+--------| |-------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, KC_EXLM, KC_AT, _______, _______, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS, KC_GRV,
//|--------+--------+--------+--------+--------+--------+--------' `-------+--------+--------+--------+--------+--------+--------|
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE, KC_TILD,
//|--------+--------+--------+--------+--------+--------+--------. ,--------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, _______
//`--------------------------' `--------------------------'
),
[3] = LAYOUT_split_3x6_3_ex2(
//,--------------------------------------------------------------. ,-------------------------------------------------------------.
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______, _______, XXXXXXX, KC_P7, KC_P8, KC_P9, XXXXXXX, _______,
//|--------+--------+--------+--------+--------+--------+--------| |-------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, XXXXXXX, _______, _______, XXXXXXX, KC_P4, KC_P5, KC_P6, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------' `-------+--------+--------+--------+--------+--------+--------|
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_P1, KC_P2, KC_P3, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, KC_P0, _______, _______
//`--------------------------' `--------------------------'
),
[4] = LAYOUT_split_3x6_3_ex2(
//,--------------------------------------------------------------. ,-------------------------------------------------------------.
KC_CAPS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, _______, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_DEL,
//|--------+--------+--------+--------+--------+--------+--------| |-------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, XXXXXXX, _______, _______, XXXXXXX, XXXXXXX, XXXXXXX, KC_F11, KC_F12, KC_MEH,
//|--------+--------+--------+--------+--------+--------+--------' `-------+--------+--------+--------+--------+--------+--------|
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_BRID, KC_BRIU, KC_VOLD, KC_VOLU, KC_MUTE, KC_HYPR,
//|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, _______
//`--------------------------' `--------------------------'
),
[5] = LAYOUT_split_3x6_3_ex2(
//,--------------------------------------------------------------. ,-------------------------------------------------------------.
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______, _______, KC_BTN4, KC_BTN5, KC_MS_U, XXXXXXX, XXXXXXX, _______,
//|--------+--------+--------+--------+--------+--------+--------| |-------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, _______, _______, XXXXXXX, _______, _______, XXXXXXX, KC_MS_L, KC_MS_D, KC_MS_R, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------' `-------+--------+--------+--------+--------+--------+--------|
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_WH_L, KC_WH_D, KC_WH_U, KC_WH_R, XXXXXXX, XXXXXXX,
//|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------|
_______, _______, _______, KC_BTN1, XXXXXXX, KC_BTN2
//`--------------------------' `--------------------------'
)
};
uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case SFT_T(KC_A): // home row
case OPT_T(KC_S): // home row
case GUI_T(KC_D): // home row
case MEH_T(KC_QUOT): // home row
case OPT_T(KC_L): // home row
return TAPPING_TERM + 50;
default:
return TAPPING_TERM;
}
}
uint16_t get_quick_tap_term(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case LT(3,KC_R):
return 0; // disable quick tap
default:
return QUICK_TAP_TERM;
}
}
bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case LT(1, KC_F):
case LT(3, KC_R):
case LT(1, KC_ENT):
// Immediately select the hold action when another key is tapped.
return true;
default:
// Do not select the hold action when another key is tapped.
return false;
}
}
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case CTL_T(KC_ESC):
// Immediately select the hold action when another key is pressed.
return true;
default:
// Do not select the hold action when another key is pressed.
return false;
}
}
rules.mk
# Disable RGB lighting support
RGBLIGHT_ENABLE = no
Final Thoughts
With the HOLD_ON_OTHER_KEY_PRESS_PER_KEY
feature enabled and applied only to my Ctrl
key configured with LCTRL_T(KC_ESC)
, I can ensure the hold action is selected when another key is pressed. This does not affect other keys like LSFT_T(KC_A)
, which retain their default behavior. This setup ensures that sequences like Ctrl + E
register correctly, dramatically improving my workflow.
While Vial remains a great option for instant configuration, QMK's flexibility and advanced features made it the ideal choice for my needs. The process of setting it up was worth it, and I’m now able to enjoy a seamless and efficient typing experience!