From bef73f44aacf49d0969e3cdd6718b9a594d49066 Mon Sep 17 00:00:00 2001
From: Jakob Hærvig <10219471+jakobhaervig@users.noreply.github.com>
Date: Thu, 1 Jul 2021 19:12:19 +0200
Subject: [Keymap] Add haervig userspace and keymaps (#13362)

---
 users/haervig/config.h  |  19 ++++
 users/haervig/haervig.c | 234 ++++++++++++++++++++++++++++++++++++++
 users/haervig/haervig.h | 297 ++++++++++++++++++++++++++++++++++++++++++++++++
 users/haervig/readme.md |  11 ++
 users/haervig/rules.mk  |   5 +
 5 files changed, 566 insertions(+)
 create mode 100644 users/haervig/config.h
 create mode 100644 users/haervig/haervig.c
 create mode 100644 users/haervig/haervig.h
 create mode 100644 users/haervig/readme.md
 create mode 100644 users/haervig/rules.mk

(limited to 'users')

diff --git a/users/haervig/config.h b/users/haervig/config.h
new file mode 100644
index 0000000000..6a7d67737e
--- /dev/null
+++ b/users/haervig/config.h
@@ -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
diff --git a/users/haervig/haervig.c b/users/haervig/haervig.c
new file mode 100644
index 0000000000..d03b43edc1
--- /dev/null
+++ b/users/haervig/haervig.c
@@ -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;
+}
diff --git a/users/haervig/haervig.h b/users/haervig/haervig.h
new file mode 100644
index 0000000000..e0d47e4cc9
--- /dev/null
+++ b/users/haervig/haervig.h
@@ -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;
diff --git a/users/haervig/readme.md b/users/haervig/readme.md
new file mode 100644
index 0000000000..dc2ebbd13c
--- /dev/null
+++ b/users/haervig/readme.md
@@ -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.
\ No newline at end of file
diff --git a/users/haervig/rules.mk b/users/haervig/rules.mk
new file mode 100644
index 0000000000..e06647ff27
--- /dev/null
+++ b/users/haervig/rules.mk
@@ -0,0 +1,5 @@
+SRC += haervig.c
+
+ifeq ($(strip $(DANISH_ENABLE)), yes)
+    OPT_DEFS += -DDANISH_ENABLE
+endif
-- 
cgit v1.2.3