Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: [Core] Register multiple key events/presses per USB report #12686

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/config_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ Use these to enable or disable building certain features. The more you have enab
* Key combo feature
* `NKRO_ENABLE`
* USB N-Key Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
* `REGISTER_MULTIPLE_KEYEVENTS_ENABLE`
* This allows for multiple key presses and or releases per USB hid report by combining all key state changes of a single matrix scan before reporting to host.
* `AUDIO_ENABLE`
* Enable the audio subsystem.
* `KEY_OVERRIDE_ENABLE`
Expand Down
1 change: 1 addition & 0 deletions docs/ja/config_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* キーコンボ機能
* `NKRO_ENABLE`
* USB N-キーロールオーバー - これが動作しない場合は、ここを見てください: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
* `REGISTER_MULTIPLE_KEYEVENTS_ENABLE`
* `AUDIO_ENABLE`
* オーディオサブシステムを有効にします。
* `RGBLIGHT_ENABLE`
Expand Down
171 changes: 110 additions & 61 deletions quantum/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "action.h"
#include "wait.h"

/* private functions */
static void register_code_P(uint8_t code, void send_report_f(void));
static void unregister_code_P(uint8_t code, void send_report_f(void));

extern volatile unregister_keycodes_t unregister_keycodes;

#ifdef BACKLIGHT_ENABLE
# include "backlight.h"
#endif
Expand Down Expand Up @@ -281,18 +287,18 @@ void process_action(keyrecord_t *record, action_t action) {
} else {
add_weak_mods(mods);
}
send_keyboard_report();
send_keyboard_report_deferred();
}
register_code(action.key.code);
register_code_deferred(action.key.code);
} else {
unregister_code(action.key.code);
unregister_code_deferred(action.key.code);
if (mods) {
if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
del_mods(mods);
} else {
del_weak_mods(mods);
}
send_keyboard_report();
send_keyboard_report_deferred();
}
}
} break;
Expand Down Expand Up @@ -380,12 +386,11 @@ void process_action(keyrecord_t *record, action_t action) {
} else {
if (tap_count > 0) {
dprint("MODS_TAP: Tap: unregister_code\n");
uint16_t delay = TAP_CODE_DELAY;
if (action.layer_tap.code == KC_CAPS) {
wait_ms(TAP_HOLD_CAPS_DELAY);
} else {
wait_ms(TAP_CODE_DELAY);
delay = TAP_HOLD_CAPS_DELAY;
}
unregister_code(action.key.code);
unregister_code_buffered(action.key.code, delay);
} else {
dprint("MODS_TAP: No tap: add_mods\n");
unregister_mods(mods);
Expand Down Expand Up @@ -571,12 +576,11 @@ void process_action(keyrecord_t *record, action_t action) {
} else {
if (tap_count > 0) {
dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n");
uint16_t delay = TAP_CODE_DELAY;
if (action.layer_tap.code == KC_CAPS) {
wait_ms(TAP_HOLD_CAPS_DELAY);
} else {
wait_ms(TAP_CODE_DELAY);
delay = TAP_HOLD_CAPS_DELAY;
}
unregister_code(action.layer_tap.code);
unregister_code_buffered(action.layer_tap.code, delay);
} else {
dprint("KEYMAP_TAP_KEY: No tap: Off on release\n");
layer_off(action.layer_tap.val);
Expand Down Expand Up @@ -651,10 +655,9 @@ void process_action(keyrecord_t *record, action_t action) {
swap_held = false;
}
if (event.pressed) {
register_code(action.swap.code);
register_code_deferred(action.swap.code);
} else {
wait_ms(TAP_CODE_DELAY);
unregister_code(action.swap.code);
unregister_code_buffered(action.swap.code, TAP_CODE_DELAY);
*record = (keyrecord_t){}; // hack: reset tap mode
}
} else {
Expand Down Expand Up @@ -739,11 +742,21 @@ void process_action(keyrecord_t *record, action_t action) {
#endif
}

void register_code_deferred(uint8_t code) {
#if defined(REGISTER_MULTIPLE_KEYEVENTS_ENABLE)
register_code_P(code, &send_keyboard_report_deferred);
#else
register_code_P(code, &send_keyboard_report);
#endif
}

void register_code(uint8_t code) { register_code_P(code, &send_keyboard_report); }

/** \brief Utilities for actions. (FIXME: Needs better description)
*
* FIXME: Needs documentation.
*/
void register_code(uint8_t code) {
void register_code_P(uint8_t code, void send_report_f(void)) {
if (code == KC_NO) {
return;
}
Expand All @@ -757,7 +770,7 @@ void register_code(uint8_t code) {
send_keyboard_report();
wait_ms(100);
del_key(KC_CAPSLOCK);
send_keyboard_report();
send_report_f();
}

else if (KC_LOCKING_NUM == code) {
Expand All @@ -768,7 +781,7 @@ void register_code(uint8_t code) {
send_keyboard_report();
wait_ms(100);
del_key(KC_NUMLOCK);
send_keyboard_report();
send_report_f();
}

else if (KC_LOCKING_SCROLL == code) {
Expand All @@ -779,13 +792,14 @@ void register_code(uint8_t code) {
send_keyboard_report();
wait_ms(100);
del_key(KC_SCROLLLOCK);
send_keyboard_report();
send_report_f();
}
#endif

else if IS_KEY (code) {
// TODO: should push command_proc out of this block?
if (command_proc(code)) return;
else if
IS_KEY(code) {
// TODO: should push command_proc out of this block?
if (command_proc(code)) return;

#ifndef NO_ACTION_ONESHOT
/* TODO: remove
Expand All @@ -794,49 +808,80 @@ void register_code(uint8_t code) {
add_mods(oneshot_state.mods);

add_key(code);
send_keyboard_report();
send_report_f();

set_mods(tmp_mods);
send_keyboard_report();
send_report_f();
oneshot_cancel();
} else
*/
#endif
{
// Force a new key press if the key is already pressed
// without this, keys with the same keycode, but different
// modifiers will be reported incorrectly, see issue #1708
if (is_key_pressed(keyboard_report, code)) {
if (is_key_pressed(&keyboard_report, code)) {
del_key(code);
send_keyboard_report();
}
add_key(code);
send_keyboard_report();
send_report_f();
}
else if
IS_MOD(code) {
add_mods(MOD_BIT(code));
send_report_f();
}
} else if IS_MOD (code) {
add_mods(MOD_BIT(code));
send_keyboard_report();
}
#ifdef EXTRAKEY_ENABLE
else if IS_SYSTEM (code) {
host_system_send(KEYCODE2SYSTEM(code));
} else if IS_CONSUMER (code) {
host_consumer_send(KEYCODE2CONSUMER(code));
}
else if
IS_SYSTEM(code) { host_system_send(KEYCODE2SYSTEM(code)); }
else if
IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); }
#endif
#ifdef MOUSEKEY_ENABLE
else if IS_MOUSEKEY (code) {
mousekey_on(code);
mousekey_send();
else if
IS_MOUSEKEY(code) {
mousekey_on(code);
mousekey_send();
}
#endif
}

void unregister_code_deferred(uint8_t code) {
#if defined(REGISTER_MULTIPLE_KEYEVENTS_ENABLE)
unregister_code_P(code, &send_keyboard_report_deferred);
#else
unregister_code_P(code, &send_keyboard_report);
#endif
}

void unregister_code(uint8_t code) { unregister_code_P(code, &send_keyboard_report); }

void unregister_code_buffered(uint8_t code, uint16_t delay) {
#if defined(REGISTER_MULTIPLE_KEYEVENTS_ENABLE)
if (unregister_keycodes.len > UNREGISTER_KEYCODES_BUFFER_SIZE) {
dprintln("ERROR: couldn't add unregister keycode, buffer is full!");
return;
}
unregister_keycodes.buffer[unregister_keycodes.len] = code;
unregister_keycodes.len += 1;
if (unregister_keycodes.tap_delay < delay) {
unregister_keycodes.tap_delay = delay;
}
#else

if (delay > 0) {
wait_ms(delay);
}

unregister_code_P(code, &send_keyboard_report);
#endif
}

/** \brief Utilities for actions. (FIXME: Needs better description)
*
* FIXME: Needs documentation.
*/
void unregister_code(uint8_t code) {
void unregister_code_P(uint8_t code, void send_report_f(void)) {
if (code == KC_NO) {
return;
}
Expand All @@ -847,48 +892,52 @@ void unregister_code(uint8_t code) {
if (!(host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK))) return;
# endif
add_key(KC_CAPSLOCK);
send_keyboard_report();
send_report_f();
del_key(KC_CAPSLOCK);
send_keyboard_report();
send_report_f();
}

else if (KC_LOCKING_NUM == code) {
# ifdef LOCKING_RESYNC_ENABLE
if (!(host_keyboard_leds() & (1 << USB_LED_NUM_LOCK))) return;
# endif
add_key(KC_NUMLOCK);
send_keyboard_report();
send_report_f();
del_key(KC_NUMLOCK);
send_keyboard_report();
send_report_f();
}

else if (KC_LOCKING_SCROLL == code) {
# ifdef LOCKING_RESYNC_ENABLE
if (!(host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK))) return;
# endif
add_key(KC_SCROLLLOCK);
send_keyboard_report();
send_report_f();
del_key(KC_SCROLLLOCK);
send_keyboard_report();
send_report_f();
}
#endif

else if IS_KEY (code) {
del_key(code);
send_keyboard_report();
} else if IS_MOD (code) {
del_mods(MOD_BIT(code));
send_keyboard_report();
} else if IS_SYSTEM (code) {
host_system_send(0);
} else if IS_CONSUMER (code) {
host_consumer_send(0);
}
else if
IS_KEY(code) {
del_key(code);
send_report_f();
}
else if
IS_MOD(code) {
del_mods(MOD_BIT(code));
send_report_f();
}
else if
IS_SYSTEM(code) { host_system_send(0); }
else if
IS_CONSUMER(code) { host_consumer_send(0); }
#ifdef MOUSEKEY_ENABLE
else if IS_MOUSEKEY (code) {
mousekey_off(code);
mousekey_send();
}
else if
IS_MOUSEKEY(code) {
mousekey_off(code);
mousekey_send();
}
#endif
}

Expand Down
10 changes: 7 additions & 3 deletions quantum/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ extern "C" {
# endif
#endif

#ifndef TAP_CODE_DELAY
#if !defined(TAP_CODE_DELAY)
# define TAP_CODE_DELAY 0
#endif
#ifndef TAP_HOLD_CAPS_DELAY

#if !defined(TAP_HOLD_CAPS_DELAY)
# define TAP_HOLD_CAPS_DELAY 80
#endif

Expand Down Expand Up @@ -88,7 +89,7 @@ extern bool disable_action_cache;

/* Code for handling one-handed key modifiers. */
#ifdef SWAP_HANDS_ENABLE
extern bool swap_hands;
extern bool swap_hands;
extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS];
# if (MATRIX_COLS <= 8)
typedef uint8_t swap_state_row_t;
Expand All @@ -108,7 +109,10 @@ void process_record(keyrecord_t *record);
void process_record_handler(keyrecord_t *record);
void post_process_record_quantum(keyrecord_t *record);
void process_action(keyrecord_t *record, action_t action);
void register_code_deferred(uint8_t code);
void register_code(uint8_t code);
void unregister_code_deferred(uint8_t code);
void unregister_code_buffered(uint8_t code, uint16_t delay);
void unregister_code(uint8_t code);
void tap_code(uint8_t code);
void tap_code_delay(uint8_t code, uint16_t delay);
Expand Down
Loading