@ -0,0 +1,36 @@ | |||||
/* | |||||
Copyright 2021 Jakob Hærvig <jakob.haervig@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 QMK_KEYBOARD_H | |||||
#include "haervig.h" | |||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||||
[0] = LAYOUT_65_ansi( | |||||
KC_GESC, DK_1, CU_2, DK_3, CU_4, DK_5, CU_6, CU_7, CU_8, CU_9, CU_0, CU_MINS, CU_EQL, CU_BSPC, KC_HOME, | |||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, CU_LBRC, CU_RBRC, CU_BSLS, KC_PGUP, | |||||
CTL_T(KC_CAPS), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, CU_SCLN, CU_QUOT, KC_ENT, KC_PGDN, | |||||
CU_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, CU_COMM, CU_DOT, CU_SLSH, CU_RSFT, KC_UP, KC_END, | |||||
KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, MO(1), KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT | |||||
), | |||||
[1] = LAYOUT_65_ansi( | |||||
_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, | |||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______ | |||||
) | |||||
}; |
@ -0,0 +1,3 @@ | |||||
# Userspace defines | |||||
DANISH_ENABLE = yes # Enable Custom US Ansi Keycodes for PC with Danish set as input language | |||||
RGB_MATRIX_ENABLE = no # Disable the ugly RGB light |
@ -0,0 +1,19 @@ | |||||
/* | |||||
Copyright 2021 Jakob Hærvig <jakob.haervig@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 | |||||
#define TAPPING_TERM 200 |
@ -0,0 +1,234 @@ | |||||
/* | |||||
Copyright 2021 Jakob Hærvig <jakob.haervig@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 "haervig.h" | |||||
#ifdef DANISH_ENABLE | |||||
// These indicate if left and right shift are physically pressed | |||||
bool lshift = false; | |||||
bool rshift = false; | |||||
// Interrupt and times for space cadet shift | |||||
bool lshiftp = false; | |||||
bool rshiftp = false; | |||||
uint16_t lshift_timer = 0; | |||||
uint16_t rshift_timer = 0; | |||||
// Number of items that are saved in prev_kcs | |||||
uint8_t prev_indx = 0; | |||||
// Used to save the last 6 actual keycodes activated by frankenkeycodes | |||||
uint16_t prev_kcs[6] = {0, 0, 0, 0, 0, 0}; | |||||
// If true the deadkey characters grave and circonflexe are not automatically escaped | |||||
bool esct = false; | |||||
/* | |||||
Used to add a keycode to a prev_kcs to remember it. | |||||
When full the last code gets discarded and replaced by | |||||
the new one. | |||||
*/ | |||||
void add_to_prev(uint16_t kc){ | |||||
for (int i=0; i<prev_indx; i++){ | |||||
if (kc == prev_kcs[i]) | |||||
return; | |||||
} | |||||
if (prev_indx == 6){ | |||||
for (int i=5; i>0; i--){ | |||||
prev_kcs[i] = prev_kcs[i-1]; | |||||
} | |||||
prev_kcs[0] = kc; | |||||
} else { | |||||
prev_kcs[prev_indx] = kc; | |||||
prev_indx++; | |||||
} | |||||
} | |||||
/* | |||||
Unregisters all codes saved in prev_kcs and resets prev_indx. | |||||
gets called on multiple occasions mainly when shift is released | |||||
and when frankenkeycodes are pressed. Prevents output of | |||||
wrong characters when really specific key combinations | |||||
that would never occur during normal usage are pressed. | |||||
*/ | |||||
void unreg_prev(void){ | |||||
if (prev_indx == 0) | |||||
return; | |||||
for (int i=0; i<prev_indx; i++){ | |||||
unregister_code(prev_kcs[i]); | |||||
} | |||||
prev_indx = 0; | |||||
} | |||||
#endif | |||||
// Interrupt and times for Nav/Esc | |||||
bool navesc = false; | |||||
uint16_t navesc_timer = 0; | |||||
// Interrupts all timers | |||||
void timer_timeout(void){ | |||||
#ifdef DANISH_ENABLE | |||||
lshiftp = false; | |||||
rshiftp = false; | |||||
#endif | |||||
navesc = false; | |||||
timer_timeout_keymap(); | |||||
} | |||||
__attribute__((weak)) | |||||
void timer_timeout_keymap(void){ | |||||
} | |||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) { | |||||
switch (keycode) { | |||||
case KC_LGUI: | |||||
case KC_RGUI: | |||||
if (record->event.pressed) | |||||
timer_timeout(); | |||||
return true; | |||||
case CU_NAV: | |||||
if(record->event.pressed) { | |||||
navesc = true; | |||||
navesc_timer = timer_read(); | |||||
layer_on(_NAV); | |||||
} else { | |||||
if (timer_elapsed(navesc_timer) < TAPPING_TERM && navesc) { | |||||
tap_code(KC_ESC); | |||||
} | |||||
layer_off(_NAV); | |||||
} | |||||
return false; | |||||
#ifdef DANISH_ENABLE | |||||
case CU_LSFT: | |||||
if(record->event.pressed) { | |||||
lshiftp = true; | |||||
lshift_timer = timer_read(); | |||||
unregister_code(KC_LSFT); | |||||
register_code(KC_LSFT); | |||||
lshift = true; | |||||
} else { | |||||
if (timer_elapsed(lshift_timer) < TAPPING_TERM && lshiftp) { | |||||
register_code(KC_LSFT); | |||||
tap_code(KC_8); | |||||
unregister_code(KC_LSFT); | |||||
} | |||||
unreg_prev(); | |||||
if (!rshift) | |||||
unregister_code(KC_LSFT); | |||||
lshift = false; | |||||
} | |||||
return false; | |||||
case CU_RSFT: | |||||
if(record->event.pressed) { | |||||
rshiftp = true; | |||||
rshift_timer = timer_read(); | |||||
unregister_code(KC_LSFT); | |||||
register_code(KC_LSFT); | |||||
rshift = true; | |||||
} else { | |||||
if (timer_elapsed(rshift_timer) < TAPPING_TERM && rshiftp) { | |||||
register_code(KC_LSFT); | |||||
tap_code(KC_9); | |||||
unregister_code(KC_LSFT); | |||||
} | |||||
unreg_prev(); | |||||
if (!lshift) | |||||
unregister_code(KC_LSFT); | |||||
rshift = false; | |||||
} | |||||
return false; | |||||
case CU_COMM: | |||||
SHIFT_NO(DK_COMM, KC_GRV) | |||||
case CU_DOT: | |||||
SHIFT_NORM(DK_DOT, KC_GRV) | |||||
case CU_SLSH: | |||||
SHIFT_ALL(DK_7, KC_MINS) | |||||
case CU_SCLN: | |||||
SHIFT_ALL(DK_COMM, DK_DOT) | |||||
case CU_QUOT: | |||||
SHIFT_NORM(DK_QUOT, DK_2) | |||||
case CU_2: | |||||
NORM_ALGR(DK_2, KC_NUHS) | |||||
case CU_4: | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
if (lshift || rshift) { \ | |||||
register_code(KC_LSFT); \ | |||||
register_code(KC_ALGR); \ | |||||
unregister_code(KC_3); \ | |||||
tap_code(KC_3); \ | |||||
unregister_code(KC_3); \ | |||||
} else { \ | |||||
unregister_code(KC_4); \ | |||||
tap_code(KC_4); \ | |||||
} \ | |||||
unregister_code(KC_ALGR); \ | |||||
unregister_code(KC_LSFT); \ | |||||
} \ | |||||
return false; | |||||
case CU_6: | |||||
SHIFT_NORM(DK_6, KC_RBRC) | |||||
case CU_7: | |||||
SHIFT_NORM(DK_7, DK_6) | |||||
case CU_8: | |||||
SHIFT_NORM(DK_8, KC_NUHS) | |||||
case CU_9: | |||||
SHIFT_NORM(DK_9, DK_8) | |||||
case CU_0: | |||||
SHIFT_NORM(DK_0, DK_9) | |||||
case CU_MINS: | |||||
SHIFT_NORM(KC_SLSH, KC_SLSH) | |||||
case CU_EQL: | |||||
SHIFT_SWITCH(DK_0, DK_PLUS) | |||||
case CU_BSPC: | |||||
SHIFT_NO(KC_BSPC, KC_DEL) | |||||
case CU_LBRC: | |||||
NORM_ALGRSHIFT(DK_8, DK_8) | |||||
case CU_RBRC: | |||||
NORM_ALGRSHIFT(DK_9, DK_9) | |||||
case CU_BSLS: | |||||
ALGR_SWITCH(DK_7, DK_I) | |||||
case KC_LCTL: | |||||
case KC_RCTL: | |||||
if(!record->event.pressed) { | |||||
timer_timeout(); | |||||
unregister_code(KC_Z); | |||||
unregister_code(KC_Y); | |||||
} | |||||
return true; | |||||
#endif | |||||
default: | |||||
if(record->event.pressed) { | |||||
timer_timeout(); | |||||
#ifdef DANISH_ENABLE | |||||
if (lshift || rshift) | |||||
register_code(KC_LSFT); | |||||
else | |||||
unregister_code(KC_LSFT); | |||||
#endif | |||||
} | |||||
return process_record_keymap(keycode, record); | |||||
} | |||||
} | |||||
__attribute__((weak)) | |||||
bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { | |||||
return true; | |||||
} |
@ -0,0 +1,297 @@ | |||||
/* | |||||
Copyright 2021 Jakob Hærvig <jakob.haervig@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 "quantum.h" | |||||
#include "keymap_danish.h" | |||||
enum userspace_layers { | |||||
_DEADKEY = 14, // Change if more than 16 layers are required | |||||
_NAV | |||||
}; | |||||
enum userspace_custom_keycodes { | |||||
//CU_GAME = SAFE_RANGE, // Toggle game mode on/off | |||||
CU_NAV = SAFE_RANGE, // NAV | ESC | |||||
#ifdef DANISH_ENABLE | |||||
CU_LSFT, // LSFT | ( | |||||
CU_RSFT, // LSFT | ) | |||||
CU_COMM, // , | < | |||||
CU_DOT, // . | > | |||||
CU_SLSH, // / | ? | |||||
CU_SCLN, // ; | : | |||||
CU_QUOT, // ' | " | |||||
CU_2, // 2 | @ | |||||
CU_4, // 4 | $ | |||||
CU_6, // 6 | ^ | |||||
CU_7, // 7 | & | |||||
CU_8, // 8 | * | |||||
CU_9, // 9 | ( | |||||
CU_0, // 0 | ) | |||||
CU_MINS, // - | _ | |||||
CU_EQL, // = | + | |||||
CU_BSPC, // backspace | delete | |||||
CU_LBRC, // [ | { | |||||
CU_RBRC, // ] | } | |||||
CU_BSLS, // \ | | | |||||
#endif | |||||
NEW_SAFE_RANGE // Use for keymap specific keycodes | |||||
}; | |||||
#ifdef DANISH_ENABLE | |||||
extern bool lshift; | |||||
extern bool rshift; | |||||
extern bool lshiftp; | |||||
extern bool rshiftp; | |||||
extern uint16_t lshift_timer; | |||||
extern uint16_t rshift_timer; | |||||
extern uint8_t prev_indx; | |||||
extern uint16_t prev_kcs[6]; | |||||
void add_to_prev(uint16_t kc); | |||||
void unreg_prev(void); | |||||
extern bool esct; | |||||
#endif | |||||
extern bool navesc; | |||||
extern uint16_t navesc_timer; | |||||
void timer_timeout(void); | |||||
void timer_timeout_keymap(void); | |||||
bool process_record_keymap(uint16_t keycode, keyrecord_t *record); | |||||
#define CTRLX LCTL(KC_X) | |||||
#define CTRLC LCTL(KC_C) | |||||
#define CTRLV LCTL(KC_V) | |||||
#define ALTF4 LALT(KC_F4) | |||||
#define GUIU LGUI(KC_UP) | |||||
#define GUID LGUI(KC_DOWN) | |||||
#define GUIL LGUI(KC_LEFT) | |||||
#define GUIR RGUI(KC_RIGHT) | |||||
#define CTLENT CTL_T(KC_ENT) | |||||
#define EMOJI LWIN(KC_DOT) | |||||
/* | |||||
Templates for Keys, with custom shifted and non shifted Characters | |||||
*/ | |||||
// Normal shift status | |||||
#define SHIFT_NORM(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
if (lshift || rshift) { \ | |||||
register_code(KC_LSFT); \ | |||||
unregister_code(kc2); \ | |||||
register_code(kc2); \ | |||||
add_to_prev(kc2); \ | |||||
} else { \ | |||||
unregister_code(KC_LSFT); \ | |||||
unregister_code(kc1); \ | |||||
register_code(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
} \ | |||||
return false; | |||||
// Inverted shift status | |||||
#define SHIFT_SWITCH(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
if (lshift || rshift) { \ | |||||
unregister_code(KC_LSFT); \ | |||||
unregister_code(kc2); \ | |||||
register_code(kc2); \ | |||||
add_to_prev(kc2); \ | |||||
} else { \ | |||||
register_code(KC_LSFT); \ | |||||
unregister_code(kc1); \ | |||||
register_code(kc1); \ | |||||
add_to_prev(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
unreg_prev(); \ | |||||
if (lshift || rshift) \ | |||||
register_code(KC_LSFT); \ | |||||
else \ | |||||
unregister_code(KC_LSFT); \ | |||||
} \ | |||||
return false; | |||||
// Always shifted | |||||
#define SHIFT_ALL(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
register_code(KC_LSFT); \ | |||||
if (lshift || rshift) { \ | |||||
tap_code(kc2); \ | |||||
add_to_prev(kc2); \ | |||||
} else { \ | |||||
tap_code(kc1); \ | |||||
add_to_prev(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
unreg_prev(); \ | |||||
if (lshift || rshift) \ | |||||
register_code(KC_LSFT); \ | |||||
else \ | |||||
unregister_code(KC_LSFT); \ | |||||
} \ | |||||
return false; | |||||
// Never shifted | |||||
#define SHIFT_NO(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
unregister_code(KC_LSFT); \ | |||||
if (lshift || rshift) { \ | |||||
tap_code(kc2); \ | |||||
add_to_prev(kc2); \ | |||||
} else { \ | |||||
tap_code(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
unreg_prev(); \ | |||||
if (lshift || rshift) \ | |||||
register_code(KC_LSFT); \ | |||||
else \ | |||||
unregister_code(KC_LSFT); \ | |||||
} \ | |||||
return false; | |||||
// Norm AltGr | |||||
#define NORM_ALGR(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
if (lshift || rshift) { \ | |||||
register_code(KC_ALGR); \ | |||||
unregister_code(KC_LSFT); \ | |||||
tap_code(kc2); \ | |||||
unregister_code(KC_ALGR); \ | |||||
} else { \ | |||||
unregister_code(KC_ALGR); \ | |||||
unregister_code(KC_LSFT); \ | |||||
tap_code(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
} \ | |||||
return false; | |||||
// Norm AltGr shift | |||||
#define NORM_ALGRSHIFT(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
register_code(KC_LSFT); \ | |||||
register_code(KC_ALGR); \ | |||||
if (lshift || rshift) { \ | |||||
unregister_code(kc2); \ | |||||
tap_code(kc2); \ | |||||
unregister_code(KC_LSFT); \ | |||||
} else { \ | |||||
unregister_code(KC_LSFT); \ | |||||
unregister_code(kc1); \ | |||||
register_code(kc1); \ | |||||
} \ | |||||
unregister_code(KC_ALGR); \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
} \ | |||||
return false; | |||||
// Inverted altgr status | |||||
#define ALGR_SWITCH(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
register_code(KC_ALGR); \ | |||||
if (lshift || rshift) { \ | |||||
unregister_code(KC_LSFT); \ | |||||
unregister_code(kc2); \ | |||||
register_code(kc2); \ | |||||
unregister_code(KC_ALGR); \ | |||||
add_to_prev(kc2); \ | |||||
} else { \ | |||||
register_code(KC_LSFT); \ | |||||
unregister_code(kc1); \ | |||||
register_code(kc1); \ | |||||
unregister_code(KC_ALGR); \ | |||||
add_to_prev(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
unreg_prev(); \ | |||||
if (lshift || rshift) \ | |||||
register_code(KC_LSFT); \ | |||||
else \ | |||||
unregister_code(KC_LSFT); \ | |||||
} \ | |||||
return false; | |||||
// Always AltGr | |||||
#define SHIFT_ALGR(kc1, kc2) \ | |||||
if (record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
unregister_code(KC_LSFT); \ | |||||
register_code(KC_ALGR); \ | |||||
if (lshift || rshift) { \ | |||||
unregister_code(kc2); \ | |||||
tap_code(kc2); \ | |||||
register_code(KC_LSFT); \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
tap_code(kc1); \ | |||||
} \ | |||||
unregister_code(KC_ALGR); \ | |||||
} \ | |||||
return false; | |||||
// Different keycode when Ctrl is pressed | |||||
#define CTRL(kc1, kc2) \ | |||||
if(record->event.pressed) { \ | |||||
timer_timeout(); \ | |||||
if (lshift || rshift) \ | |||||
register_code(KC_LSFT); \ | |||||
else \ | |||||
unregister_code(KC_LSFT); \ | |||||
if (keyboard_report->mods & (MOD_BIT(KC_LCTL) | MOD_BIT(KC_RCTL))){ \ | |||||
register_code(kc2); \ | |||||
} else { \ | |||||
register_code(kc1); \ | |||||
} \ | |||||
} else { \ | |||||
unregister_code(kc1); \ | |||||
unregister_code(kc2); \ | |||||
} \ | |||||
return false; |
@ -0,0 +1,11 @@ | |||||
# haervig Userspace | |||||
This userspace keeps my userdefined codes. I work on a ANSI keyboard on a Danish macOS system. I believe this code might be relevant for similar users. A big shout out to user spacebarracecar for the ideas on how to map keys, which served as the basis of this code. | |||||
## US Layout Keys for Danish PCs | |||||
By daily work involves a lot of coding. I find an ANSI layout superior and decided to buy a QMK keyboard. However, all PC's here in Denmark are set to input language Danish. Even though I could simply set input language language to US international, I find this inconvenient. I instead decided to map my keys so the ANSI keyboard would will function as expected when the OS inputn language is Danish. | |||||
## More details | |||||
Tracking the current state of the shift code is nessesary for it to work. User spacebarracecar has documented the idea thoroughly and should serve you as a starting point if you wish to implement this code. I modified the code to suit Danish input language. Additionally, a couple of functions were added to accomodate the altgr key. |
@ -0,0 +1,5 @@ | |||||
SRC += haervig.c | |||||
ifeq ($(strip $(DANISH_ENABLE)), yes) | |||||
OPT_DEFS += -DDANISH_ENABLE | |||||
endif |