@ -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 |