はじめに
これは、「C言語とか組み込みなんもわからん」男が QMK というジャングルを探検していく、ノンフィクションドキュメンタリーである……
なお、更新は亀の歩みである……
- はじめに
- 前回のおさらい
- 探検開始
- action.c
- mousekey.h
- mousekey.c
- timer.h
- print.h
- command.h
- command.c
- action_layer.h
- action_layter.c
- ~11行
- ~最終行
- layer_state_t default_layer_state
- layer_state_t default_layer_state_set_user(layer_state_t state)
- layer_state_t default_layer_state_set_kb(layer_state_t state)
- void default_layer_state_set(layer_state_t state)
- void default_layer_debug(void)
- void default_layer_set(layer_state_t state)
- void default_layer_or(layer_state_t state)
- void default_layer_and(layer_state_t state)
- void default_layer_xor(layer_state_t state)
- layer_state_t layer_state
- layer_state_t layer_state_set_user(layer_state_t state)
- layer_state_t layer_state_set_kb(layer_state_t state)
- void layer_state_set(layer_state_t state)
- void layer_clear(void)
- bool layer_state_is(uint8_t layer)
- bool layer_state_cmp(layer_state_t cmp_layer_state, uint8_t layer)
- void layer_move(uint8_t layer)
- void layer_on(uint8_t layer)
- void layer_off(uint8_t layer)
- void layer_invert(uint8_t layer)
- void layer_or(layer_state_t state)
- void layer_and(layer_state_t state)
- void layer_xor(layer_state_t state)
- void layer_debug(void)
- uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS]
- void update_source_layers_cache(keypos_t key, uint8_t layer)
- uint8_t read_source_layers_cache(keypos_t key)
- action_t store_or_get_action(bool pressed, keypos_t key)
- uint8_t layer_switch_get_layer(keypos_t key)
- action_t layer_switch_get_action(keypos_t key)
- まとめ
- 次回予告
前回のおさらい
quantum.h
の include を順番に探検していたら、 keymap.h
もいっぱい include されていたので、順番に探検していたら、 action.c
もいっぱい include されていたので、順番に見ていくことにした
探検開始
続きから探検していこう
keycode.hquantum_keycodes.hkeycode_config.hdebug.hreport.hhost.haction_macro.h- action.h
action.c
ソース全体
/* Copyright 2012,2013 Jun Wako <wakojun@gmail.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 "host.h" #include "keycode.h" #include "keyboard.h" #include "mousekey.h" #include "command.h" #include "led.h" #include "action_layer.h" #include "action_tapping.h" #include "action_macro.h" #include "action_util.h" #include "action.h" #include "wait.h" #ifdef BACKLIGHT_ENABLE # include "backlight.h" #endif #ifdef DEBUG_ACTION # include "debug.h" #else # include "nodebug.h" #endif #ifdef POINTING_DEVICE_ENABLE # include "pointing_device.h" #endif int tp_buttons; #if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) int retro_tapping_counter = 0; #endif #ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY __attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) { return false; } #endif #ifdef RETRO_TAPPING_PER_KEY __attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) { return false; } #endif #ifndef TAP_CODE_DELAY # define TAP_CODE_DELAY 0 #endif #ifndef TAP_HOLD_CAPS_DELAY # define TAP_HOLD_CAPS_DELAY 80 #endif /** \brief Called to execute an action. * * FIXME: Needs documentation. */ void action_exec(keyevent_t event) { if (!IS_NOEVENT(event)) { dprint("\n---- action_exec: start -----\n"); dprint("EVENT: "); debug_event(event); dprintln(); #if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) retro_tapping_counter++; #endif } if (event.pressed) { // clear the potential weak mods left by previously pressed keys clear_weak_mods(); } #ifdef SWAP_HANDS_ENABLE if (!IS_NOEVENT(event)) { process_hand_swap(&event); } #endif keyrecord_t record = {.event = event}; #ifndef NO_ACTION_ONESHOT # if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) if (has_oneshot_layer_timed_out()) { clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); } if (has_oneshot_mods_timed_out()) { clear_oneshot_mods(); } # ifdef SWAP_HANDS_ENABLE if (has_oneshot_swaphands_timed_out()) { clear_oneshot_swaphands(); } # endif # endif #endif #ifndef NO_ACTION_TAPPING action_tapping_process(record); #else process_record(&record); if (!IS_NOEVENT(record.event)) { dprint("processed: "); debug_record(record); dprintln(); } #endif } #ifdef SWAP_HANDS_ENABLE bool swap_hands = false; bool swap_held = false; /** \brief Process Hand Swap * * FIXME: Needs documentation. */ void process_hand_swap(keyevent_t *event) { static swap_state_row_t swap_state[MATRIX_ROWS]; keypos_t pos = event->key; swap_state_row_t col_bit = (swap_state_row_t)1 << pos.col; bool do_swap = event->pressed ? swap_hands : swap_state[pos.row] & (col_bit); if (do_swap) { event->key = hand_swap_config[pos.row][pos.col]; swap_state[pos.row] |= col_bit; } else { swap_state[pos.row] &= ~(col_bit); } } #endif #if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) bool disable_action_cache = false; void process_record_nocache(keyrecord_t *record) { disable_action_cache = true; process_record(record); disable_action_cache = false; } #else void process_record_nocache(keyrecord_t *record) { process_record(record); } #endif __attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; } __attribute__((weak)) void post_process_record_quantum(keyrecord_t *record) {} #ifndef NO_ACTION_TAPPING /** \brief Allows for handling tap-hold actions immediately instead of waiting for TAPPING_TERM or another keypress. * * FIXME: Needs documentation. */ void process_record_tap_hint(keyrecord_t *record) { action_t action = layer_switch_get_action(record->event.key); switch (action.kind.id) { # ifdef SWAP_HANDS_ENABLE case ACT_SWAP_HANDS: switch (action.swap.code) { case OP_SH_ONESHOT: break; case OP_SH_TAP_TOGGLE: default: swap_hands = !swap_hands; swap_held = true; } break; # endif } } #endif /** \brief Take a key event (key press or key release) and processes it. * * FIXME: Needs documentation. */ void process_record(keyrecord_t *record) { if (IS_NOEVENT(record->event)) { return; } if (!process_record_quantum(record)) { #ifndef NO_ACTION_ONESHOT if (is_oneshot_layer_active() && record->event.pressed) { clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); } #endif return; } process_record_handler(record); post_process_record_quantum(record); } void process_record_handler(keyrecord_t *record) { action_t action = store_or_get_action(record->event.pressed, record->event.key); dprint("ACTION: "); debug_action(action); #ifndef NO_ACTION_LAYER dprint(" layer_state: "); layer_debug(); dprint(" default_layer_state: "); default_layer_debug(); #endif dprintln(); process_action(record, action); } #if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE) void register_button(bool pressed, enum mouse_buttons button) { # ifdef PS2_MOUSE_ENABLE tp_buttons = pressed ? tp_buttons | button : tp_buttons & ~button; # endif # ifdef POINTING_DEVICE_ENABLE report_mouse_t currentReport = pointing_device_get_report(); currentReport.buttons = pressed ? currentReport.buttons | button : currentReport.buttons & ~button; pointing_device_set_report(currentReport); # endif } #endif /** \brief Take an action and processes it. * * FIXME: Needs documentation. */ void process_action(keyrecord_t *record, action_t action) { keyevent_t event = record->event; #ifndef NO_ACTION_TAPPING uint8_t tap_count = record->tap.count; #endif #ifndef NO_ACTION_ONESHOT bool do_release_oneshot = false; // notice we only clear the one shot layer if the pressed key is not a modifier. if (is_oneshot_layer_active() && event.pressed && (action.kind.id == ACT_USAGE || !IS_MOD(action.key.code)) # ifdef SWAP_HANDS_ENABLE && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT) # endif ) { clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); do_release_oneshot = !is_oneshot_layer_active(); } #endif switch (action.kind.id) { /* Key and Mods */ case ACT_LMODS: case ACT_RMODS: { uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods : action.key.mods << 4; if (event.pressed) { if (mods) { if (IS_MOD(action.key.code) || action.key.code == KC_NO) { // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless. // This also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT). // Same applies for some keys like KC_MEH which are declared as MEH(KC_NO). add_mods(mods); } else { add_weak_mods(mods); } send_keyboard_report(); } register_code(action.key.code); } else { unregister_code(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(); } } } break; #ifndef NO_ACTION_TAPPING case ACT_LMODS_TAP: case ACT_RMODS_TAP: { uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods : action.key.mods << 4; switch (action.layer_tap.code) { # ifndef NO_ACTION_ONESHOT case MODS_ONESHOT: // Oneshot modifier if (event.pressed) { if (tap_count == 0) { dprint("MODS_TAP: Oneshot: 0\n"); register_mods(mods | get_oneshot_mods()); } else if (tap_count == 1) { dprint("MODS_TAP: Oneshot: start\n"); set_oneshot_mods(mods | get_oneshot_mods()); # if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 } else if (tap_count == ONESHOT_TAP_TOGGLE) { dprint("MODS_TAP: Toggling oneshot"); clear_oneshot_mods(); set_oneshot_locked_mods(mods); register_mods(mods); # endif } else { register_mods(mods | get_oneshot_mods()); } } else { if (tap_count == 0) { clear_oneshot_mods(); unregister_mods(mods); } else if (tap_count == 1) { // Retain Oneshot mods # if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 if (mods & get_mods()) { clear_oneshot_locked_mods(); clear_oneshot_mods(); unregister_mods(mods); } } else if (tap_count == ONESHOT_TAP_TOGGLE) { // Toggle Oneshot Layer # endif } else { clear_oneshot_mods(); unregister_mods(mods); } } break; # endif case MODS_TAP_TOGGLE: if (event.pressed) { if (tap_count <= TAPPING_TOGGLE) { register_mods(mods); } } else { if (tap_count < TAPPING_TOGGLE) { unregister_mods(mods); } } break; default: if (event.pressed) { if (tap_count > 0) { # if !defined(IGNORE_MOD_TAP_INTERRUPT) || defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY) if ( # ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY !get_ignore_mod_tap_interrupt(get_event_keycode(record->event, false), record) && # endif record->tap.interrupted) { dprint("mods_tap: tap: cancel: add_mods\n"); // ad hoc: set 0 to cancel tap record->tap.count = 0; register_mods(mods); } else # endif { dprint("MODS_TAP: Tap: register_code\n"); register_code(action.key.code); } } else { dprint("MODS_TAP: No tap: add_mods\n"); register_mods(mods); } } else { if (tap_count > 0) { dprint("MODS_TAP: Tap: unregister_code\n"); if (action.layer_tap.code == KC_CAPS) { wait_ms(TAP_HOLD_CAPS_DELAY); } else { wait_ms(TAP_CODE_DELAY); } unregister_code(action.key.code); } else { dprint("MODS_TAP: No tap: add_mods\n"); unregister_mods(mods); } } break; } } break; #endif #ifdef EXTRAKEY_ENABLE /* other HID usage */ case ACT_USAGE: switch (action.usage.page) { case PAGE_SYSTEM: if (event.pressed) { host_system_send(action.usage.code); } else { host_system_send(0); } break; case PAGE_CONSUMER: if (event.pressed) { host_consumer_send(action.usage.code); } else { host_consumer_send(0); } break; } break; #endif #ifdef MOUSEKEY_ENABLE /* Mouse key */ case ACT_MOUSEKEY: if (event.pressed) { mousekey_on(action.key.code); } else { mousekey_off(action.key.code); } switch (action.key.code) { # if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE) # ifdef POINTING_DEVICE_ENABLE case KC_MS_BTN1 ... KC_MS_BTN8: # else case KC_MS_BTN1 ... KC_MS_BTN3: # endif register_button(event.pressed, MOUSE_BTN_MASK(action.key.code - KC_MS_BTN1)); break; # endif default: mousekey_send(); break; } break; #endif #ifndef NO_ACTION_LAYER case ACT_LAYER: if (action.layer_bitop.on == 0) { /* Default Layer Bitwise Operation */ if (!event.pressed) { uint8_t shift = action.layer_bitop.part * 4; layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift; layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0; switch (action.layer_bitop.op) { case OP_BIT_AND: default_layer_and(bits | mask); break; case OP_BIT_OR: default_layer_or(bits | mask); break; case OP_BIT_XOR: default_layer_xor(bits | mask); break; case OP_BIT_SET: default_layer_set(bits | mask); break; } } } else { /* Layer Bitwise Operation */ if (event.pressed ? (action.layer_bitop.on & ON_PRESS) : (action.layer_bitop.on & ON_RELEASE)) { uint8_t shift = action.layer_bitop.part * 4; layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift; layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0; switch (action.layer_bitop.op) { case OP_BIT_AND: layer_and(bits | mask); break; case OP_BIT_OR: layer_or(bits | mask); break; case OP_BIT_XOR: layer_xor(bits | mask); break; case OP_BIT_SET: layer_state_set(bits | mask); break; } } } break; case ACT_LAYER_MODS: if (event.pressed) { layer_on(action.layer_mods.layer); register_mods(action.layer_mods.mods); } else { unregister_mods(action.layer_mods.mods); layer_off(action.layer_mods.layer); } break; # ifndef NO_ACTION_TAPPING case ACT_LAYER_TAP: case ACT_LAYER_TAP_EXT: switch (action.layer_tap.code) { case OP_TAP_TOGGLE: /* tap toggle */ if (event.pressed) { if (tap_count < TAPPING_TOGGLE) { layer_invert(action.layer_tap.val); } } else { if (tap_count <= TAPPING_TOGGLE) { layer_invert(action.layer_tap.val); } } break; case OP_ON_OFF: event.pressed ? layer_on(action.layer_tap.val) : layer_off(action.layer_tap.val); break; case OP_OFF_ON: event.pressed ? layer_off(action.layer_tap.val) : layer_on(action.layer_tap.val); break; case OP_SET_CLEAR: event.pressed ? layer_move(action.layer_tap.val) : layer_clear(); break; # ifndef NO_ACTION_ONESHOT case OP_ONESHOT: // Oneshot modifier # if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 do_release_oneshot = false; if (event.pressed) { del_mods(get_oneshot_locked_mods()); if (get_oneshot_layer_state() == ONESHOT_TOGGLED) { reset_oneshot_layer(); layer_off(action.layer_tap.val); break; } else if (tap_count < ONESHOT_TAP_TOGGLE) { layer_on(action.layer_tap.val); set_oneshot_layer(action.layer_tap.val, ONESHOT_START); } } else { add_mods(get_oneshot_locked_mods()); if (tap_count >= ONESHOT_TAP_TOGGLE) { reset_oneshot_layer(); clear_oneshot_locked_mods(); set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED); } else { clear_oneshot_layer_state(ONESHOT_PRESSED); } } # else if (event.pressed) { layer_on(action.layer_tap.val); set_oneshot_layer(action.layer_tap.val, ONESHOT_START); } else { clear_oneshot_layer_state(ONESHOT_PRESSED); if (tap_count > 1) { clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); } } # endif break; # endif default: /* tap key */ if (event.pressed) { if (tap_count > 0) { dprint("KEYMAP_TAP_KEY: Tap: register_code\n"); register_code(action.layer_tap.code); } else { dprint("KEYMAP_TAP_KEY: No tap: On on press\n"); layer_on(action.layer_tap.val); } } else { if (tap_count > 0) { dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n"); if (action.layer_tap.code == KC_CAPS) { wait_ms(TAP_HOLD_CAPS_DELAY); } else { wait_ms(TAP_CODE_DELAY); } unregister_code(action.layer_tap.code); } else { dprint("KEYMAP_TAP_KEY: No tap: Off on release\n"); layer_off(action.layer_tap.val); } } break; } break; # endif #endif /* Extentions */ #ifndef NO_ACTION_MACRO case ACT_MACRO: action_macro_play(action_get_macro(record, action.func.id, action.func.opt)); break; #endif #ifdef SWAP_HANDS_ENABLE case ACT_SWAP_HANDS: switch (action.swap.code) { case OP_SH_TOGGLE: if (event.pressed) { swap_hands = !swap_hands; } break; case OP_SH_ON_OFF: swap_hands = event.pressed; break; case OP_SH_OFF_ON: swap_hands = !event.pressed; break; case OP_SH_ON: if (!event.pressed) { swap_hands = true; } break; case OP_SH_OFF: if (!event.pressed) { swap_hands = false; } break; # ifndef NO_ACTION_ONESHOT case OP_SH_ONESHOT: if (event.pressed) { set_oneshot_swaphands(); } else { release_oneshot_swaphands(); } break; # endif # ifndef NO_ACTION_TAPPING case OP_SH_TAP_TOGGLE: /* tap toggle */ if (event.pressed) { if (swap_held) { swap_held = false; } else { swap_hands = !swap_hands; } } else { if (tap_count < TAPPING_TOGGLE) { swap_hands = !swap_hands; } } break; default: /* tap key */ if (tap_count > 0) { if (swap_held) { swap_hands = !swap_hands; // undo hold set up in _tap_hint swap_held = false; } if (event.pressed) { register_code(action.swap.code); } else { wait_ms(TAP_CODE_DELAY); unregister_code(action.swap.code); *record = (keyrecord_t){}; // hack: reset tap mode } } else { if (swap_held && !event.pressed) { swap_hands = !swap_hands; // undo hold set up in _tap_hint swap_held = false; } } # endif } #endif #ifndef NO_ACTION_FUNCTION case ACT_FUNCTION: action_function(record, action.func.id, action.func.opt); break; #endif default: break; } #ifndef NO_ACTION_LAYER // if this event is a layer action, update the leds switch (action.kind.id) { case ACT_LAYER: case ACT_LAYER_MODS: # ifndef NO_ACTION_TAPPING case ACT_LAYER_TAP: case ACT_LAYER_TAP_EXT: # endif led_set(host_keyboard_leds()); break; default: break; } #endif #ifndef NO_ACTION_TAPPING # if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY) if (!is_tap_action(action)) { retro_tapping_counter = 0; } else { if (event.pressed) { if (tap_count > 0) { retro_tapping_counter = 0; } } else { if (tap_count > 0) { retro_tapping_counter = 0; } else { if ( # ifdef RETRO_TAPPING_PER_KEY get_retro_tapping(get_event_keycode(record->event, false), record) && # endif retro_tapping_counter == 2) { tap_code(action.layer_tap.code); } retro_tapping_counter = 0; } } } # endif #endif #ifdef SWAP_HANDS_ENABLE # ifndef NO_ACTION_ONESHOT if (event.pressed && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)) { use_oneshot_swaphands(); } # endif #endif #ifndef NO_ACTION_ONESHOT /* Because we switch layers after a oneshot event, we need to release the * key before we leave the layer or no key up event will be generated. */ if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED)) { record->event.pressed = false; layer_on(get_oneshot_layer()); process_record(record); layer_off(get_oneshot_layer()); } #endif } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ void register_code(uint8_t code) { if (code == KC_NO) { return; } #ifdef LOCKING_SUPPORT_ENABLE else if (KC_LOCKING_CAPS == code) { # ifdef LOCKING_RESYNC_ENABLE // Resync: ignore if caps lock already is on if (host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK)) return; # endif add_key(KC_CAPSLOCK); send_keyboard_report(); wait_ms(100); del_key(KC_CAPSLOCK); send_keyboard_report(); } 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(); wait_ms(100); del_key(KC_NUMLOCK); send_keyboard_report(); } 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(); wait_ms(100); del_key(KC_SCROLLLOCK); send_keyboard_report(); } #endif 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 if (oneshot_state.mods && !oneshot_state.disabled) { uint8_t tmp_mods = get_mods(); add_mods(oneshot_state.mods); add_key(code); send_keyboard_report(); set_mods(tmp_mods); send_keyboard_report(); 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)) { del_key(code); send_keyboard_report(); } add_key(code); send_keyboard_report(); } } 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)); } #endif #ifdef MOUSEKEY_ENABLE else if IS_MOUSEKEY(code) { mousekey_on(code); mousekey_send(); } #endif } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ void unregister_code(uint8_t code) { if (code == KC_NO) { return; } #ifdef LOCKING_SUPPORT_ENABLE else if (KC_LOCKING_CAPS == code) { # ifdef LOCKING_RESYNC_ENABLE // Resync: ignore if caps lock already is off if (!(host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK))) return; # endif add_key(KC_CAPSLOCK); send_keyboard_report(); del_key(KC_CAPSLOCK); send_keyboard_report(); } 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(); del_key(KC_NUMLOCK); send_keyboard_report(); } 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(); del_key(KC_SCROLLLOCK); send_keyboard_report(); } #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); } #ifdef MOUSEKEY_ENABLE else if IS_MOUSEKEY(code) { mousekey_off(code); mousekey_send(); } #endif } /** \brief Tap a keycode with a delay. * * \param code The basic keycode to tap. * \param delay The amount of time in milliseconds to leave the keycode registered, before unregistering it. */ void tap_code_delay(uint8_t code, uint16_t delay) { register_code(code); for (uint16_t i = delay; i > 0; i--) { wait_ms(1); } unregister_code(code); } /** \brief Tap a keycode with the default delay. * * \param code The basic keycode to tap. If `code` is `KC_CAPS`, the delay will be `TAP_HOLD_CAPS_DELAY`, otherwise `TAP_CODE_DELAY`, if defined. */ void tap_code(uint8_t code) { tap_code_delay(code, code == KC_CAPS ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY); } /** \brief Adds the given physically pressed modifiers and sends a keyboard report immediately. * * \param mods A bitfield of modifiers to register. */ void register_mods(uint8_t mods) { if (mods) { add_mods(mods); send_keyboard_report(); } } /** \brief Removes the given physically pressed modifiers and sends a keyboard report immediately. * * \param mods A bitfield of modifiers to unregister. */ void unregister_mods(uint8_t mods) { if (mods) { del_mods(mods); send_keyboard_report(); } } /** \brief Adds the given weak modifiers and sends a keyboard report immediately. * * \param mods A bitfield of modifiers to register. */ void register_weak_mods(uint8_t mods) { if (mods) { add_weak_mods(mods); send_keyboard_report(); } } /** \brief Removes the given weak modifiers and sends a keyboard report immediately. * * \param mods A bitfield of modifiers to unregister. */ void unregister_weak_mods(uint8_t mods) { if (mods) { del_weak_mods(mods); send_keyboard_report(); } } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ void clear_keyboard(void) { clear_mods(); clear_keyboard_but_mods(); } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ void clear_keyboard_but_mods(void) { clear_keys(); clear_keyboard_but_mods_and_keys(); } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ void clear_keyboard_but_mods_and_keys() { #ifdef EXTRAKEY_ENABLE host_system_send(0); host_consumer_send(0); #endif clear_weak_mods(); clear_macro_mods(); send_keyboard_report(); #ifdef MOUSEKEY_ENABLE mousekey_clear(); mousekey_send(); #endif } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ bool is_tap_key(keypos_t key) { action_t action = layer_switch_get_action(key); return is_tap_action(action); } /** \brief Utilities for actions. (FIXME: Needs better description) * * FIXME: Needs documentation. */ bool is_tap_action(action_t action) { switch (action.kind.id) { case ACT_LMODS_TAP: case ACT_RMODS_TAP: case ACT_LAYER_TAP: case ACT_LAYER_TAP_EXT: switch (action.layer_tap.code) { case KC_NO ... KC_RGUI: case OP_TAP_TOGGLE: case OP_ONESHOT: return true; } return false; case ACT_SWAP_HANDS: switch (action.swap.code) { case KC_NO ... KC_RGUI: case OP_SH_TAP_TOGGLE: return true; } return false; case ACT_MACRO: case ACT_FUNCTION: if (action.func.opt & FUNC_TAP) { return true; } return false; } return false; } /** \brief Debug print (FIXME: Needs better description) * * FIXME: Needs documentation. */ void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); } /** \brief Debug print (FIXME: Needs better description) * * FIXME: Needs documentation. */ void debug_record(keyrecord_t record) { debug_event(record.event); #ifndef NO_ACTION_TAPPING dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' ')); #endif } /** \brief Debug print (FIXME: Needs better description) * * FIXME: Needs documentation. */ void debug_action(action_t action) { switch (action.kind.id) { case ACT_LMODS: dprint("ACT_LMODS"); break; case ACT_RMODS: dprint("ACT_RMODS"); break; case ACT_LMODS_TAP: dprint("ACT_LMODS_TAP"); break; case ACT_RMODS_TAP: dprint("ACT_RMODS_TAP"); break; case ACT_USAGE: dprint("ACT_USAGE"); break; case ACT_MOUSEKEY: dprint("ACT_MOUSEKEY"); break; case ACT_LAYER: dprint("ACT_LAYER"); break; case ACT_LAYER_MODS: dprint("ACT_LAYER_MODS"); break; case ACT_LAYER_TAP: dprint("ACT_LAYER_TAP"); break; case ACT_LAYER_TAP_EXT: dprint("ACT_LAYER_TAP_EXT"); break; case ACT_MACRO: dprint("ACT_MACRO"); break; case ACT_FUNCTION: dprint("ACT_FUNCTION"); break; case ACT_SWAP_HANDS: dprint("ACT_SWAP_HANDS"); break; default: dprint("UNKNOWN"); break; } dprintf("[%X:%02X]", action.kind.param >> 8, action.kind.param & 0xff); }
新たな include がいくつかある
- mousekey.h
- command.h
- action_layer.h
- action_tapping.h
- action_util.h
順番に見ていこう
mousekey.h
ソース全体
/* Copyright 2011 Jun Wako <wakojun@gmail.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/>. */ #pragma once #include <stdint.h> #include "host.h" #ifndef MK_3_SPEED /* max value on report descriptor */ # ifndef MOUSEKEY_MOVE_MAX # define MOUSEKEY_MOVE_MAX 127 # elif MOUSEKEY_MOVE_MAX > 127 # error MOUSEKEY_MOVE_MAX needs to be smaller than 127 # endif # ifndef MOUSEKEY_WHEEL_MAX # define MOUSEKEY_WHEEL_MAX 127 # elif MOUSEKEY_WHEEL_MAX > 127 # error MOUSEKEY_WHEEL_MAX needs to be smaller than 127 # endif # ifndef MOUSEKEY_MOVE_DELTA # ifndef MK_KINETIC_SPEED # define MOUSEKEY_MOVE_DELTA 5 # else # define MOUSEKEY_MOVE_DELTA 25 # endif # endif # ifndef MOUSEKEY_WHEEL_DELTA # define MOUSEKEY_WHEEL_DELTA 1 # endif # ifndef MOUSEKEY_DELAY # ifndef MK_KINETIC_SPEED # define MOUSEKEY_DELAY 300 # else # define MOUSEKEY_DELAY 8 # endif # endif # ifndef MOUSEKEY_INTERVAL # ifndef MK_KINETIC_SPEED # define MOUSEKEY_INTERVAL 50 # else # define MOUSEKEY_INTERVAL 8 # endif # endif # ifndef MOUSEKEY_MAX_SPEED # define MOUSEKEY_MAX_SPEED 10 # endif # ifndef MOUSEKEY_TIME_TO_MAX # define MOUSEKEY_TIME_TO_MAX 20 # endif # ifndef MOUSEKEY_WHEEL_DELAY # define MOUSEKEY_WHEEL_DELAY 300 # endif # ifndef MOUSEKEY_WHEEL_INTERVAL # define MOUSEKEY_WHEEL_INTERVAL 100 # endif # ifndef MOUSEKEY_WHEEL_MAX_SPEED # define MOUSEKEY_WHEEL_MAX_SPEED 8 # endif # ifndef MOUSEKEY_WHEEL_TIME_TO_MAX # define MOUSEKEY_WHEEL_TIME_TO_MAX 40 # endif # ifndef MOUSEKEY_INITIAL_SPEED # define MOUSEKEY_INITIAL_SPEED 100 # endif # ifndef MOUSEKEY_BASE_SPEED # define MOUSEKEY_BASE_SPEED 1000 # endif # ifndef MOUSEKEY_DECELERATED_SPEED # define MOUSEKEY_DECELERATED_SPEED 400 # endif # ifndef MOUSEKEY_ACCELERATED_SPEED # define MOUSEKEY_ACCELERATED_SPEED 3000 # endif # ifndef MOUSEKEY_WHEEL_INITIAL_MOVEMENTS # define MOUSEKEY_WHEEL_INITIAL_MOVEMENTS 16 # endif # ifndef MOUSEKEY_WHEEL_BASE_MOVEMENTS # define MOUSEKEY_WHEEL_BASE_MOVEMENTS 32 # endif # ifndef MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS # define MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS 48 # endif # ifndef MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS # define MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS 8 # endif #else /* #ifndef MK_3_SPEED */ # ifndef MK_C_OFFSET_UNMOD # define MK_C_OFFSET_UNMOD 16 # endif # ifndef MK_C_INTERVAL_UNMOD # define MK_C_INTERVAL_UNMOD 16 # endif # ifndef MK_C_OFFSET_0 # define MK_C_OFFSET_0 1 # endif # ifndef MK_C_INTERVAL_0 # define MK_C_INTERVAL_0 32 # endif # ifndef MK_C_OFFSET_1 # define MK_C_OFFSET_1 4 # endif # ifndef MK_C_INTERVAL_1 # define MK_C_INTERVAL_1 16 # endif # ifndef MK_C_OFFSET_2 # define MK_C_OFFSET_2 32 # endif # ifndef MK_C_INTERVAL_2 # define MK_C_INTERVAL_2 16 # endif # ifndef MK_W_OFFSET_UNMOD # define MK_W_OFFSET_UNMOD 1 # endif # ifndef MK_W_INTERVAL_UNMOD # define MK_W_INTERVAL_UNMOD 40 # endif # ifndef MK_W_OFFSET_0 # define MK_W_OFFSET_0 1 # endif # ifndef MK_W_INTERVAL_0 # define MK_W_INTERVAL_0 360 # endif # ifndef MK_W_OFFSET_1 # define MK_W_OFFSET_1 1 # endif # ifndef MK_W_INTERVAL_1 # define MK_W_INTERVAL_1 120 # endif # ifndef MK_W_OFFSET_2 # define MK_W_OFFSET_2 1 # endif # ifndef MK_W_INTERVAL_2 # define MK_W_INTERVAL_2 20 # endif #endif /* #ifndef MK_3_SPEED */ #ifdef __cplusplus extern "C" { #endif extern uint8_t mk_delay; extern uint8_t mk_interval; extern uint8_t mk_max_speed; extern uint8_t mk_time_to_max; extern uint8_t mk_wheel_max_speed; extern uint8_t mk_wheel_time_to_max; void mousekey_task(void); void mousekey_on(uint8_t code); void mousekey_off(uint8_t code); void mousekey_clear(void); void mousekey_send(void); #ifdef __cplusplus } #endif
~158行
マウスに関する設定の初期化処理である
各設定にの意味などはここが詳しい
~最終行
あとは関数のプロトタイプ宣言である
mousekey.c
ソース全体
/* * Copyright 2011 Jun Wako <wakojun@gmail.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 <stdint.h> #include "keycode.h" #include "host.h" #include "timer.h" #include "print.h" #include "debug.h" #include "mousekey.h" inline int8_t times_inv_sqrt2(int8_t x) { // 181/256 is pretty close to 1/sqrt(2) // 0.70703125 0.707106781 // 1 too small for x=99 and x=198 // This ends up being a mult and discard lower 8 bits return (x * 181) >> 8; } static report_mouse_t mouse_report = {0}; static void mousekey_debug(void); static uint8_t mousekey_accel = 0; static uint8_t mousekey_repeat = 0; static uint8_t mousekey_wheel_repeat = 0; #ifdef MK_KINETIC_SPEED static uint16_t mouse_timer = 0; #endif #ifndef MK_3_SPEED static uint16_t last_timer_c = 0; static uint16_t last_timer_w = 0; /* * Mouse keys acceleration algorithm * http://en.wikipedia.org/wiki/Mouse_keys * * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000) */ /* milliseconds between the initial key press and first repeated motion event (0-2550) */ uint8_t mk_delay = MOUSEKEY_DELAY / 10; /* milliseconds between repeated motion events (0-255) */ uint8_t mk_interval = MOUSEKEY_INTERVAL; /* steady speed (in action_delta units) applied each event (0-255) */ uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED; /* number of events (count) accelerating to steady speed (0-255) */ uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX; /* ramp used to reach maximum pointer speed (NOT SUPPORTED) */ // int8_t mk_curve = 0; /* wheel params */ /* milliseconds between the initial key press and first repeated motion event (0-2550) */ uint8_t mk_wheel_delay = MOUSEKEY_WHEEL_DELAY / 10; /* milliseconds between repeated motion events (0-255) */ uint8_t mk_wheel_interval = MOUSEKEY_WHEEL_INTERVAL; uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; # ifndef MK_COMBINED static uint8_t move_unit(void) { uint16_t unit; if (mousekey_accel & (1 << 0)) { unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 4; } else if (mousekey_accel & (1 << 1)) { unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2; } else if (mousekey_accel & (1 << 2)) { unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed); } else if (mousekey_repeat == 0) { unit = MOUSEKEY_MOVE_DELTA; } else if (mousekey_repeat >= mk_time_to_max) { unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; } else { unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; } return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); } static uint8_t wheel_unit(void) { uint16_t unit; if (mousekey_accel & (1 << 0)) { unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 4; } else if (mousekey_accel & (1 << 1)) { unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2; } else if (mousekey_accel & (1 << 2)) { unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed); } else if (mousekey_wheel_repeat == 0) { unit = MOUSEKEY_WHEEL_DELTA; } else if (mousekey_wheel_repeat >= mk_wheel_time_to_max) { unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; } else { unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_wheel_repeat) / mk_wheel_time_to_max; } return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); } # else /* #ifndef MK_COMBINED */ # ifdef MK_KINETIC_SPEED /* * Kinetic movement acceleration algorithm * * current speed = I + A * T/50 + A * 0.5 * T^2 | maximum B * * T: time since the mouse movement started * E: mouse events per second (set through MOUSEKEY_INTERVAL, UHK sends 250, the * pro micro on my Signum 3.0 sends only 125!) * I: initial speed at time 0 * A: acceleration * B: base mouse travel speed */ const uint16_t mk_accelerated_speed = MOUSEKEY_ACCELERATED_SPEED; const uint16_t mk_base_speed = MOUSEKEY_BASE_SPEED; const uint16_t mk_decelerated_speed = MOUSEKEY_DECELERATED_SPEED; const uint16_t mk_initial_speed = MOUSEKEY_INITIAL_SPEED; static uint8_t move_unit(void) { float speed = mk_initial_speed; if (mousekey_accel & ((1 << 0) | (1 << 2))) { speed = mousekey_accel & (1 << 2) ? mk_accelerated_speed : mk_decelerated_speed; } else if (mousekey_repeat && mouse_timer) { const float time_elapsed = timer_elapsed(mouse_timer) / 50; speed = mk_initial_speed + MOUSEKEY_MOVE_DELTA * time_elapsed + MOUSEKEY_MOVE_DELTA * 0.5 * time_elapsed * time_elapsed; speed = speed > mk_base_speed ? mk_base_speed : speed; } /* convert speed to USB mouse speed 1 to 127 */ speed = (uint8_t)(speed / (1000.0f / mk_interval)); speed = speed < 1 ? 1 : speed; return speed > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : speed; } float mk_wheel_interval = 1000.0f / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; static uint8_t wheel_unit(void) { float speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; if (mousekey_accel & ((1 << 0) | (1 << 2))) { speed = mousekey_accel & (1 << 2) ? MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS : MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS; } else if (mousekey_repeat && mouse_timer) { if (mk_wheel_interval != MOUSEKEY_WHEEL_BASE_MOVEMENTS) { const float time_elapsed = timer_elapsed(mouse_timer) / 50; speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS + 1 * time_elapsed + 1 * 0.5 * time_elapsed * time_elapsed; } speed = speed > MOUSEKEY_WHEEL_BASE_MOVEMENTS ? MOUSEKEY_WHEEL_BASE_MOVEMENTS : speed; } mk_wheel_interval = 1000.0f / speed; return 1; } # else /* #ifndef MK_KINETIC_SPEED */ static uint8_t move_unit(void) { uint16_t unit; if (mousekey_accel & (1 << 0)) { unit = 1; } else if (mousekey_accel & (1 << 1)) { unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2; } else if (mousekey_accel & (1 << 2)) { unit = MOUSEKEY_MOVE_MAX; } else if (mousekey_repeat == 0) { unit = MOUSEKEY_MOVE_DELTA; } else if (mousekey_repeat >= mk_time_to_max) { unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; } else { unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; } return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); } static uint8_t wheel_unit(void) { uint16_t unit; if (mousekey_accel & (1 << 0)) { unit = 1; } else if (mousekey_accel & (1 << 1)) { unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2; } else if (mousekey_accel & (1 << 2)) { unit = MOUSEKEY_WHEEL_MAX; } else if (mousekey_repeat == 0) { unit = MOUSEKEY_WHEEL_DELTA; } else if (mousekey_repeat >= mk_wheel_time_to_max) { unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; } else { unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max; } return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); } # endif /* #ifndef MK_KINETIC_SPEED */ # endif /* #ifndef MK_COMBINED */ void mousekey_task(void) { // report cursor and scroll movement independently report_mouse_t const tmpmr = mouse_report; mouse_report.x = 0; mouse_report.y = 0; mouse_report.v = 0; mouse_report.h = 0; if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > (mousekey_repeat ? mk_interval : mk_delay * 10)) { if (mousekey_repeat != UINT8_MAX) mousekey_repeat++; if (tmpmr.x != 0) mouse_report.x = move_unit() * ((tmpmr.x > 0) ? 1 : -1); if (tmpmr.y != 0) mouse_report.y = move_unit() * ((tmpmr.y > 0) ? 1 : -1); /* diagonal move [1/sqrt(2)] */ if (mouse_report.x && mouse_report.y) { mouse_report.x = times_inv_sqrt2(mouse_report.x); if (mouse_report.x == 0) { mouse_report.x = 1; } mouse_report.y = times_inv_sqrt2(mouse_report.y); if (mouse_report.y == 0) { mouse_report.y = 1; } } } if ((tmpmr.v || tmpmr.h) && timer_elapsed(last_timer_w) > (mousekey_wheel_repeat ? mk_wheel_interval : mk_wheel_delay * 10)) { if (mousekey_wheel_repeat != UINT8_MAX) mousekey_wheel_repeat++; if (tmpmr.v != 0) mouse_report.v = wheel_unit() * ((tmpmr.v > 0) ? 1 : -1); if (tmpmr.h != 0) mouse_report.h = wheel_unit() * ((tmpmr.h > 0) ? 1 : -1); /* diagonal move [1/sqrt(2)] */ if (mouse_report.v && mouse_report.h) { mouse_report.v = times_inv_sqrt2(mouse_report.v); if (mouse_report.v == 0) { mouse_report.v = 1; } mouse_report.h = times_inv_sqrt2(mouse_report.h); if (mouse_report.h == 0) { mouse_report.h = 1; } } } if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send(); mouse_report = tmpmr; } void mousekey_on(uint8_t code) { # ifdef MK_KINETIC_SPEED if (mouse_timer == 0) { mouse_timer = timer_read(); } # endif /* #ifdef MK_KINETIC_SPEED */ if (code == KC_MS_UP) mouse_report.y = move_unit() * -1; else if (code == KC_MS_DOWN) mouse_report.y = move_unit(); else if (code == KC_MS_LEFT) mouse_report.x = move_unit() * -1; else if (code == KC_MS_RIGHT) mouse_report.x = move_unit(); else if (code == KC_MS_WH_UP) mouse_report.v = wheel_unit(); else if (code == KC_MS_WH_DOWN) mouse_report.v = wheel_unit() * -1; else if (code == KC_MS_WH_LEFT) mouse_report.h = wheel_unit() * -1; else if (code == KC_MS_WH_RIGHT) mouse_report.h = wheel_unit(); else if (IS_MOUSEKEY_BUTTON(code)) mouse_report.buttons |= 1 << (code - KC_MS_BTN1); else if (code == KC_MS_ACCEL0) mousekey_accel |= (1 << 0); else if (code == KC_MS_ACCEL1) mousekey_accel |= (1 << 1); else if (code == KC_MS_ACCEL2) mousekey_accel |= (1 << 2); } void mousekey_off(uint8_t code) { if (code == KC_MS_UP && mouse_report.y < 0) mouse_report.y = 0; else if (code == KC_MS_DOWN && mouse_report.y > 0) mouse_report.y = 0; else if (code == KC_MS_LEFT && mouse_report.x < 0) mouse_report.x = 0; else if (code == KC_MS_RIGHT && mouse_report.x > 0) mouse_report.x = 0; else if (code == KC_MS_WH_UP && mouse_report.v > 0) mouse_report.v = 0; else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) mouse_report.v = 0; else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) mouse_report.h = 0; else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) mouse_report.h = 0; else if (IS_MOUSEKEY_BUTTON(code)) mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1)); else if (code == KC_MS_ACCEL0) mousekey_accel &= ~(1 << 0); else if (code == KC_MS_ACCEL1) mousekey_accel &= ~(1 << 1); else if (code == KC_MS_ACCEL2) mousekey_accel &= ~(1 << 2); if (mouse_report.x == 0 && mouse_report.y == 0) { mousekey_repeat = 0; # ifdef MK_KINETIC_SPEED mouse_timer = 0; # endif /* #ifdef MK_KINETIC_SPEED */ } if (mouse_report.v == 0 && mouse_report.h == 0) mousekey_wheel_repeat = 0; } #else /* #ifndef MK_3_SPEED */ enum { mkspd_unmod, mkspd_0, mkspd_1, mkspd_2, mkspd_COUNT }; # ifndef MK_MOMENTARY_ACCEL static uint8_t mk_speed = mkspd_1; # else static uint8_t mk_speed = mkspd_unmod; static uint8_t mkspd_DEFAULT = mkspd_unmod; # endif static uint16_t last_timer_c = 0; static uint16_t last_timer_w = 0; uint16_t c_offsets[mkspd_COUNT] = {MK_C_OFFSET_UNMOD, MK_C_OFFSET_0, MK_C_OFFSET_1, MK_C_OFFSET_2}; uint16_t c_intervals[mkspd_COUNT] = {MK_C_INTERVAL_UNMOD, MK_C_INTERVAL_0, MK_C_INTERVAL_1, MK_C_INTERVAL_2}; uint16_t w_offsets[mkspd_COUNT] = {MK_W_OFFSET_UNMOD, MK_W_OFFSET_0, MK_W_OFFSET_1, MK_W_OFFSET_2}; uint16_t w_intervals[mkspd_COUNT] = {MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0, MK_W_INTERVAL_1, MK_W_INTERVAL_2}; void mousekey_task(void) { // report cursor and scroll movement independently report_mouse_t const tmpmr = mouse_report; mouse_report.x = 0; mouse_report.y = 0; mouse_report.v = 0; mouse_report.h = 0; if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) { mouse_report.x = tmpmr.x; mouse_report.y = tmpmr.y; } if ((tmpmr.h || tmpmr.v) && timer_elapsed(last_timer_w) > w_intervals[mk_speed]) { mouse_report.v = tmpmr.v; mouse_report.h = tmpmr.h; } if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send(); mouse_report = tmpmr; } void adjust_speed(void) { uint16_t const c_offset = c_offsets[mk_speed]; uint16_t const w_offset = w_offsets[mk_speed]; if (mouse_report.x > 0) mouse_report.x = c_offset; if (mouse_report.x < 0) mouse_report.x = c_offset * -1; if (mouse_report.y > 0) mouse_report.y = c_offset; if (mouse_report.y < 0) mouse_report.y = c_offset * -1; if (mouse_report.h > 0) mouse_report.h = w_offset; if (mouse_report.h < 0) mouse_report.h = w_offset * -1; if (mouse_report.v > 0) mouse_report.v = w_offset; if (mouse_report.v < 0) mouse_report.v = w_offset * -1; // adjust for diagonals if (mouse_report.x && mouse_report.y) { mouse_report.x = times_inv_sqrt2(mouse_report.x); if (mouse_report.x == 0) { mouse_report.x = 1; } mouse_report.y = times_inv_sqrt2(mouse_report.y); if (mouse_report.y == 0) { mouse_report.y = 1; } } if (mouse_report.h && mouse_report.v) { mouse_report.h = times_inv_sqrt2(mouse_report.h); mouse_report.v = times_inv_sqrt2(mouse_report.v); } } void mousekey_on(uint8_t code) { uint16_t const c_offset = c_offsets[mk_speed]; uint16_t const w_offset = w_offsets[mk_speed]; uint8_t const old_speed = mk_speed; if (code == KC_MS_UP) mouse_report.y = c_offset * -1; else if (code == KC_MS_DOWN) mouse_report.y = c_offset; else if (code == KC_MS_LEFT) mouse_report.x = c_offset * -1; else if (code == KC_MS_RIGHT) mouse_report.x = c_offset; else if (code == KC_MS_WH_UP) mouse_report.v = w_offset; else if (code == KC_MS_WH_DOWN) mouse_report.v = w_offset * -1; else if (code == KC_MS_WH_LEFT) mouse_report.h = w_offset * -1; else if (code == KC_MS_WH_RIGHT) mouse_report.h = w_offset; else if (IS_MOUSEKEY_BUTTON(code)) mouse_report.buttons |= 1 << (code - KC_MS_BTN1); else if (code == KC_MS_ACCEL0) mk_speed = mkspd_0; else if (code == KC_MS_ACCEL1) mk_speed = mkspd_1; else if (code == KC_MS_ACCEL2) mk_speed = mkspd_2; if (mk_speed != old_speed) adjust_speed(); } void mousekey_off(uint8_t code) { # ifdef MK_MOMENTARY_ACCEL uint8_t const old_speed = mk_speed; # endif if (code == KC_MS_UP && mouse_report.y < 0) mouse_report.y = 0; else if (code == KC_MS_DOWN && mouse_report.y > 0) mouse_report.y = 0; else if (code == KC_MS_LEFT && mouse_report.x < 0) mouse_report.x = 0; else if (code == KC_MS_RIGHT && mouse_report.x > 0) mouse_report.x = 0; else if (code == KC_MS_WH_UP && mouse_report.v > 0) mouse_report.v = 0; else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) mouse_report.v = 0; else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) mouse_report.h = 0; else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) mouse_report.h = 0; else if (IS_MOUSEKEY_BUTTON(code)) mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1)); # ifdef MK_MOMENTARY_ACCEL else if (code == KC_MS_ACCEL0) mk_speed = mkspd_DEFAULT; else if (code == KC_MS_ACCEL1) mk_speed = mkspd_DEFAULT; else if (code == KC_MS_ACCEL2) mk_speed = mkspd_DEFAULT; if (mk_speed != old_speed) adjust_speed(); # endif } #endif /* #ifndef MK_3_SPEED */ void mousekey_send(void) { mousekey_debug(); uint16_t time = timer_read(); if (mouse_report.x || mouse_report.y) last_timer_c = time; if (mouse_report.v || mouse_report.h) last_timer_w = time; host_mouse_send(&mouse_report); } void mousekey_clear(void) { mouse_report = (report_mouse_t){}; mousekey_repeat = 0; mousekey_wheel_repeat = 0; mousekey_accel = 0; } static void mousekey_debug(void) { if (!debug_mouse) return; print("mousekey [btn|x y v h](rep/acl): ["); print_hex8(mouse_report.buttons); print("|"); print_decs(mouse_report.x); print(" "); print_decs(mouse_report.y); print(" "); print_decs(mouse_report.v); print(" "); print_decs(mouse_report.h); print("]("); print_dec(mousekey_repeat); print("/"); print_dec(mousekey_accel); print(")\n"); }
~24行
include 宣言である
いくつか初めてのものがある
- timer.h
- print.h
~32行
計算を簡便にするための関数が定義されている
int8_t times_inv_sqrt2(int8_t x)
と が近似であることから、 x
に 181 をかけ、 8bit 右シフトする(256で割る)ことで を実現している
math.h
を include する必要もなく、単純に (int8_t)(x * sqrt(2))
を行うよりも高速だろう
~70行
定数や変数の宣言である
~最終行
残りはマウスポインタの移動量の計算などである
加速度や、定速モードに切り替えたときの移動量の計算などが記述されている
特に詳しくは見る必要もないだろう
マウスキーについてはここが詳しい
timer.h
ソース全体
/* Copyright 2011 Jun Wako <wakojun@gmail.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/>. */ #pragma once #include <stdint.h> #include <stdbool.h> #if defined(__AVR__) # include "avr/timer_avr.h" #endif #define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a))))) #define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX) #define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX) #define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX) #define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b) #ifdef __cplusplus extern "C" { #endif extern volatile uint32_t timer_count; void timer_init(void); void timer_clear(void); uint16_t timer_read(void); uint32_t timer_read32(void); uint16_t timer_elapsed(uint16_t last); uint32_t timer_elapsed32(uint32_t last); // Utility functions to check if a future time has expired & autmatically handle time wrapping if checked / reset frequently (half of max value) #define timer_expired(current, future) ((uint16_t)(current - future) < UINT16_MAX / 2) #define timer_expired32(current, future) ((uint32_t)(current - future) < UINT32_MAX / 2) #ifdef __cplusplus } #endif
タイマーを使うための関数のプロトタイプ宣言である
各 CPU などに合わせて関数がそれぞれ実装されている
ARM
AVR
ChibiOS
print.h
ソース全体
/* Copyright 2012 Jun Wako <wakojun@gmail.com> */ /* Very basic print functions, intended to be used with usb_debug_only.c * http://www.pjrc.com/teensy/ * Copyright (c) 2008 PJRC.COM, LLC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #pragma once #include <stdint.h> #include <stdbool.h> #include "util.h" #include "sendchar.h" #include "progmem.h" void print_set_sendchar(sendchar_func_t func); #ifndef NO_PRINT # if __has_include_next("_print.h") # include_next "_print.h" /* Include the platforms print.h */ # else // Fall back to lib/printf # include "printf.h" // lib/printf/printf.h // Create user & normal print defines # define print(s) printf(s) # define println(s) printf(s "\r\n") # define xprintf printf # define uprint(s) printf(s) # define uprintln(s) printf(s "\r\n") # define uprintf printf # endif /* __AVR__ / PROTOCOL_CHIBIOS / PROTOCOL_ARM_ATSAM */ #else /* NO_PRINT */ # undef xprintf // Remove print defines # define print(s) # define println(s) # define xprintf(fmt, ...) # define uprintf(fmt, ...) # define uprint(s) # define uprintln(s) #endif /* NO_PRINT */ #ifdef USER_PRINT // Remove normal print defines # undef print # undef println # undef xprintf # define print(s) # define println(s) # define xprintf(fmt, ...) #endif #define print_dec(i) xprintf("%u", i) #define print_decs(i) xprintf("%d", i) /* hex */ #define print_hex4(i) xprintf("%X", i) #define print_hex8(i) xprintf("%02X", i) #define print_hex16(i) xprintf("%04X", i) #define print_hex32(i) xprintf("%08lX", i) /* binary */ #define print_bin4(i) xprintf("%04b", i) #define print_bin8(i) xprintf("%08b", i) #define print_bin16(i) xprintf("%016b", i) #define print_bin32(i) xprintf("%032lb", i) #define print_bin_reverse8(i) xprintf("%08b", bitrev(i)) #define print_bin_reverse16(i) xprintf("%016b", bitrev16(i)) #define print_bin_reverse32(i) xprintf("%032lb", bitrev32(i)) /* print value utility */ #define print_val_dec(v) xprintf(#v ": %u\n", v) #define print_val_decs(v) xprintf(#v ": %d\n", v) #define print_val_hex8(v) xprintf(#v ": %X\n", v) #define print_val_hex16(v) xprintf(#v ": %02X\n", v) #define print_val_hex32(v) xprintf(#v ": %04lX\n", v) #define print_val_bin8(v) xprintf(#v ": %08b\n", v) #define print_val_bin16(v) xprintf(#v ": %016b\n", v) #define print_val_bin32(v) xprintf(#v ": %032lb\n", v) #define print_val_bin_reverse8(v) xprintf(#v ": %08b\n", bitrev(v)) #define print_val_bin_reverse16(v) xprintf(#v ": %016b\n", bitrev16(v)) #define print_val_bin_reverse32(v) xprintf(#v ": %032lb\n", bitrev32(v)) // User print disables the normal print messages in the body of QMK/TMK code and // is meant as a lightweight alternative to NOPRINT. Use it when you only want to do // a spot of debugging but lack flash resources for allowing all of the codebase to // print (and store their wasteful strings). // // !!! DO NOT USE USER PRINT CALLS IN THE BODY OF QMK/TMK !!! /* decimal */ #define uprint_dec(i) uprintf("%u", i) #define uprint_decs(i) uprintf("%d", i) /* hex */ #define uprint_hex4(i) uprintf("%X", i) #define uprint_hex8(i) uprintf("%02X", i) #define uprint_hex16(i) uprintf("%04X", i) #define uprint_hex32(i) uprintf("%08lX", i) /* binary */ #define uprint_bin4(i) uprintf("%04b", i) #define uprint_bin8(i) uprintf("%08b", i) #define uprint_bin16(i) uprintf("%016b", i) #define uprint_bin32(i) uprintf("%032lb", i) #define uprint_bin_reverse8(i) uprintf("%08b", bitrev(i)) #define uprint_bin_reverse16(i) uprintf("%016b", bitrev16(i)) #define uprint_bin_reverse32(i) uprintf("%032lb", bitrev32(i)) /* print value utility */ #define uprint_val_dec(v) uprintf(#v ": %u\n", v) #define uprint_val_decs(v) uprintf(#v ": %d\n", v) #define uprint_val_hex8(v) uprintf(#v ": %X\n", v) #define uprint_val_hex16(v) uprintf(#v ": %02X\n", v) #define uprint_val_hex32(v) uprintf(#v ": %04lX\n", v) #define uprint_val_bin8(v) uprintf(#v ": %08b\n", v) #define uprint_val_bin16(v) uprintf(#v ": %016b\n", v) #define uprint_val_bin32(v) uprintf(#v ": %032lb\n", v) #define uprint_val_bin_reverse8(v) uprintf(#v ": %08b\n", bitrev(v)) #define uprint_val_bin_reverse16(v) uprintf(#v ": %016b\n", bitrev16(v)) #define uprint_val_bin_reverse32(v) uprintf(#v ": %032lb\n", bitrev32(v))
一般的に使われそうな print 系の関数が定義されている
command.h
ソース全体
/* Copyright 2011 Jun Wako <wakojun@gmail.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/>. */ #pragma once /* FIXME: Add doxygen comments for the behavioral defines in here. */ /* TODO: Refactoring */ typedef enum { ONESHOT, CONSOLE, MOUSEKEY } command_state_t; extern command_state_t command_state; /* This allows to extend commands. Return false when command is not processed. */ bool command_extra(uint8_t code); bool command_console_extra(uint8_t code); #ifdef COMMAND_ENABLE uint8_t numkey2num(uint8_t code); bool command_proc(uint8_t code); #else # define command_proc(code) false #endif #ifndef IS_COMMAND # define IS_COMMAND() (get_mods() == MOD_MASK_SHIFT) #endif #ifndef MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS # define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true #endif #ifndef MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS # define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true #endif #ifndef MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM # define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false #endif #ifndef MAGIC_KEY_HELP # define MAGIC_KEY_HELP H #endif #ifndef MAGIC_KEY_HELP_ALT # define MAGIC_KEY_HELP_ALT SLASH #endif #ifndef MAGIC_KEY_DEBUG # define MAGIC_KEY_DEBUG D #endif #ifndef MAGIC_KEY_DEBUG_MATRIX # define MAGIC_KEY_DEBUG_MATRIX X #endif #ifndef MAGIC_KEY_DEBUG_KBD # define MAGIC_KEY_DEBUG_KBD K #endif #ifndef MAGIC_KEY_DEBUG_MOUSE # define MAGIC_KEY_DEBUG_MOUSE M #endif #ifndef MAGIC_KEY_VERSION # define MAGIC_KEY_VERSION V #endif #ifndef MAGIC_KEY_STATUS # define MAGIC_KEY_STATUS S #endif #ifndef MAGIC_KEY_CONSOLE # define MAGIC_KEY_CONSOLE C #endif #ifndef MAGIC_KEY_LAYER0 # define MAGIC_KEY_LAYER0 0 #endif #ifndef MAGIC_KEY_LAYER0_ALT # define MAGIC_KEY_LAYER0_ALT GRAVE #endif #ifndef MAGIC_KEY_LAYER1 # define MAGIC_KEY_LAYER1 1 #endif #ifndef MAGIC_KEY_LAYER2 # define MAGIC_KEY_LAYER2 2 #endif #ifndef MAGIC_KEY_LAYER3 # define MAGIC_KEY_LAYER3 3 #endif #ifndef MAGIC_KEY_LAYER4 # define MAGIC_KEY_LAYER4 4 #endif #ifndef MAGIC_KEY_LAYER5 # define MAGIC_KEY_LAYER5 5 #endif #ifndef MAGIC_KEY_LAYER6 # define MAGIC_KEY_LAYER6 6 #endif #ifndef MAGIC_KEY_LAYER7 # define MAGIC_KEY_LAYER7 7 #endif #ifndef MAGIC_KEY_LAYER8 # define MAGIC_KEY_LAYER8 8 #endif #ifndef MAGIC_KEY_LAYER9 # define MAGIC_KEY_LAYER9 9 #endif #ifndef MAGIC_KEY_BOOTLOADER # define MAGIC_KEY_BOOTLOADER B #endif #ifndef MAGIC_KEY_BOOTLOADER_ALT # define MAGIC_KEY_BOOTLOADER_ALT ESC #endif #ifndef MAGIC_KEY_LOCK # define MAGIC_KEY_LOCK CAPS #endif #ifndef MAGIC_KEY_EEPROM # define MAGIC_KEY_EEPROM E #endif #ifndef MAGIC_KEY_EEPROM_CLEAR # define MAGIC_KEY_EEPROM_CLEAR BSPACE #endif #ifndef MAGIC_KEY_NKRO # define MAGIC_KEY_NKRO N #endif #ifndef MAGIC_KEY_SLEEP_LED # define MAGIC_KEY_SLEEP_LED Z #endif #define XMAGIC_KC(key) KC_##key #define MAGIC_KC(key) XMAGIC_KC(key)
コマンドで使用する定数の初期化を行っている
command.c
ソース全体
/* Copyright 2011 Jun Wako <wakojun@gmail.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 <stdint.h> #include <stdbool.h> #include "wait.h" #include "keycode.h" #include "host.h" #include "keymap.h" #include "print.h" #include "debug.h" #include "util.h" #include "timer.h" #include "keyboard.h" #include "bootloader.h" #include "action_layer.h" #include "action_util.h" #include "eeconfig.h" #include "sleep_led.h" #include "led.h" #include "command.h" #include "quantum.h" #include "version.h" #ifdef BACKLIGHT_ENABLE # include "backlight.h" #endif #if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED) # include "mousekey.h" #endif #ifdef AUDIO_ENABLE # include "audio.h" #endif /* AUDIO_ENABLE */ static bool command_common(uint8_t code); static void command_common_help(void); static void print_version(void); static void print_status(void); static bool command_console(uint8_t code); static void command_console_help(void); #if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED) static bool mousekey_console(uint8_t code); static void mousekey_console_help(void); #endif static void switch_default_layer(uint8_t layer); command_state_t command_state = ONESHOT; bool command_proc(uint8_t code) { switch (command_state) { case ONESHOT: if (!IS_COMMAND()) return false; return (command_extra(code) || command_common(code)); break; case CONSOLE: if (IS_COMMAND()) return (command_extra(code) || command_common(code)); else return (command_console_extra(code) || command_console(code)); break; #if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED) case MOUSEKEY: mousekey_console(code); break; #endif default: command_state = ONESHOT; return false; } return true; } /* TODO: Refactoring is needed. */ /* This allows to define extra commands. return false when not processed. */ bool command_extra(uint8_t code) __attribute__((weak)); bool command_extra(uint8_t code) { (void)code; return false; } bool command_console_extra(uint8_t code) __attribute__((weak)); bool command_console_extra(uint8_t code) { (void)code; return false; } /*********************************************************** * Command common ***********************************************************/ static void command_common_help(void) { print("\n\t- Magic -\n" STR(MAGIC_KEY_DEBUG) ": Debug Message Toggle\n" STR(MAGIC_KEY_DEBUG_MATRIX) ": Matrix Debug Mode Toggle - Show keypresses in matrix grid\n" STR(MAGIC_KEY_DEBUG_KBD) ": Keyboard Debug Toggle - Show keypress report\n" STR(MAGIC_KEY_DEBUG_MOUSE) ": Debug Mouse Toggle\n" STR(MAGIC_KEY_VERSION) ": Version\n" STR(MAGIC_KEY_STATUS) ": Status\n" STR(MAGIC_KEY_CONSOLE) ": Activate Console Mode\n" #if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM STR(MAGIC_KEY_LAYER0) ": Switch to Layer 0\n" STR(MAGIC_KEY_LAYER1) ": Switch to Layer 1\n" STR(MAGIC_KEY_LAYER2) ": Switch to Layer 2\n" STR(MAGIC_KEY_LAYER3) ": Switch to Layer 3\n" STR(MAGIC_KEY_LAYER4) ": Switch to Layer 4\n" STR(MAGIC_KEY_LAYER5) ": Switch to Layer 5\n" STR(MAGIC_KEY_LAYER6) ": Switch to Layer 6\n" STR(MAGIC_KEY_LAYER7) ": Switch to Layer 7\n" STR(MAGIC_KEY_LAYER8) ": Switch to Layer 8\n" STR(MAGIC_KEY_LAYER9) ": Switch to Layer 9\n" #endif #if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS "F1-F10: Switch to Layer 0-9 (F10 = L0)\n" #endif #if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS "0-9: Switch to Layer 0-9\n" #endif STR(MAGIC_KEY_LAYER0_ALT) ": Switch to Layer 0 (alternate)\n" STR(MAGIC_KEY_BOOTLOADER) ": Jump to Bootloader\n" STR(MAGIC_KEY_BOOTLOADER_ALT) ": Jump to Bootloader (alternate)\n" #ifdef KEYBOARD_LOCK_ENABLE STR(MAGIC_KEY_LOCK) ": Lock Keyboard\n" #endif STR(MAGIC_KEY_EEPROM) ": Print EEPROM Settings\n" STR(MAGIC_KEY_EEPROM_CLEAR) ": Clear EEPROM\n" #ifdef NKRO_ENABLE STR(MAGIC_KEY_NKRO) ": NKRO Toggle\n" #endif #ifdef SLEEP_LED_ENABLE STR(MAGIC_KEY_SLEEP_LED) ": Sleep LED Test\n" #endif ); } static void print_version(void) { // print version & information print("\n\t- Version -\n"); print("VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") " "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") " "VER: " STR(DEVICE_VER) "\n"); print("BUILD: (" __DATE__ ")\n"); #ifndef SKIP_VERSION # ifdef PROTOCOL_CHIBIOS print("CHIBIOS: " STR(CHIBIOS_VERSION) ", CONTRIB: " STR(CHIBIOS_CONTRIB_VERSION) "\n"); # endif #endif /* build options */ print("OPTIONS:" #ifdef PROTOCOL_LUFA " LUFA" #endif #ifdef PROTOCOL_VUSB " VUSB" #endif #ifdef BOOTMAGIC_ENABLE " BOOTMAGIC" #endif #ifdef MOUSEKEY_ENABLE " MOUSEKEY" #endif #ifdef EXTRAKEY_ENABLE " EXTRAKEY" #endif #ifdef CONSOLE_ENABLE " CONSOLE" #endif #ifdef COMMAND_ENABLE " COMMAND" #endif #ifdef NKRO_ENABLE " NKRO" #endif #ifdef LTO_ENABLE " LTO" #endif " " STR(BOOTLOADER_SIZE) "\n"); print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__) #if defined(__AVR__) " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__ " AVR_ARCH: avr" STR(__AVR_ARCH__) #endif "\n"); return; } static void print_status(void) { print("\n\t- Status -\n"); print_val_hex8(host_keyboard_leds()); #ifndef PROTOCOL_VUSB // these aren't set on the V-USB protocol, so we just ignore them for now print_val_hex8(keyboard_protocol); print_val_hex8(keyboard_idle); #endif #ifdef NKRO_ENABLE print_val_hex8(keymap_config.nkro); #endif print_val_hex32(timer_read32()); return; } static void print_eeconfig(void) { // Print these variables if NO_PRINT or USER_PRINT are not defined. #if !defined(NO_PRINT) && !defined(USER_PRINT) print("default_layer: "); print_dec(eeconfig_read_default_layer()); print("\n"); debug_config_t dc; dc.raw = eeconfig_read_debug(); print("debug_config.raw: "); print_hex8(dc.raw); print("\n"); print(".enable: "); print_dec(dc.enable); print("\n"); print(".matrix: "); print_dec(dc.matrix); print("\n"); print(".keyboard: "); print_dec(dc.keyboard); print("\n"); print(".mouse: "); print_dec(dc.mouse); print("\n"); keymap_config_t kc; kc.raw = eeconfig_read_keymap(); print("keymap_config.raw: "); print_hex8(kc.raw); print("\n"); print(".swap_control_capslock: "); print_dec(kc.swap_control_capslock); print("\n"); print(".capslock_to_control: "); print_dec(kc.capslock_to_control); print("\n"); print(".swap_lctl_lgui: "); print_dec(kc.swap_lctl_lgui); print("\n"); print(".swap_rctl_rgui: "); print_dec(kc.swap_rctl_rgui); print("\n"); print(".swap_lalt_lgui: "); print_dec(kc.swap_lalt_lgui); print("\n"); print(".swap_ralt_rgui: "); print_dec(kc.swap_ralt_rgui); print("\n"); print(".no_gui: "); print_dec(kc.no_gui); print("\n"); print(".swap_grave_esc: "); print_dec(kc.swap_grave_esc); print("\n"); print(".swap_backslash_backspace: "); print_dec(kc.swap_backslash_backspace); print("\n"); print(".nkro: "); print_dec(kc.nkro); print("\n"); # ifdef BACKLIGHT_ENABLE backlight_config_t bc; bc.raw = eeconfig_read_backlight(); print("backlight_config.raw: "); print_hex8(bc.raw); print("\n"); print(".enable: "); print_dec(bc.enable); print("\n"); print(".level: "); print_dec(bc.level); print("\n"); # endif /* BACKLIGHT_ENABLE */ #endif /* !NO_PRINT */ } static bool command_common(uint8_t code) { #ifdef KEYBOARD_LOCK_ENABLE static host_driver_t *host_driver = 0; #endif switch (code) { #ifdef SLEEP_LED_ENABLE // test breathing sleep LED case MAGIC_KC(MAGIC_KEY_SLEEP_LED): print("Sleep LED Test\n"); sleep_led_toggle(); led_set(host_keyboard_leds()); break; #endif // print stored eeprom config case MAGIC_KC(MAGIC_KEY_EEPROM): print("eeconfig:\n"); print_eeconfig(); break; // clear eeprom case MAGIC_KC(MAGIC_KEY_EEPROM_CLEAR): print("Clearing EEPROM\n"); eeconfig_init(); break; #ifdef KEYBOARD_LOCK_ENABLE // lock/unlock keyboard case MAGIC_KC(MAGIC_KEY_LOCK): if (host_get_driver()) { host_driver = host_get_driver(); clear_keyboard(); host_set_driver(0); print("Locked.\n"); } else { host_set_driver(host_driver); print("Unlocked.\n"); } break; #endif // print help case MAGIC_KC(MAGIC_KEY_HELP): case MAGIC_KC(MAGIC_KEY_HELP_ALT): command_common_help(); break; // activate console case MAGIC_KC(MAGIC_KEY_CONSOLE): debug_matrix = false; debug_keyboard = false; debug_mouse = false; debug_enable = false; command_console_help(); print("C> "); command_state = CONSOLE; break; // jump to bootloader case MAGIC_KC(MAGIC_KEY_BOOTLOADER): case MAGIC_KC(MAGIC_KEY_BOOTLOADER_ALT): print("\n\nJumping to bootloader... "); reset_keyboard(); break; // debug toggle case MAGIC_KC(MAGIC_KEY_DEBUG): debug_enable = !debug_enable; if (debug_enable) { print("\ndebug: on\n"); } else { print("\ndebug: off\n"); debug_matrix = false; debug_keyboard = false; debug_mouse = false; } break; // debug matrix toggle case MAGIC_KC(MAGIC_KEY_DEBUG_MATRIX): debug_matrix = !debug_matrix; if (debug_matrix) { print("\nmatrix: on\n"); debug_enable = true; } else { print("\nmatrix: off\n"); } break; // debug keyboard toggle case MAGIC_KC(MAGIC_KEY_DEBUG_KBD): debug_keyboard = !debug_keyboard; if (debug_keyboard) { print("\nkeyboard: on\n"); debug_enable = true; } else { print("\nkeyboard: off\n"); } break; // debug mouse toggle case MAGIC_KC(MAGIC_KEY_DEBUG_MOUSE): debug_mouse = !debug_mouse; if (debug_mouse) { print("\nmouse: on\n"); debug_enable = true; } else { print("\nmouse: off\n"); } break; // print version case MAGIC_KC(MAGIC_KEY_VERSION): print_version(); break; // print status case MAGIC_KC(MAGIC_KEY_STATUS): print_status(); break; #ifdef NKRO_ENABLE // NKRO toggle case MAGIC_KC(MAGIC_KEY_NKRO): clear_keyboard(); // clear to prevent stuck keys keymap_config.nkro = !keymap_config.nkro; if (keymap_config.nkro) { print("NKRO: on\n"); } else { print("NKRO: off\n"); } break; #endif // switch layers case MAGIC_KC(MAGIC_KEY_LAYER0_ALT): switch_default_layer(0); break; #if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM case MAGIC_KC(MAGIC_KEY_LAYER0): switch_default_layer(0); break; case MAGIC_KC(MAGIC_KEY_LAYER1): switch_default_layer(1); break; case MAGIC_KC(MAGIC_KEY_LAYER2): switch_default_layer(2); break; case MAGIC_KC(MAGIC_KEY_LAYER3): switch_default_layer(3); break; case MAGIC_KC(MAGIC_KEY_LAYER4): switch_default_layer(4); break; case MAGIC_KC(MAGIC_KEY_LAYER5): switch_default_layer(5); break; case MAGIC_KC(MAGIC_KEY_LAYER6): switch_default_layer(6); break; case MAGIC_KC(MAGIC_KEY_LAYER7): switch_default_layer(7); break; case MAGIC_KC(MAGIC_KEY_LAYER8): switch_default_layer(8); break; case MAGIC_KC(MAGIC_KEY_LAYER9): switch_default_layer(9); break; #endif #if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS case KC_F1 ... KC_F9: switch_default_layer((code - KC_F1) + 1); break; case KC_F10: switch_default_layer(0); break; #endif #if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS case KC_1 ... KC_9: switch_default_layer((code - KC_1) + 1); break; case KC_0: switch_default_layer(0); break; #endif default: print("?"); return false; } return true; } /*********************************************************** * Command console ***********************************************************/ static void command_console_help(void) { print("\n\t- Console -\n" "ESC/q: quit\n" #ifdef MOUSEKEY_ENABLE "m: mousekey\n" #endif ); } static bool command_console(uint8_t code) { switch (code) { case KC_H: case KC_SLASH: /* ? */ command_console_help(); break; case KC_Q: case KC_ESC: command_state = ONESHOT; return false; #if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED) case KC_M: mousekey_console_help(); print("M> "); command_state = MOUSEKEY; return true; #endif default: print("?"); return false; } print("C> "); return true; } #if defined(MOUSEKEY_ENABLE) && !defined(MK_3_SPEED) /*********************************************************** * Mousekey console ***********************************************************/ static uint8_t mousekey_param = 0; static void mousekey_param_print(void) { // Print these variables if NO_PRINT or USER_PRINT are not defined. # if !defined(NO_PRINT) && !defined(USER_PRINT) print("\n\t- Values -\n"); print("1: delay(*10ms): "); print_dec(mk_delay); print("\n"); print("2: interval(ms): "); print_dec(mk_interval); print("\n"); print("3: max_speed: "); print_dec(mk_max_speed); print("\n"); print("4: time_to_max: "); print_dec(mk_time_to_max); print("\n"); print("5: wheel_max_speed: "); print_dec(mk_wheel_max_speed); print("\n"); print("6: wheel_time_to_max: "); print_dec(mk_wheel_time_to_max); print("\n"); # endif /* !NO_PRINT */ } //#define PRINT_SET_VAL(v) print(#v " = "); print_dec(v); print("\n"); # define PRINT_SET_VAL(v) xprintf(# v " = %d\n", (v)) static void mousekey_param_inc(uint8_t param, uint8_t inc) { switch (param) { case 1: if (mk_delay + inc < UINT8_MAX) mk_delay += inc; else mk_delay = UINT8_MAX; PRINT_SET_VAL(mk_delay); break; case 2: if (mk_interval + inc < UINT8_MAX) mk_interval += inc; else mk_interval = UINT8_MAX; PRINT_SET_VAL(mk_interval); break; case 3: if (mk_max_speed + inc < UINT8_MAX) mk_max_speed += inc; else mk_max_speed = UINT8_MAX; PRINT_SET_VAL(mk_max_speed); break; case 4: if (mk_time_to_max + inc < UINT8_MAX) mk_time_to_max += inc; else mk_time_to_max = UINT8_MAX; PRINT_SET_VAL(mk_time_to_max); break; case 5: if (mk_wheel_max_speed + inc < UINT8_MAX) mk_wheel_max_speed += inc; else mk_wheel_max_speed = UINT8_MAX; PRINT_SET_VAL(mk_wheel_max_speed); break; case 6: if (mk_wheel_time_to_max + inc < UINT8_MAX) mk_wheel_time_to_max += inc; else mk_wheel_time_to_max = UINT8_MAX; PRINT_SET_VAL(mk_wheel_time_to_max); break; } } static void mousekey_param_dec(uint8_t param, uint8_t dec) { switch (param) { case 1: if (mk_delay > dec) mk_delay -= dec; else mk_delay = 0; PRINT_SET_VAL(mk_delay); break; case 2: if (mk_interval > dec) mk_interval -= dec; else mk_interval = 0; PRINT_SET_VAL(mk_interval); break; case 3: if (mk_max_speed > dec) mk_max_speed -= dec; else mk_max_speed = 0; PRINT_SET_VAL(mk_max_speed); break; case 4: if (mk_time_to_max > dec) mk_time_to_max -= dec; else mk_time_to_max = 0; PRINT_SET_VAL(mk_time_to_max); break; case 5: if (mk_wheel_max_speed > dec) mk_wheel_max_speed -= dec; else mk_wheel_max_speed = 0; PRINT_SET_VAL(mk_wheel_max_speed); break; case 6: if (mk_wheel_time_to_max > dec) mk_wheel_time_to_max -= dec; else mk_wheel_time_to_max = 0; PRINT_SET_VAL(mk_wheel_time_to_max); break; } } static void mousekey_console_help(void) { print("\n\t- Mousekey -\n" "ESC/q: quit\n" "1: delay(*10ms)\n" "2: interval(ms)\n" "3: max_speed\n" "4: time_to_max\n" "5: wheel_max_speed\n" "6: wheel_time_to_max\n" "\n" "p: print values\n" "d: set defaults\n" "up: +1\n" "down: -1\n" "pgup: +10\n" "pgdown: -10\n" "\n" "speed = delta * max_speed * (repeat / time_to_max)\n"); xprintf("where delta: cursor=%d, wheel=%d\n" "See http://en.wikipedia.org/wiki/Mouse_keys\n", MOUSEKEY_MOVE_DELTA, MOUSEKEY_WHEEL_DELTA); } static bool mousekey_console(uint8_t code) { switch (code) { case KC_H: case KC_SLASH: /* ? */ mousekey_console_help(); break; case KC_Q: case KC_ESC: if (mousekey_param) { mousekey_param = 0; } else { print("C> "); command_state = CONSOLE; return false; } break; case KC_P: mousekey_param_print(); break; case KC_1: case KC_2: case KC_3: case KC_4: case KC_5: case KC_6: mousekey_param = numkey2num(code); break; case KC_UP: mousekey_param_inc(mousekey_param, 1); break; case KC_DOWN: mousekey_param_dec(mousekey_param, 1); break; case KC_PGUP: mousekey_param_inc(mousekey_param, 10); break; case KC_PGDN: mousekey_param_dec(mousekey_param, 10); break; case KC_D: mk_delay = MOUSEKEY_DELAY / 10; mk_interval = MOUSEKEY_INTERVAL; mk_max_speed = MOUSEKEY_MAX_SPEED; mk_time_to_max = MOUSEKEY_TIME_TO_MAX; mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; print("set default\n"); break; default: print("?"); return false; } if (mousekey_param) { xprintf("M%d> ", mousekey_param); } else { print("M>"); } return true; } #endif /*********************************************************** * Utilities ***********************************************************/ uint8_t numkey2num(uint8_t code) { switch (code) { case KC_1: return 1; case KC_2: return 2; case KC_3: return 3; case KC_4: return 4; case KC_5: return 5; case KC_6: return 6; case KC_7: return 7; case KC_8: return 8; case KC_9: return 9; case KC_0: return 0; } return 0; } static void switch_default_layer(uint8_t layer) { xprintf("L%d\n", layer); default_layer_set(1UL << layer); clear_keyboard(); }
各種コマンドの動作が記述されている
また、コンソールへの出力等も行っている
コマンドについてはここが詳しい
action_layer.h
ソース全体
/* Copyright 2013 Jun Wako <wakojun@gmail.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/>. */ #pragma once #include <stdint.h> #include "keyboard.h" #include "action.h" #if defined(LAYER_STATE_8BIT) typedef uint8_t layer_state_t; # define MAX_LAYER_BITS 3 # ifndef MAX_LAYER # define MAX_LAYER 8 # endif # define get_highest_layer(state) biton(state) #elif defined(LAYER_STATE_16BIT) typedef uint16_t layer_state_t; # define MAX_LAYER_BITS 4 # ifndef MAX_LAYER # define MAX_LAYER 16 # endif # define get_highest_layer(state) biton16(state) #else typedef uint32_t layer_state_t; # define MAX_LAYER_BITS 5 # ifndef MAX_LAYER # define MAX_LAYER 32 # endif # define get_highest_layer(state) biton32(state) #endif /* * Default Layer */ extern layer_state_t default_layer_state; void default_layer_debug(void); void default_layer_set(layer_state_t state); __attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state); __attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state); #ifndef NO_ACTION_LAYER /* bitwise operation */ void default_layer_or(layer_state_t state); void default_layer_and(layer_state_t state); void default_layer_xor(layer_state_t state); #else # define default_layer_or(state) # define default_layer_and(state) # define default_layer_xor(state) #endif /* * Keymap Layer */ #ifndef NO_ACTION_LAYER extern layer_state_t layer_state; void layer_state_set(layer_state_t state); bool layer_state_is(uint8_t layer); bool layer_state_cmp(layer_state_t layer1, uint8_t layer2); void layer_debug(void); void layer_clear(void); void layer_move(uint8_t layer); void layer_on(uint8_t layer); void layer_off(uint8_t layer); void layer_invert(uint8_t layer); /* bitwise operation */ void layer_or(layer_state_t state); void layer_and(layer_state_t state); void layer_xor(layer_state_t state); layer_state_t layer_state_set_user(layer_state_t state); layer_state_t layer_state_set_kb(layer_state_t state); #else # define layer_state 0 # define layer_state_set(layer) # define layer_state_is(layer) (layer == 0) # define layer_state_cmp(state, layer) (state == 0 ? layer == 0 : (state & 1UL << layer) != 0) # define layer_debug() # define layer_clear() # define layer_move(layer) (void)layer # define layer_on(layer) (void)layer # define layer_off(layer) (void)layer # define layer_invert(layer) (void)layer # define layer_or(state) (void)state # define layer_and(state) (void)state # define layer_xor(state) (void)state # define layer_state_set_kb(state) (void)state # define layer_state_set_user(state) (void)state #endif /* pressed actions cache */ #if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) void update_source_layers_cache(keypos_t key, uint8_t layer); uint8_t read_source_layers_cache(keypos_t key); #endif action_t store_or_get_action(bool pressed, keypos_t key); /* return the topmost non-transparent layer currently associated with key */ uint8_t layer_switch_get_layer(keypos_t key); /* return action depending on current layer status */ action_t layer_switch_get_action(keypos_t key);
ほぼ定数の初期化や、プロトタイプ宣言である
action_layter.c
ソース全体
#include <stdint.h> #include "keyboard.h" #include "action.h" #include "util.h" #include "action_layer.h" #ifdef DEBUG_ACTION # include "debug.h" #else # include "nodebug.h" #endif /** \brief Default Layer State */ layer_state_t default_layer_state = 0; /** \brief Default Layer State Set At user Level * * Run user code on default layer state change */ __attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state) { return state; } /** \brief Default Layer State Set At Keyboard Level * * Run keyboard code on default layer state change */ __attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state) { return default_layer_state_set_user(state); } /** \brief Default Layer State Set * * Static function to set the default layer state, prints debug info and clears keys */ static void default_layer_state_set(layer_state_t state) { state = default_layer_state_set_kb(state); debug("default_layer_state: "); default_layer_debug(); debug(" to "); default_layer_state = state; default_layer_debug(); debug("\n"); #ifdef STRICT_LAYER_RELEASE clear_keyboard_but_mods(); // To avoid stuck keys #else clear_keyboard_but_mods_and_keys(); // Don't reset held keys #endif } /** \brief Default Layer Print * * Print out the hex value of the 32-bit default layer state, as well as the value of the highest bit. */ void default_layer_debug(void) { dprintf("%08lX(%u)", default_layer_state, get_highest_layer(default_layer_state)); } /** \brief Default Layer Set * * Sets the default layer state. */ void default_layer_set(layer_state_t state) { default_layer_state_set(state); } #ifndef NO_ACTION_LAYER /** \brief Default Layer Or * * Turns on the default layer based on matching bits between specifed layer and existing layer state */ void default_layer_or(layer_state_t state) { default_layer_state_set(default_layer_state | state); } /** \brief Default Layer And * * Turns on default layer based on matching enabled bits between specifed layer and existing layer state */ void default_layer_and(layer_state_t state) { default_layer_state_set(default_layer_state & state); } /** \brief Default Layer Xor * * Turns on default layer based on non-matching bits between specifed layer and existing layer state */ void default_layer_xor(layer_state_t state) { default_layer_state_set(default_layer_state ^ state); } #endif #ifndef NO_ACTION_LAYER /** \brief Keymap Layer State */ layer_state_t layer_state = 0; /** \brief Layer state set user * * Runs user code on layer state change */ __attribute__((weak)) layer_state_t layer_state_set_user(layer_state_t state) { return state; } /** \brief Layer state set keyboard * * Runs keyboard code on layer state change */ __attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) { return layer_state_set_user(state); } /** \brief Layer state set * * Sets the layer to match the specifed state (a bitmask) */ void layer_state_set(layer_state_t state) { state = layer_state_set_kb(state); dprint("layer_state: "); layer_debug(); dprint(" to "); layer_state = state; layer_debug(); dprintln(); # ifdef STRICT_LAYER_RELEASE clear_keyboard_but_mods(); // To avoid stuck keys # else clear_keyboard_but_mods_and_keys(); // Don't reset held keys # endif } /** \brief Layer clear * * Turn off all layers */ void layer_clear(void) { layer_state_set(0); } /** \brief Layer state is * * Return whether the given state is on (it might still be shadowed by a higher state, though) */ bool layer_state_is(uint8_t layer) { return layer_state_cmp(layer_state, layer); } /** \brief Layer state compare * * Used for comparing layers {mostly used for unit testing} */ bool layer_state_cmp(layer_state_t cmp_layer_state, uint8_t layer) { if (!cmp_layer_state) { return layer == 0; } return (cmp_layer_state & (1UL << layer)) != 0; } /** \brief Layer move * * Turns on the given layer and turn off all other layers */ void layer_move(uint8_t layer) { layer_state_set(1UL << layer); } /** \brief Layer on * * Turns on given layer */ void layer_on(uint8_t layer) { layer_state_set(layer_state | (1UL << layer)); } /** \brief Layer off * * Turns off given layer */ void layer_off(uint8_t layer) { layer_state_set(layer_state & ~(1UL << layer)); } /** \brief Layer invert * * Toggle the given layer (set it if it's unset, or unset it if it's set) */ void layer_invert(uint8_t layer) { layer_state_set(layer_state ^ (1UL << layer)); } /** \brief Layer or * * Turns on layers based on matching bits between specifed layer and existing layer state */ void layer_or(layer_state_t state) { layer_state_set(layer_state | state); } /** \brief Layer and * * Turns on layers based on matching enabled bits between specifed layer and existing layer state */ void layer_and(layer_state_t state) { layer_state_set(layer_state & state); } /** \brief Layer xor * * Turns on layers based on non-matching bits between specifed layer and existing layer state */ void layer_xor(layer_state_t state) { layer_state_set(layer_state ^ state); } /** \brief Layer debug printing * * Print out the hex value of the 32-bit layer state, as well as the value of the highest bit. */ void layer_debug(void) { dprintf("%08lX(%u)", layer_state, get_highest_layer(layer_state)); } #endif #if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) /** \brief source layer cache */ uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}}; /** \brief update source layers cache * * Updates the cached keys when changing layers */ void update_source_layers_cache(keypos_t key, uint8_t layer) { const uint8_t key_number = key.col + (key.row * MATRIX_COLS); const uint8_t storage_row = key_number / 8; const uint8_t storage_bit = key_number % 8; for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { source_layers_cache[storage_row][bit_number] ^= (-((layer & (1U << bit_number)) != 0) ^ source_layers_cache[storage_row][bit_number]) & (1U << storage_bit); } } /** \brief read source layers cache * * reads the cached keys stored when the layer was changed */ uint8_t read_source_layers_cache(keypos_t key) { const uint8_t key_number = key.col + (key.row * MATRIX_COLS); const uint8_t storage_row = key_number / 8; const uint8_t storage_bit = key_number % 8; uint8_t layer = 0; for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { layer |= ((source_layers_cache[storage_row][bit_number] & (1U << storage_bit)) != 0) << bit_number; } return layer; } #endif /** \brief Store or get action (FIXME: Needs better summary) * * Make sure the action triggered when the key is released is the same * one as the one triggered on press. It's important for the mod keys * when the layer is switched after the down event but before the up * event as they may get stuck otherwise. */ action_t store_or_get_action(bool pressed, keypos_t key) { #if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) if (disable_action_cache) { return layer_switch_get_action(key); } uint8_t layer; if (pressed) { layer = layer_switch_get_layer(key); update_source_layers_cache(key, layer); } else { layer = read_source_layers_cache(key); } return action_for_key(layer, key); #else return layer_switch_get_action(key); #endif } /** \brief Layer switch get layer * * Gets the layer based on key info */ uint8_t layer_switch_get_layer(keypos_t key) { #ifndef NO_ACTION_LAYER action_t action; action.code = ACTION_TRANSPARENT; layer_state_t layers = layer_state | default_layer_state; /* check top layer first */ for (int8_t i = MAX_LAYER - 1; i >= 0; i--) { if (layers & (1UL << i)) { action = action_for_key(i, key); if (action.code != ACTION_TRANSPARENT) { return i; } } } /* fall back to layer 0 */ return 0; #else return get_highest_layer(default_layer_state); #endif } /** \brief Layer switch get layer * * Gets action code based on key position */ action_t layer_switch_get_action(keypos_t key) { return action_for_key(layer_switch_get_layer(key), key); }
~11行
include 宣言である
~最終行
各変数や関数について見ていこう
layer_state_t default_layer_state
デフォルトの layer_state_t
を初期化している
layer_state_t
は uint8_t
, uint16_t
, uint32_t
のいずれかである(デフォルトは uint32_t
)
初期化処理を除いて、基本的には参照されるだけだと思われる
layer_state_t default_layer_state_set_user(layer_state_t state)
ユーザーが上書き可能な関数である
渡された state
を処理することで default_layer_state
を定義できる
主に keymap.c
などで実装する
layer_state_t default_layer_state_set_kb(layer_state_t state)
ユーザーが上書き可能な関数である
渡された state
を処理することで default_layer_state
を定義できる
主に <keyboard>.c
などで実装する
void default_layer_state_set(layer_state_t state)
default_layer_state
を定義する関数である
レイヤの状態の表示も行う
void default_layer_debug(void)
default_layer_state
と、1地番上のレイヤを表示する関数である
void default_layer_set(layer_state_t state)
default_layer_state
を定義する関数である
void default_layer_or(layer_state_t state)
default_layer_state
と渡された state
との OR 演算を行い、 default_layer_state
に代入する関数である
void default_layer_and(layer_state_t state)
default_layer_state
と渡された state
との AND 演算を行い、 default_layer_state
に代入する関数である
void default_layer_xor(layer_state_t state)
default_layer_state
と渡された state
との XOR 演算を行い、 default_layer_state
に代入する関数である
layer_state_t layer_state
現在の layer_state_t
の状態を保持する変数である
layer_state_t layer_state_set_user(layer_state_t state)
ユーザーが上書き可能な関数である
渡された state
を処理することで layer_state
を定義できる
主に keymap.c
などで実装する
layer_state_t layer_state_set_kb(layer_state_t state)
ユーザーが上書き可能な関数である
渡された state
を処理することで layer_state
を定義できる
主に <keyboard>.c
などで実装する
void layer_state_set(layer_state_t state)
layer_state
を定義する関数である
レイヤの状態の表示も行う
void layer_clear(void)
layer_state
を 0
に初期化する関数である
bool layer_state_is(uint8_t layer)
layer_state
が layer
と一致するかを返す関数である
bool layer_state_cmp(layer_state_t cmp_layer_state, uint8_t layer)
cmp_layer_state
の下から layer
bit 目が立っているかを判定する関数である
void layer_move(uint8_t layer)
layer_state
の下から layer
bit 目を立て、ほかのビットを倒す関数である
void layer_on(uint8_t layer)
layer_state
の下から layer
bit 目を立てる関数である(ほかのビットは触れない)
void layer_off(uint8_t layer)
layer_state
の下から layer
bit 目を倒す関数である(ほかのビットは触れない)
void layer_invert(uint8_t layer)
layer_state
の下から layer
bit 目を反転する関数である(ほかのビットは触れない)
1 -> 0
, 0 -> 1
void layer_or(layer_state_t state)
layer_state
と渡された state
との OR 演算を行い、 layer_state
に代入する関数である
void layer_and(layer_state_t state)
layer_state
と渡された state
との AND 演算を行い、 layer_state
に代入する関数である
void layer_xor(layer_state_t state)
layer_state
と渡された state
との XOR 演算を行い、 layer_state
に代入する関数である
void layer_debug(void)
現在の layer_state
と、1地番上のレイヤを表示する関数である
uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS]
以下のようなキーボードを考える
/*--------------------*/ #define MATRIX_ROWS 3 #define MATRIX_COLS 3 /*--------------------*/ // action_layer.h L39-44 より #define MAX_LAYER_BITS 5 #define MAX_LAYER 32 /*--------------------*/ /* | 0 | 1 | 2 | --- ,-----------. 0 | a | b | c | --- |---+---+---| 1 | d | e | f | --- |---+---+---| 2 | g | h | i | --- `-----------' */
a
~ i
はキーを識別しやすくするために振っているもので、キーコードではない
この時 uint8_t source_layers_cache[][]
は以下のようになる
(MATRIX_ROWS * MATRIX_COLS +7) / 8 = (3 * 3 + 7) / 8 = 16 / 8 = 2 MAX_LAYER_BITS = 5 source_layers_cache[2][5] = [ [0000 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000], [0000 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000] ]
void update_source_layers_cache(keypos_t key, uint8_t layer)
keypos_t
は以下のように定義されている
// https://github.com/qmk/qmk_firmware/blob/master/tmk_core/common/keyboard.h#L28-L31 typedef struct { uint8_t col; uint8_t row; } keypos_t;
例えば、上で示したキーボードで layer = 1
のとき f
のキーを押したとする
すると、渡される key
と layer
は以下である
key.col = 2 key.row = 1 layer = 1
よって、各変数は以下のようになる
key_number = key.col + (key.row * MATRIX_COLS) = 2 + (1 * 3) = 5 storage_row = key_number / 8 = 5 / 8 = 0 storage_bit = key_number % 8 = 5 % 8 = 5
つまり、 source_layer_cache[][]
の 0 行目、 6bit 目に値を格納する という意味になる
storage_bit
は 0
から始まるため、 + 1
している
実行すると、 source_layer_cache[][]
の中身はこのようになる
source_layers_cache[2][5] = [ [0010 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000], [0000 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000] ]
さて、どのようにキーの位置を保持しているかを考えよう
key_number
の計算式を見ればわかるだろう
上で示したキーボードの例で考えるとこのようになる
row | col | key_number |
|
---|---|---|---|
a | 0 | 0 | 0 |
b | 0 | 1 | 1 |
c | 0 | 2 | 2 |
d | 1 | 0 | 3 |
e | 1 | 1 | 4 |
f | 1 | 2 | 5 |
g | 2 | 0 | 6 |
h | 2 | 1 | 7 |
i | 2 | 2 | 8 |
では、 source_layer_cache[][]
にこれに基づいて値を入れてみよう
全部記述するのはわかりにくいので、一番左の要素のみ記述する
押されたキー : a key_number = 0 source_layers_cache[2][5] = [ [0000 0001, ...], [0000 0000, ...] ]
押されたキー : b key_number = 1 source_layers_cache[2][5] = [ [0000 0010, ...], [0000 0000, ...] ]
押されたキー : c key_number = 2 source_layers_cache[2][5] = [ [0000 0100, ...], [0000 0000, ...] ]
押されたキー : d key_number = 3 source_layers_cache[2][5] = [ [0000 1000, ...], [0000 0000, ...] ]
押されたキー : e key_number = 4 source_layers_cache[2][5] = [ [0001 0000, ...], [0000 0000, ...] ]
押されたキー : f key_number = 5 source_layers_cache[2][5] = [ [0010 0000, ...], [0000 0000, ...] ]
押されたキー : g key_number = 6 source_layers_cache[2][5] = [ [0100 0000, ...], [0000 0000, ...] ]
押されたキー : h key_number = 7 source_layers_cache[2][5] = [ [1000 0000, ...], [0000 0000, ...] ]
押されたキー : i key_number = 8 source_layers_cache[2][5] = [ [0000 0000, ...], [0000 0001, ...] ]
key_number = 8
つまり 9bit 目を立てる場合、2行目に入るので注意してほしい
キーの位置をどうやって保持しているかは分かった
では、レイヤーの情報はどのように保持しているのだろうか
source_layers_cache[][]
は要素を5つ持つ配列の配列であった
この 要素が5つあること が意味を持つ
各要素が2進数の桁を表しているのだ
<--1桁--> <--2桁--> <--3桁--> <--4桁--> <--5桁--> [0000 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000],
例えば、 layer = 5
のとき、2進数で表すと 0000 0101
となる
この時 e
(key.col = 1
, key.row = 1
) のキーを押したとすると、 key_number = 4
となり、 source_layers_cache[][]
は次のようになる
source_layers_cache[2][5] = [ [0001 0000, 0000 0000, 0001 0000, 0000 0000, 0000 0000], [0000 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000] ]
これで、キーの位置とレイヤーの情報が保持できた
さらに別のキーを別のレイヤーで押しても、同じように保持される
layer = 15
で d
(key.col = 0
, key.row = 1
, key_number = 3
) のキーを押すと、次のように更新される
source_layers_cache[2][5] = [ [0001 1000, 0000 1000, 0001 1000, 0000 1000, 0000 0000], [0000 0000, 0000 0000, 0000 0000, 0000 0000, 0000 0000] ]
uint8_t read_source_layers_cache(keypos_t key)
source_layers_cache[][]
を key
の位置で確認し、レイヤーのインデックスを返す関数である
action_t store_or_get_action(bool pressed, keypos_t key)
press = true
のとき update_source_layers_cache()
を実行して source_layers_cache[][]
を更新する
press = false
のとき read_source_layers_cache()
を実行してレイヤーのインデックスを取得し、 action_t
を返す
action_t
は以下で定義されている
uint8_t layer_switch_get_layer(keypos_t key)
key
の位置において、 ACTION_TRANSPARENT
(キーコードで言う KC_TRNS
, _______
)でない最上位のレイヤーを返す関数である
action_t layer_switch_get_action(keypos_t key)
key
の位置の action_t
を返す関数である
layer_switch_get_layer()
で ACTION_TRANSPARENT
でないレイヤーを取得しているので有効な action_t
が実行される
まとめ
action.c
に include されているものを順番に探検してきた
action_layer.c
でのキーの位置とレイヤーの情報の持ち方には感嘆しかなかった
次回予告
次回は action.c
に include されているものの続きを見ていこうと思う