diff --git a/keyboards/chocofi/chocofi.h b/keyboards/chocofi/chocofi.h new file mode 100644 index 000000000000..a4ecd1ccd354 --- /dev/null +++ b/keyboards/chocofi/chocofi.h @@ -0,0 +1,19 @@ +#pragma once +#include "quantum.h" + +#define LAYOUT_split_3x5_3( \ + L00, L01, L02, L03, L04, R00, R01, R02, R03, R04, \ + L10, L11, L12, L13, L14, R10, R11, R12, R13, R14, \ + L20, L21, L22, L23, L24, R20, R21, R22, R23, R24, \ + L30, L31, L32, R30, R31, R32 \ + ) \ + { \ + { KC_NO, L00, L01, L02, L03, L04 }, \ + { KC_NO, L10, L11, L12, L13, L14 }, \ + { KC_NO, L20, L21, L22, L23, L24 }, \ + { KC_NO, KC_NO, KC_NO, L30, L31, L32 }, \ + { KC_NO, R04, R03, R02, R01, R00 }, \ + { KC_NO, R14, R13, R12, R11, R10 }, \ + { KC_NO, R24, R23, R22, R21, R20 }, \ + { KC_NO, KC_NO, KC_NO, R32, R31, R30 } \ + } diff --git a/keyboards/chocofi/config.h b/keyboards/chocofi/config.h new file mode 100644 index 000000000000..2bce5adffee9 --- /dev/null +++ b/keyboards/chocofi/config.h @@ -0,0 +1,13 @@ +// Copyright 2022 Pavel Glushkov (@pashutk) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define MATRIX_ROWS 8 +#define MATRIX_COLS 6 + +#define USE_SERIAL +#define SOFT_SERIAL_PIN D2 + +#define TAPPING_TERM 175 +#define TAPPING_TERM_PER_KEY \ No newline at end of file diff --git a/keyboards/chocofi/info.json b/keyboards/chocofi/info.json new file mode 100644 index 000000000000..768feda44a42 --- /dev/null +++ b/keyboards/chocofi/info.json @@ -0,0 +1,71 @@ +{ + "manufacturer": "Pavel Glushkov", + "keyboard_name": "chocofi", + "maintainer": "pashutk", + "bootloader": "caterina", + "diode_direction": "COL2ROW", + "features": { + "magic": false, + "bootmagic": false, + "space_cadet": false, + "grave_esc": false, + "command": false, + "console": false, + "extrakey": false, + "mousekey": false, + "nkro": true + }, + "matrix_pins": { + "cols": ["F4", "F5", "F6", "F7", "B1", "B3"], + "rows": ["D4", "C6", "D7", "E6"] + }, + "processor": "atmega32u4", + "url": "https://github.com/pashutk/chocofi", + "usb": { + "device_version": "1.0.0", + "pid": "0x0000", + "vid": "0xFEED" + }, + "layouts": { + "LAYOUT_split_3x5_3": { + "layout": [ + { "x": 0, "y": 0.25 }, + { "x": 1, "y": 0.125 }, + { "x": 2, "y": 0 }, + { "x": 3, "y": 0.125 }, + { "x": 4, "y": 0.25 }, + { "x": 7, "y": 0.25 }, + { "x": 8, "y": 0.125 }, + { "x": 9, "y": 0 }, + { "x": 10, "y": 0.125 }, + { "x": 11, "y": 0.25 }, + { "x": 0, "y": 1.25 }, + { "x": 1, "y": 1.125 }, + { "x": 2, "y": 1 }, + { "x": 3, "y": 1.125 }, + { "x": 4, "y": 1.25 }, + { "x": 7, "y": 1.25 }, + { "x": 8, "y": 1.125 }, + { "x": 9, "y": 1 }, + { "x": 10, "y": 1.125 }, + { "x": 11, "y": 1.25 }, + { "x": 0, "y": 2.25 }, + { "x": 1, "y": 2.125 }, + { "x": 2, "y": 2 }, + { "x": 3, "y": 2.125 }, + { "x": 4, "y": 2.25 }, + { "x": 7, "y": 2.25 }, + { "x": 8, "y": 2.125 }, + { "x": 9, "y": 2 }, + { "x": 10, "y": 2.125 }, + { "x": 11, "y": 2.25 }, + { "x": 2.5, "y": 3.25 }, + { "x": 3.5, "y": 3.5 }, + { "x": 4.5, "y": 3.75 }, + { "x": 6.5, "y": 3.75 }, + { "x": 7.5, "y": 3.5 }, + { "x": 8.5, "y": 3.25 } + ] + } + } +} diff --git a/keyboards/chocofi/keymaps/default/keymap.c b/keyboards/chocofi/keymaps/default/keymap.c new file mode 100644 index 000000000000..089301156eb5 --- /dev/null +++ b/keyboards/chocofi/keymaps/default/keymap.c @@ -0,0 +1,25 @@ +#include QMK_KEYBOARD_H +#include + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* + * ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ + * │ Q │ W │ E │ R │ T │ │ Y │ U │ I │ O │ P │ + * ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + * │ A │ S │ D │ F │ G │ │ H │ J │ K │ L │ ; │ + * ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + * │ Z │ X │ C │ V │ B │ │ N │ M │ , │ . │ / │ + * └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ + * ┌───┐ ┌───┐ + * │GUI├───┐ ┌───┤Alt│ + * └───┤Bsp├───┐ ┌───┤Ent├───┘ + * └───┤ │ │ ├───┘ + * └───┘ └───┘ + */ + [0] = LAYOUT_split_3x5_3( + KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, + KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, + KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, + KC_LGUI, KC_BSPC, KC_SPC, KC_SPC, KC_ENT, KC_RALT + ) +}; diff --git a/keyboards/chocofi/keymaps/dtk35/config.h b/keyboards/chocofi/keymaps/dtk35/config.h new file mode 100644 index 000000000000..f382a6fc45f7 --- /dev/null +++ b/keyboards/chocofi/keymaps/dtk35/config.h @@ -0,0 +1,8 @@ +#undef NO_ACTION_LAYER +#undef NO_ACTION_TAPPING + +#define IGNORE_MOD_TAP_INTERRUPT +#define TAPPING_TERM_PER_KEY +#define TAPPING_TERM_SFT 150 +#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY +#define RETRO_TAPPING_PER_KEY diff --git a/keyboards/chocofi/keymaps/dtk35/features/caps_word.c b/keyboards/chocofi/keymaps/dtk35/features/caps_word.c new file mode 100644 index 000000000000..24dbd76f857c --- /dev/null +++ b/keyboards/chocofi/keymaps/dtk35/features/caps_word.c @@ -0,0 +1,158 @@ +// Copyright 2021-2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// For full documentation, see +// https://getreuer.info/posts/keyboards/caps-word + +#include "caps_word.h" + +static bool caps_word_active = false; + +// Many keyboards enable the Command feature, which by default is also activated +// by Left Shift + Right Shift. It can be configured to use a different key +// combination by defining IS_COMMAND(). We make a non-fatal warning if Command +// is enabled but IS_COMMAND() is *not* defined. +#if defined(COMMAND_ENABLE) && !defined(IS_COMMAND) +#pragma message "Caps Word and Command should not be enabled at the same time, since both use the Left Shift + Right Shift key combination. Please disable Command, or ensure that `IS_COMMAND` is not set to (get_mods() == MOD_MASK_SHIFT)." +#endif // defined(COMMAND_ENABLE) && !defined(IS_COMMAND) + +#if CAPS_WORD_IDLE_TIMEOUT > 0 +#if CAPS_WORD_IDLE_TIMEOUT < 100 || CAPS_WORD_IDLE_TIMEOUT > 30000 +// Constrain timeout to a sensible range. With the 16-bit timer, the longest +// representable timeout is 32768 ms, rounded here to 30000 ms = half a minute. +#error "caps_word: CAPS_WORD_IDLE_TIMEOUT must be between 100 and 30000 ms" +#endif + +static uint16_t idle_timer = 0; + +void caps_word_task(void) { + if (caps_word_active && timer_expired(timer_read(), idle_timer)) { + caps_word_set(false); + } +} +#endif // CAPS_WORD_IDLE_TIMEOUT > 0 + +bool process_caps_word(uint16_t keycode, keyrecord_t* record) { +#ifndef NO_ACTION_ONESHOT + const uint8_t mods = get_mods() | get_oneshot_mods(); +#else + const uint8_t mods = get_mods(); +#endif // NO_ACTION_ONESHOT + + if (!caps_word_active) { + // Pressing both shift keys at the same time enables caps word. + if (mods == MOD_MASK_SHIFT) { + caps_word_set(true); // Activate Caps Word. + return false; + } + return true; + } else { +#if CAPS_WORD_IDLE_TIMEOUT > 0 + idle_timer = record->event.time + CAPS_WORD_IDLE_TIMEOUT; +#endif // CAPS_WORD_IDLE_TIMEOUT > 0 + } + + if (!record->event.pressed) { return true; } + + if (!(mods & ~MOD_MASK_SHIFT)) { + switch (keycode) { + // Ignore MO, TO, TG, TT, and OSL layer switch keys. + case QK_MOMENTARY ... QK_MOMENTARY_MAX: + case QK_TO ... QK_TO_MAX: + case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: + case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: + case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: + return true; + +#ifndef NO_ACTION_TAPPING + case QK_MOD_TAP ... QK_MOD_TAP_MAX: + if (record->tap.count == 0) { + // Deactivate if a mod becomes active through holding a mod-tap key. + caps_word_set(false); + return true; + } + keycode &= 0xff; + break; + +#ifndef NO_ACTION_LAYER + case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: +#endif // NO_ACTION_LAYER + if (record->tap.count == 0) { return true; } + keycode &= 0xff; + break; +#endif // NO_ACTION_TAPPING + +#ifdef SWAP_HANDS_ENABLE + case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: + if (keycode > 0x56F0 || record->tap.count == 0) { return true; } + keycode &= 0xff; + break; +#endif // SWAP_HANDS_ENABLE + } + + clear_weak_mods(); + if (caps_word_press_user(keycode)) { + send_keyboard_report(); + return true; + } + } + + caps_word_set(false); // Deactivate Caps Word. + return true; +} + +void caps_word_set(bool active) { + if (active != caps_word_active) { + if (active) { + clear_mods(); +#ifndef NO_ACTION_ONESHOT + clear_oneshot_mods(); +#endif // NO_ACTION_ONESHOT +#if CAPS_WORD_IDLE_TIMEOUT > 0 + idle_timer = timer_read() + CAPS_WORD_IDLE_TIMEOUT; +#endif // CAPS_WORD_IDLE_TIMEOUT > 0 + } else { + // Make sure weak shift is off. + unregister_weak_mods(MOD_BIT(KC_LSFT)); + } + + caps_word_active = active; + caps_word_set_user(active); + } +} + +bool caps_word_get(void) { return caps_word_active; } + +__attribute__((weak)) void caps_word_set_user(bool active) {} + +__attribute__((weak)) bool caps_word_press_user(uint16_t keycode) { + switch (keycode) { + // Keycodes that continue Caps Word, with shift applied. + case KC_A ... KC_Z: + case KC_MINS: + add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key. + return true; + + // Keycodes that continue Caps Word, without shifting. + case KC_1 ... KC_0: + case KC_BSPC: + case KC_DEL: + case KC_UNDS: + return true; + + default: + return false; // Deactivate Caps Word. + } +} diff --git a/keyboards/chocofi/keymaps/dtk35/features/caps_word.h b/keyboards/chocofi/keymaps/dtk35/features/caps_word.h new file mode 100644 index 000000000000..7cfe6a3193b8 --- /dev/null +++ b/keyboards/chocofi/keymaps/dtk35/features/caps_word.h @@ -0,0 +1,135 @@ +// Copyright 2021-2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// Caps Word, activated by pressing both shift keys at the same time. +// +// This library implements "Caps Word", which is like conventional Caps Lock, +// but automatically disables itself at the end of the word. This is useful for +// typing all-caps identifiers like `MOD_MASK_ALT`. +// +// Caps Word is activated by pressing the left and right shift keys at the same +// time. This way you don't need a dedicated key for using Caps Word. I've +// tested that this works as expected with one-shot mods and Space Cadet Shift. +// If your shift keys are mod-taps, activate Caps Word by holding both shift +// mod-tap keys until the tapping term, release them, then begin typing. +// +// Optionally, Caps Word may be configured to deactivate if the keyboard is idle +// for some time. This is useful to mitigate unintended shifting when you get +// interrupted or switch to the mouse while Caps Word is active. In your +// config.h, define `CAPS_WORD_IDLE_TIMEOUT` with a time in milliseconds: +// +// #define CAPS_WORD_IDLE_TIMEOUT 5000 // Turn off Caps Word after 5 seconds. +// +// and in your keymap.c, define (or add to) `matrix_scan_user()` as +// +// void matrix_scan_user(void) { +// caps_word_task(); +// // Other tasks... +// } +// +// For full documentation, see +// https://getreuer.info/posts/keyboards/caps-word + +#pragma once + +#include "quantum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Call this function from `process_record_user()` to implement Caps Word. +bool process_caps_word(uint16_t keycode, keyrecord_t* record); + +// If CAPS_WORD_IDLE_TIMEOUT is set, call `caps_word_task()` from +// `matrix_scan_user()` as described above. +// +// If CAPS_WORD_IDLE_TIMEOUT isn't set, calling this function has no effect (but +// will still compile). +#if CAPS_WORD_IDLE_TIMEOUT > 0 +void caps_word_task(void); +#else +static inline void caps_word_task(void) {} +#endif + +// Activates or deactivates Caps Word. For instance activate Caps Word with a +// combo by defining a `COMBO_ACTION` that calls `caps_word_set(true)`: +// +// void process_combo_event(uint16_t combo_index, bool pressed) { +// switch(combo_index) { +// case CAPS_COMBO: +// if (pressed) { +// caps_word_set(true); // Activate Caps Word. +// } +// break; +// +// // Other combos... +// } +// } +void caps_word_set(bool active); + +// Returns whether Caps Word is currently active. +bool caps_word_get(void); + +// An optional callback that gets called when Caps Word turns on or off. This is +// useful to represent the current Caps Word state, e.g. by setting an LED or +// playing a sound. In your keymap, define +// +// void caps_word_set_user(bool active) { +// if (active) { +// // Do something when Caps Word activates. +// } else { +// // Do something when Caps Word deactivates. +// } +// } +void caps_word_set_user(bool active); + +// An optional callback which is called on every key press while Caps Word is +// active. When the key should be shifted (that is, a letter key), the callback +// should call `add_weak_mods(MOD_BIT(KC_LSFT))` to shift the key. The callback +// also determines whether the key should continue Caps Word. Returning true +// continues the current "word", while returning false is "word breaking" and +// deactivates Caps Word. The default callback is +// +// bool caps_word_press_user(uint16_t keycode) { +// switch (keycode) { +// // Keycodes that continue Caps Word, with shift applied. +// case KC_A ... KC_Z: +// case KC_MINS: +// add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key. +// return true; +// +// // Keycodes that continue Caps Word, without shifting. +// case KC_1 ... KC_0: +// case KC_BSPC: +// case KC_DEL: +// case KC_UNDS: +// return true; +// +// default: +// return false; // Deactivate Caps Word. +// } +// } +// +// To customize, copy the above function into your keymap and add/remove +// keycodes to the above cases. +// +// NOTE: Outside of this callback, you can use `caps_word_set(false)` to +// deactivate Caps Word. +bool caps_word_press_user(uint16_t keycode); + +#ifdef __cplusplus +} +#endif diff --git a/keyboards/chocofi/keymaps/dtk35/keymap.c b/keyboards/chocofi/keymaps/dtk35/keymap.c new file mode 100644 index 000000000000..9f6bd82b56b6 --- /dev/null +++ b/keyboards/chocofi/keymaps/dtk35/keymap.c @@ -0,0 +1,311 @@ +#include QMK_KEYBOARD_H +#include +#include "features/caps_word.h" + +enum { + GNOME_3 = 0, + GNOME_40, + OSX, + WIN_10, + + NUM_SUPPORTED_WMS, +} window_manager = WIN_10; + +// Layer declarations +enum { + COLEMAK = 0, + MOD_ARR, + NAVIGAT, + FUN_NUM, + SYMBOLS, + WNDWMGR, + COMPOSE, + + NUM_LAYERS +}; + + +// Custom keycodes +enum custom_keycodes { + WM_GNOME_3 = SAFE_RANGE, + WM_GNOME_40, + WM_OSX, + WM_WIN_10, + WM_EXPOSEE, + WM_LEFT_DESK, + WM_RGHT_DESK, + WM_UPPR_DESK, + WM_LOWR_DESK, +}; + +#define ____ KC_TRNS +#define XXXX KC_NO +// Left +// Home row mods +#define KC_A_ LALT_T(KC_A) +#define KC_R_ LGUI_T(KC_R) +#define KC_S_ LCTL_T(KC_S) +#define KC_T_ LSFT_T(KC_T) +// Layer toggles +#define KC_WM LT(WNDWMGR, WM_EXPOSEE) +#define KC_BSP_ LT(MOD_ARR, KC_BSPC) +#define KC_TAB_ LT(FUN_NUM, KC_TAB) +#define KC_D_ LT(SYMBOLS, KC_D) +#define KC_NAV LT(NAVIGAT, KC_NO) +// Right +// Home-row mods +#define KC_N_ RSFT_T(KC_N) +#define KC_E_ RCTL_T(KC_E) +#define KC_I_ RGUI_T(KC_I) +#define KC_O_ LALT_T(KC_O) +// Layer toggles +#define KC_ENT_ LT(FUN_NUM, KC_ENT) +#define KC_SPC_ LT(MOD_ARR, KC_SPC) +#define KC_ESC_ LT(COMPOSE, KC_ESC) +#define KC_H_ LT(SYMBOLS, KC_H) +// Window Manager +#define KC_GNM3 WM_GNOME_3 +#define KC_GNM4 WM_GNOME_40 +#define KC_OSX WM_OSX +#define KC_WIN WM_WIN_10 +#define KC_WM LT(WNDWMGR, WM_EXPOSEE) +#define KC_LFTD WM_LEFT_DESK +#define KC_RGTD WM_RGHT_DESK +#define KC_UPRD WM_UPPR_DESK +#define KC_LWRD WM_LOWR_DESK +// Compose +#define KC_AE RALT(KC_Q) +#define KC_SZ RALT(KC_S) +#define KC_EE RALT(KC_E) +#define KC_IE RALT(KC_I) +#define KC_UE RALT(KC_Y) +#define KC_OE RALT(KC_P) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* + * ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ + * │ Q │ W │ F │ P │ B │ │ J │ L │ U │ Y │ ; │ + * ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + * │ A │ R │ S │ T │ G │ │ M │ N │ E │ I │ O │ + * ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + * │ Z │ X │ C │ D │ V │ │ K │ H │ , │ . │ / │ + * └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ + * ┌───┐ ┌───┐ + * │GUI├───┐ ┌───┤Tab│ + * └───┤Bsp├───┐ ┌───┤ ├───┘ + * └───┤Esc│ │Ent├───┘ + * └───┘ └───┘ + */ + [COLEMAK] = LAYOUT_split_3x5_3( + KC_Q, KC_W, KC_F, KC_P, KC_B, KC_J, KC_L, KC_U, KC_Y, KC_SCLN, + KC_A_, KC_R_, KC_S_, KC_T_, KC_G, KC_M, KC_N_, KC_E_, KC_I_, KC_O_, + KC_Z, KC_X, KC_C, KC_D_, KC_V, KC_K, KC_H_, KC_COMM, KC_DOT, KC_SLSH, + KC_WM, KC_BSP_, KC_TAB_, KC_ENT_, KC_SPC_, KC_ESC_ + ), + + [MOD_ARR] = LAYOUT_split_3x5_3( + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, XXXX, XXXX, KC_CAPS, XXXX, KC_LEFT, KC_DOWN, KC_UP, KC_RIGHT,XXXX, + XXXX, XXXX, XXXX, KC_NAV, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, KC_DEL, XXXX, XXXX, XXXX, XXXX + ), + [NAVIGAT] = LAYOUT_split_3x5_3( + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, KC_HOME, KC_PGDN, KC_PGUP, KC_END, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX + ), + [FUN_NUM] = LAYOUT_split_3x5_3( + XXXX, KC_F4, KC_F3, KC_F2, KC_F1, XXXX, KC_7, KC_8, KC_9, KC_MINS, + XXXX, KC_F8, KC_F7, KC_F6, KC_F5, KC_QUOT, KC_4, KC_5, KC_6, KC_EQL, + XXXX, KC_F12, KC_F11, KC_F10, KC_F9, KC_GRV, KC_1, KC_2, KC_3, KC_BSLS, + XXXX, XXXX, XXXX, KC_0, KC_0, KC_DOT + ), + [SYMBOLS] = LAYOUT_split_3x5_3( + KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_UNDS, + KC_EXLM, XXXX, XXXX, XXXX, XXXX, KC_DQUO, XXXX, KC_LBRC, KC_RBRC, KC_PLUS, + XXXX, XXXX, XXXX, XXXX, XXXX, KC_TILD, XXXX, KC_LCBR, KC_RCBR, KC_PIPE, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX + ), + [COMPOSE] = LAYOUT_split_3x5_3( + KC_AE, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, KC_UE, KC_OE, + XXXX, XXXX, KC_SZ, XXXX, XXXX, XXXX, XXXX, KC_EE, KC_IE, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX + ), + [WNDWMGR] = LAYOUT_split_3x5_3( + KC_GNM3, KC_GNM4, KC_OSX, KC_WIN, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, KC_LFTD, KC_LWRD, KC_UPRD, KC_RGTD, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX + ) + /*[] = LAYOUT_split_3x5_3( + * XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + * XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + * XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, + * XXXX, XXXX, XXXX, XXXX, XXXX, XXXX + *) + */ +}; + +uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case LSFT_T(KC_T): + case RSFT_T(KC_N): + case LT(COMPOSE, KC_ESC): + return TAPPING_TERM_SFT; + default: + return TAPPING_TERM; + } +} + +bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case LT(COMPOSE, KC_ESC): + return true; + default: + return false; + } +} + +bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case LT(MOD_ARR, KC_BSPC): + return true; + default: + return false; + } +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + if (!process_caps_word(keycode, record)) { return false; } + + switch (keycode) { + case WM_GNOME_3: + if (record->event.pressed) { + window_manager=GNOME_3; + } + return false; + case WM_GNOME_40: + if (record->event.pressed) { + window_manager=GNOME_40; + } + return false; + case WM_OSX: + if (record->event.pressed) { + window_manager=OSX; + } + return false; + case WM_WIN_10: + if (record->event.pressed) { + window_manager=WIN_10; + } + return false; + case LT(WNDWMGR, WM_EXPOSEE): + if (record->tap.count && record->event.pressed) { + switch (window_manager) { + case GNOME_3 ... GNOME_40: + tap_code(KC_LGUI); + break; + case OSX: + register_code(KC_LCTL); + tap_code(KC_UP); + unregister_code(KC_LCTL); + break; + case WIN_10: + register_code(KC_LGUI); + tap_code(KC_TAB); + unregister_code(KC_LGUI); + break; + default: break; + } + return false; + } + break; + case WM_LEFT_DESK: + if (record->event.pressed) { + switch (window_manager) { + case GNOME_40: + register_code(KC_LGUI); + register_code(KC_LALT); + tap_code(KC_LEFT); + unregister_code(KC_LALT); + unregister_code(KC_LGUI); + break; + case OSX: + register_code(KC_LCTL); + tap_code(KC_LEFT); + unregister_code(KC_LCTL); + break; + case WIN_10: + register_code(KC_LCTL); + register_code(KC_LGUI); + tap_code(KC_LEFT); + unregister_code(KC_LGUI); + unregister_code(KC_LCTL); + break; + default: break; + } + return false; + } + break; + case WM_RGHT_DESK: + if (record->event.pressed) { + switch (window_manager) { + case GNOME_40: + register_code(KC_LGUI); + register_code(KC_LALT); + tap_code(KC_RGHT); + unregister_code(KC_LALT); + unregister_code(KC_LGUI); + break; + case OSX: + register_code(KC_LCTL); + tap_code(KC_RGHT); + unregister_code(KC_LCTL); + break; + case WIN_10: + register_code(KC_LCTL); + register_code(KC_LGUI); + tap_code(KC_RGHT); + unregister_code(KC_LGUI); + unregister_code(KC_LCTL); + break; + default: break; + } + return false; + } + break; + case WM_UPPR_DESK: + if (record->event.pressed) { + switch (window_manager) { + case GNOME_3: + register_code(KC_LCTL); + register_code(KC_LALT); + tap_code(KC_UP); + unregister_code(KC_LALT); + unregister_code(KC_LCTL); + break; + default: break; + } + return false; + } + break; + case WM_LOWR_DESK: + if (record->event.pressed) { + switch (window_manager) { + case GNOME_3: + register_code(KC_LCTL); + register_code(KC_LALT); + tap_code(KC_DOWN); + unregister_code(KC_LALT); + unregister_code(KC_LCTL); + break; + default: break; + } + return false; + } + break; + } + return true; +} diff --git a/keyboards/chocofi/keymaps/dtk35/rules.mk b/keyboards/chocofi/keymaps/dtk35/rules.mk new file mode 100644 index 000000000000..b96aa6452d3f --- /dev/null +++ b/keyboards/chocofi/keymaps/dtk35/rules.mk @@ -0,0 +1 @@ +SRC += features/caps_word.c diff --git a/keyboards/chocofi/keymaps/lncblrmn/keymap.c b/keyboards/chocofi/keymaps/lncblrmn/keymap.c new file mode 100644 index 000000000000..c1d8ab5bf0a4 --- /dev/null +++ b/keyboards/chocofi/keymaps/lncblrmn/keymap.c @@ -0,0 +1,307 @@ +#include QMK_KEYBOARD_H + +#include "oneshot.h" +#include "swapper.h" + +#define LA_NUM MO(NUM) +#define LA_NAV MO(NAV) +#define LA_SYM MO(SYM) +#define LA_FUN MO(FUN) +#define XXXX KC_NO + +enum layers { + BASE, + NAV, + SYM, + NUM, + FUN, +}; + +enum keycodes { + // Macros + MR_FW = SAFE_RANGE, + MR_BW, + MR_ST, + MR_NT, + MR_X, + MR_C, + MR_V, + MR_F, + MR_S, + + // Swapper + SW_WIN, + + // One Shot Keys + OS_SHFT, + OS_CTRL, + OS_ALT, + OS_CMD +}; + +enum { + // Tap Dance + TD_Z, + TD_T, +}; + +void dance_undo_finished(tap_dance_state_t *state, void *user_data) { + switch (state->count) { + case 1: + register_code(KC_LGUI); + register_code(KC_Z); + break; + case 2: + register_code(KC_LGUI); + register_code(KC_LSFT); + register_code(KC_Z); + break; + default: + break; + } +} + +void dance_undo_reset(tap_dance_state_t *state, void *user_data) { + switch (state->count) { + case 1: + unregister_code(KC_LGUI); + unregister_code(KC_Z); + break; + case 2: + unregister_code(KC_LGUI); + unregister_code(KC_LSFT); + unregister_code(KC_Z); + break; + default: + break; + } + reset_tap_dance(state); +} + +void dance_tab_finished(tap_dance_state_t *state, void *user_data) { + switch (state->count) { + case 1: + register_code(KC_LGUI); + register_code(KC_W); + break; + case 2: + register_code(KC_LGUI); + register_code(KC_LSFT); + register_code(KC_T); + break; + default: + break; + } +} + +void dance_tab_reset(tap_dance_state_t *state, void *user_data) { + switch (state->count) { + case 1: + unregister_code(KC_LGUI); + unregister_code(KC_W); + break; + case 2: + unregister_code(KC_LGUI); + unregister_code(KC_LSFT); + unregister_code(KC_T); + break; + default: + break; + } + reset_tap_dance(state); +} + +tap_dance_action_t tap_dance_actions[] = { + [TD_Z] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_undo_finished, dance_undo_reset), + [TD_T] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_tab_finished, dance_tab_reset), +}; + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + [BASE] = LAYOUT_split_3x5_3( + KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, + KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, + KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_QUOT, + LA_NUM, LA_NAV, KC_SPC, KC_ENT, LA_SYM, LA_FUN + ), + + [NUM] = LAYOUT_split_3x5_3( + XXXX, XXXX, KC_LT, KC_GT, XXXX, KC_EQL, KC_1, KC_2, KC_3, KC_PLUS, + OS_SHFT, OS_CTRL, OS_ALT, OS_CMD, KC_TAB, KC_ASTR, KC_4, KC_5, KC_6, KC_MINS, + XXXX, XXXX, XXXX, XXXX, XXXX, KC_0, KC_7, KC_8, KC_9, KC_SLSH, + XXXX, XXXX, KC_SPC, KC_ENT, XXXX, XXXX + ), + + [NAV] = LAYOUT_split_3x5_3( + KC_ESC, XXXX, SW_WIN, TD(TD_T),MR_NT, MR_F, KC_HOME, KC_UP, KC_END, KC_DEL, + OS_SHFT, OS_CTRL, OS_ALT, OS_CMD, KC_TAB, KC_WH_U, KC_LEFT, KC_DOWN, KC_RGHT, KC_BSPC, + TD(TD_Z),MR_X, MR_C, MR_V, KC_CAPS, KC_WH_D, MR_FW, MR_BW, XXXX, XXXX, + XXXX, XXXX, KC_SPC, KC_ENT, MR_ST, MR_S + ), + + [SYM] = LAYOUT_split_3x5_3( + KC_EXLM, KC_AT, KC_LT, KC_GT, KC_HASH, KC_EQL, KC_GRV, KC_DLR, KC_PERC, KC_PLUS, + OS_SHFT, OS_CTRL, OS_ALT, OS_CMD, KC_TAB, KC_ASTR, KC_LPRN, KC_LCBR, KC_LBRC, KC_MINS, + KC_CIRC, KC_UNDS, KC_BSLS, KC_PIPE, KC_AMPR, KC_QUES, KC_RPRN, KC_RCBR, KC_RBRC, KC_SLSH, + XXXX, XXXX, KC_SPC, KC_ENT, XXXX, XXXX + ), + + [FUN] = LAYOUT_split_3x5_3( + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, KC_F1, KC_F2, KC_F3, KC_F4, + OS_SHFT, OS_CTRL, OS_ALT, OS_CMD, XXXX, XXXX, KC_F5, KC_F6, KC_F7, KC_F8, + XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, KC_F9, KC_F10, KC_F11, KC_F12, + XXXX, XXXX, KC_SPC, KC_ENT, XXXX, XXXX + ), +}; + +bool is_oneshot_cancel_key(uint16_t keycode) { + switch (keycode) { + case LA_NUM: + case LA_NAV: + case LA_SYM: + case LA_FUN: + return true; + default: + return false; + } +} + +bool is_oneshot_ignored_key(uint16_t keycode) { + switch (keycode) { + case LA_NUM: + case LA_NAV: + case LA_SYM: + case LA_FUN: + case OS_SHFT: + case OS_CTRL: + case OS_ALT: + case OS_CMD: + return true; + default: + return false; + } +} + +bool sw_win_active = false; + +oneshot_state os_shft_state = os_up_unqueued; +oneshot_state os_ctrl_state = os_up_unqueued; +oneshot_state os_alt_state = os_up_unqueued; +oneshot_state os_cmd_state = os_up_unqueued; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + update_swapper( + &sw_win_active, KC_LGUI, KC_TAB, SW_WIN, + keycode, record + ); + + update_oneshot( + &os_shft_state, KC_LSFT, OS_SHFT, + keycode, record + ); + update_oneshot( + &os_ctrl_state, KC_LCTL, OS_CTRL, + keycode, record + ); + update_oneshot( + &os_alt_state, KC_LALT, OS_ALT, + keycode, record + ); + update_oneshot( + &os_cmd_state, KC_LCMD, OS_CMD, + keycode, record + ); + + switch (keycode) { + case MR_FW: + // Forward by word + if (record->event.pressed) { + register_code(KC_LALT); + register_code(KC_RIGHT); + } else { + unregister_code(KC_LALT); + unregister_code(KC_RIGHT); + } + break; + case MR_BW: + // Backward by word + if (record->event.pressed) { + register_code(KC_LALT); + register_code(KC_LEFT); + } else { + unregister_code(KC_LALT); + unregister_code(KC_LEFT); + } + break; + case MR_ST: + // Spotlight + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_SPC); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_SPC); + } + break; + case MR_NT: + // New tab + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_T); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_T); + } + break; + case MR_X: + // Cut + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_X); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_X); + } + break; + case MR_C: + // Copy + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_C); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_C); + } + break; + case MR_V: + // Paste + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_V); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_V); + } + break; + case MR_F: + // Find + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_F); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_F); + } + break; + case MR_S: + // Save + if (record->event.pressed) { + register_code(KC_LGUI); + register_code(KC_S); + } else { + unregister_code(KC_LGUI); + unregister_code(KC_S); + } + break; + } + return true; +} \ No newline at end of file diff --git a/keyboards/chocofi/keymaps/lncblrmn/oneshot.c b/keyboards/chocofi/keymaps/lncblrmn/oneshot.c new file mode 100644 index 000000000000..6fa514ba14da --- /dev/null +++ b/keyboards/chocofi/keymaps/lncblrmn/oneshot.c @@ -0,0 +1,57 @@ +#include "oneshot.h" + +void update_oneshot( + oneshot_state *state, + uint16_t mod, + uint16_t trigger, + uint16_t keycode, + keyrecord_t *record +) { + if (keycode == trigger) { + if (record->event.pressed) { + // Trigger keydown + if (*state == os_up_unqueued) { + register_code(mod); + } + *state = os_down_unused; + } else { + // Trigger keyup + switch (*state) { + case os_down_unused: + // If we didn't use the mod while trigger was held, queue it. + *state = os_up_queued; + break; + case os_down_used: + // If we did use the mod while trigger was held, unregister it. + *state = os_up_unqueued; + unregister_code(mod); + break; + default: + break; + } + } + } else { + if (record->event.pressed) { + if (is_oneshot_cancel_key(keycode) && *state != os_up_unqueued) { + // Cancel oneshot on designated cancel keydown. + *state = os_up_unqueued; + unregister_code(mod); + } + } else { + if (!is_oneshot_ignored_key(keycode)) { + // On non-ignored keyup, consider the oneshot used. + switch (*state) { + case os_down_unused: + *state = os_down_used; + break; + case os_up_queued: + *state = os_up_unqueued; + unregister_code(mod); + break; + default: + break; + } + } + } + } +} \ No newline at end of file diff --git a/keyboards/chocofi/keymaps/lncblrmn/oneshot.h b/keyboards/chocofi/keymaps/lncblrmn/oneshot.h new file mode 100644 index 000000000000..72e9b8fe8d93 --- /dev/null +++ b/keyboards/chocofi/keymaps/lncblrmn/oneshot.h @@ -0,0 +1,31 @@ +#pragma once + +#include QMK_KEYBOARD_H + +// Represents the four states a oneshot key can be in +typedef enum { + os_up_unqueued, + os_up_queued, + os_down_unused, + os_down_used, +} oneshot_state; + +// Custom oneshot mod implementation that doesn't rely on timers. If a mod is +// used while it is held it will be unregistered on keyup as normal, otherwise +// it will be queued and only released after the next non-mod keyup. +void update_oneshot( + oneshot_state *state, + uint16_t mod, + uint16_t trigger, + uint16_t keycode, + keyrecord_t *record +); + +// To be implemented by the consumer. Defines keys to cancel oneshot mods. +bool is_oneshot_cancel_key(uint16_t keycode); + +// To be implemented by the consumer. Defines keys to ignore when determining +// whether a oneshot mod has been used. Setting this to modifiers and layer +// change keys allows stacking multiple oneshot modifiers, and carrying them +// between layers. +bool is_oneshot_ignored_key(uint16_t keycode); \ No newline at end of file diff --git a/keyboards/chocofi/keymaps/lncblrmn/rules.mk b/keyboards/chocofi/keymaps/lncblrmn/rules.mk new file mode 100644 index 000000000000..a9b3b2fa01e1 --- /dev/null +++ b/keyboards/chocofi/keymaps/lncblrmn/rules.mk @@ -0,0 +1,2 @@ +SRC += oneshot.c +SRC += swapper.c \ No newline at end of file diff --git a/keyboards/chocofi/keymaps/lncblrmn/swapper.c b/keyboards/chocofi/keymaps/lncblrmn/swapper.c new file mode 100644 index 000000000000..c652bbb920e3 --- /dev/null +++ b/keyboards/chocofi/keymaps/lncblrmn/swapper.c @@ -0,0 +1,26 @@ +#include "swapper.h" + +void update_swapper( + bool *active, + uint16_t cmdish, + uint16_t tabish, + uint16_t trigger, + uint16_t keycode, + keyrecord_t *record +) { + if (keycode == trigger) { + if (record->event.pressed) { + if (!*active) { + *active = true; + register_code(cmdish); + } + register_code(tabish); + } else { + unregister_code(tabish); + // Don't unregister cmdish until some other key is hit or released. + } + } else if (*active) { + unregister_code(cmdish); + *active = false; + } +} \ No newline at end of file diff --git a/keyboards/chocofi/keymaps/lncblrmn/swapper.h b/keyboards/chocofi/keymaps/lncblrmn/swapper.h new file mode 100644 index 000000000000..44cf6e582e3a --- /dev/null +++ b/keyboards/chocofi/keymaps/lncblrmn/swapper.h @@ -0,0 +1,20 @@ +#pragma once + +#include QMK_KEYBOARD_H + +// Implements cmd-tab like behaviour on a single key. On first tap of trigger +// cmdish is held and tabish is tapped -- cmdish then remains held until some +// other key is hit or released. For example: +// +// trigger, trigger, a -> cmd down, tab, tab, cmd up, a +// nav down, trigger, nav up -> nav down, cmd down, tab, cmd up, nav up +// +// This behaviour is useful for more than just cmd-tab, hence: cmdish, tabish. +void update_swapper( + bool *active, + uint16_t cmdish, + uint16_t tabish, + uint16_t trigger, + uint16_t keycode, + keyrecord_t *record +); \ No newline at end of file diff --git a/keyboards/chocofi/readme.md b/keyboards/chocofi/readme.md new file mode 100644 index 000000000000..5d747817e8b1 --- /dev/null +++ b/keyboards/chocofi/readme.md @@ -0,0 +1,27 @@ +# chocofi + +![chocofi](imgur.com image replace me!) + +*A short description of the keyboard/project* + +* Keyboard Maintainer: [Pavel Glushkov](https://github.com/pashutk) +* Hardware Supported: *The PCBs, controllers supported* +* Hardware Availability: *Links to where you can find this hardware* + +Make example for this keyboard (after setting up your build environment): + + make chocofi:default + +Flashing example for this keyboard: + + make chocofi:default:flash + +See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). + +## Bootloader + +Enter the bootloader in 3 ways: + +* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard +* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead +* **Keycode in layout**: Press the key mapped to `RESET` if it is available diff --git a/keyboards/chocofi/rules.mk b/keyboards/chocofi/rules.mk new file mode 100644 index 000000000000..57b9fbe4c797 --- /dev/null +++ b/keyboards/chocofi/rules.mk @@ -0,0 +1,3 @@ +SPLIT_KEYBOARD = yes +MOUSEKEY_ENABLE = yes +TAP_DANCE_ENABLE = yes \ No newline at end of file diff --git a/lib/chibios b/lib/chibios index be44b3305f9a..d7b9d1c87f72 160000 --- a/lib/chibios +++ b/lib/chibios @@ -1 +1 @@ -Subproject commit be44b3305f9a9fe5f2f49a4e7b978db322dc463e +Subproject commit d7b9d1c87f724bd7c8cd1486d6d0dc3ba52e0d52 diff --git a/lib/chibios-contrib b/lib/chibios-contrib index 77cb0a4f7589..d1c2126d1cd8 160000 --- a/lib/chibios-contrib +++ b/lib/chibios-contrib @@ -1 +1 @@ -Subproject commit 77cb0a4f7589f89e724f5e6ecb1d76d514dd1212 +Subproject commit d1c2126d1cd867c50127da84425805e225df8555 diff --git a/lib/lufa b/lib/lufa index 549b97320d51..19a5d533f02a 160000 --- a/lib/lufa +++ b/lib/lufa @@ -1 +1 @@ -Subproject commit 549b97320d515bfca2f95c145a67bd13be968faa +Subproject commit 19a5d533f02a7b46eeadca99cc9699659cef7a60 diff --git a/lib/printf b/lib/printf index c2e3b4e10d28..d3b984684bb8 160000 --- a/lib/printf +++ b/lib/printf @@ -1 +1 @@ -Subproject commit c2e3b4e10d281e7f0f694d3ecbd9f320977288cc +Subproject commit d3b984684bb8a8bdc48cc7a1abecb93ce59bbe3e diff --git a/lib/vusb b/lib/vusb index 819dbc1e5d59..bdb53e4c043d 160000 --- a/lib/vusb +++ b/lib/vusb @@ -1 +1 @@ -Subproject commit 819dbc1e5d5926b17e27e00ca6d3d2988adae04e +Subproject commit bdb53e4c043d089279d9891b68bea77614cb97ee