Atreus: German QWERTZ layout with Umlaute

Yesterday I received my Keyboardio Atreus and I created a Kaleidoscope based firmware for german input.

I did not modify the default layout, except swaping Z and Y and changing the individual key-codes for the german input. Umlaute can be produced if one double taps the according letter (e.g. uu for ü).

Maybe this is helpful to you. I would like to hear how you proceeded with german layouts on the Atreus.

-Sebastian


atreus-layout

atreus-layout-numrow

Here is my firmware:

/* -*- mode: c++ -*-
 * German keyboard QWERTZ layout with double tap for Umlaute (aa=ä, oo=ö, uu=ü, ss=ß, qq=@, ee=€)
 * for the Keyboardio Atreus (2020) keyboard.
 * Long pressing of x,c,v,s,a generates ctrl+x,... (qukeys).
 * 
 * Author: Sebastian Korn (2020-10-06)
 * Build environment: Arduino 1.8.13, keyboardio 1.99-0-beta, Kaleidoscope-Languages (2 Oct 2018)
 *
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */ 

#ifndef BUILD_INFORMATION
#define BUILD_INFORMATION "locally built"
#endif

#include "Kaleidoscope.h"
#include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-TapDance.h"
#include "Kaleidoscope-Qukeys.h"

/* Depends on library https://github.com/keyboardio/Kaleidoscope-Languages
 */
#include "Kaleidoscope-Languages.h"
#include "kaleidoscope/lang/de-qwertz.h"

#define MO(n) ShiftToLayer(n)
#define TG(n) LockLayer(n)

enum {
  MACRO_QWERTZ,
  MACRO_VERSION_INFO,
};

enum {
  QWERTZ,
  SHIFT,
  FUN,
  UPPER,
  NUMROW
};

// List of tap dance indices:
#define TD_a 0 // a or ä
#define TD_A 1 // a or ä
#define TD_o 2 // o or ö
#define TD_O 3 // o or ö
#define TD_u 4 // u or ü
#define TD_U 5 // u or ü
#define TD_S 6 // s or ß
#define TD_Q 7 // q or @
#define TD_E 8 // e or €

/* *INDENT-OFF* */
KEYMAPS(
  [QWERTZ] = KEYMAP_STACKED
  (
    TD(TD_Q),      Key_de_W,   TD(TD_E),       Key_de_R,         Key_de_T,
    TD(TD_a),      TD(TD_S),   Key_de_D,       Key_de_F,         Key_de_G,
    Key_de_Y,      Key_de_X,   Key_de_C,       Key_de_V,         Key_de_B,         Key_de_Backtick,
    Key_de_Escape, Key_de_Tab, Key_de_LeftGui, MO(SHIFT),        Key_de_Backspace, Key_de_LeftControl,

                      Key_de_Z,        TD(TD_u), Key_de_I,     TD(TD_o),      Key_de_P,
                      Key_de_H,        Key_de_J, Key_de_K,     Key_de_L,      Key_de_Semicolon,
    Key_de_Backslash, Key_de_N,        Key_de_M, Key_de_Comma, Key_de_Period, Key_de_Slash,
    Key_de_LeftAlt,   Key_de_Spacebar, MO(FUN),  Key_de_Minus, Key_de_Quote,  Key_de_Enter
  ),

  [SHIFT] = KEYMAP_STACKED
  (
    LSHIFT(Key_de_Q), LSHIFT(Key_de_W),   LSHIFT(Key_de_E), LSHIFT(Key_de_R), LSHIFT(Key_de_T),
    TD(TD_A),         LSHIFT(Key_de_S),   LSHIFT(Key_de_D), LSHIFT(Key_de_F), LSHIFT(Key_de_G),
    LSHIFT(Key_de_Y), LSHIFT(Key_de_X),   LSHIFT(Key_de_C), LSHIFT(Key_de_V), LSHIFT(Key_de_B), Key_de_Tilde,
    XXX,              LSHIFT(Key_de_Tab), XXX,              ___,              Key_de_Delete,    XXX,

                            LSHIFT(Key_de_Z),        TD(TD_U),         LSHIFT(Key_de_I),  TD(TD_O),           LSHIFT(Key_de_P),
                            LSHIFT(Key_de_H),        LSHIFT(Key_de_J), LSHIFT(Key_de_K),  LSHIFT(Key_de_L),   Key_de_Colon,
    Key_de_Pipe,            LSHIFT(Key_de_N),        LSHIFT(Key_de_M), Key_de_LessThan,   Key_de_GreaterThan, Key_de_QuestionMark,
    LSHIFT(Key_de_LeftAlt), LSHIFT(Key_de_Spacebar), XXX,              Key_de_Underscore, Key_de_DoubleQuote, LSHIFT(Key_de_Enter)
  ),

  [FUN] = KEYMAP_STACKED
  (
    Key_de_ExlamationMark, Key_de_At,           Key_de_UpArrow,   Key_de_Dollar,     Key_de_Percent,
    Key_de_LeftParen,      Key_de_LeftArrow,    Key_de_DownArrow, Key_de_RightArrow, Key_de_RightParen,
    Key_de_LeftBracket,    Key_de_RightBracket, Key_de_Hash,      Key_de_LeftCurly,  Key_de_RightCurly, Key_de_Circumflex,
    TG(UPPER),             Key_de_Insert,       Key_de_LeftGui,   Key_de_LeftShift,  Key_de_Delete,     Key_de_LeftControl,

                      Key_de_PageUp,         Key_de_7, Key_de_8,      Key_de_9, Key_de_Backspace,
                      Key_de_PageDown,       Key_de_4, Key_de_5,      Key_de_6, ___,
    Key_de_Ampersand, Key_de_KeypadMultiply, Key_de_1, Key_de_2,      Key_de_3, Key_de_Plus,
    Key_de_LeftAlt,   TG(NUMROW),            ___,      Key_de_Period, Key_de_0, Key_de_Equals
   ),

  [UPPER] = KEYMAP_STACKED
  (
    Key_de_Insert,         Key_de_Home,              Key_de_UpArrow,   Key_de_End,        Key_de_PageUp,
    Key_de_Delete,         Key_de_LeftArrow,         Key_de_DownArrow, Key_de_RightArrow, Key_de_PageDown,
    M(MACRO_VERSION_INFO), Consumer_VolumeIncrement, XXX,              XXX,               ___,             ___,
    MoveToLayer(QWERTZ),   Consumer_VolumeDecrement, ___,              ___,               ___,             ___,

         Key_de_UpArrow,   Key_de_F7,           Key_de_F8,          Key_de_F9,         Key_de_F10,
         Key_de_DownArrow, Key_de_F4,           Key_de_F5,          Key_de_F6,         Key_de_F11,
    ___, XXX,              Key_de_F1,           Key_de_F2,          Key_de_F3,         Key_de_F12,
    ___, ___,              MoveToLayer(QWERTZ), Key_de_PrintScreen, Key_de_ScrollLock, Consumer_PlaySlashPause
   ),

  [NUMROW] = KEYMAP_STACKED
  (
    Key_1,               Key_2,      Key_3, Key_4, Key_5,
    XXX,                 XXX,        XXX,   XXX,   XXX,
    XXX,                 XXX,        XXX,   XXX,   XXX,              XXX,
    MoveToLayer(QWERTZ), Key_de_Tab, XXX,   XXX,   Key_de_Backspace, XXX,

                  Key_6,                 Key_7,               Key_8,        Key_9,         Key_0,
                  XXX,                   XXX,                 XXX,          XXX,           XXX,
    Key_de_Slash, Key_de_KeypadMultiply, XXX,                 Key_de_Comma, Key_de_Period, Key_de_Plus,
    XXX,          Key_de_Spacebar,       MoveToLayer(QWERTZ), Key_de_Minus, XXX,           Key_de_Enter
   )
)
/* *INDENT-ON* */

KALEIDOSCOPE_INIT_PLUGINS(
  Qukeys,
  TapDance,
  Macros
);

const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
  switch (macroIndex) {
  case MACRO_QWERTZ:
    Layer.move(QWERTZ); // legancy code for compatibility
    break;
  case MACRO_VERSION_INFO:
    if (keyToggledOn(keyState)) {
      Macros.type(PSTR("Keyboardio Atreus - QUERTZ "));
      Macros.type(PSTR(BUILD_INFORMATION));
    }
    break;
  default:
    break;
  }

  return MACRO_NONE;
}

void tapDanceAction(uint8_t tap_dance_index, KeyAddr key_addr, uint8_t tap_count, kaleidoscope::plugin::TapDance::ActionType tap_dance_action) {
  switch (tap_dance_index) {
  case TD_a:
    return tapDanceActionKeys(tap_count, tap_dance_action, Key_de_A, Key_de_AUml);
  case TD_A:
    return tapDanceActionKeys(tap_count, tap_dance_action, LSHIFT(Key_de_A), LSHIFT(Key_de_AUml));
  case TD_o:
    return tapDanceActionKeys(tap_count, tap_dance_action, Key_de_O, Key_de_OUml);
  case TD_O:
    return tapDanceActionKeys(tap_count, tap_dance_action, LSHIFT(Key_de_O), LSHIFT(Key_de_OUml));
  case TD_u:
    return tapDanceActionKeys(tap_count, tap_dance_action, Key_de_U, Key_de_UUml);
  case TD_U:
    return tapDanceActionKeys(tap_count, tap_dance_action, LSHIFT(Key_de_U), LSHIFT(Key_de_UUml));
  case TD_E:
    return tapDanceActionKeys(tap_count, tap_dance_action, Key_de_E, Key_de_Euro);
  case TD_S:
    return tapDanceActionKeys(tap_count, tap_dance_action, Key_de_S, Key_de_SS);
  case TD_Q:
    return tapDanceActionKeys(tap_count, tap_dance_action, Key_de_Q, Key_de_At);
  } // end switch
}

void setup() {
  // see https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/device/keyboardio/Atreus2.h#L64-L73
  QUKEYS(
    //                    Qukey(layer, key_addr, alternate_key)
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 2), LCTRL(Key_de_C)),      // c copy
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 3), LCTRL(Key_de_V)),      // v paste
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 1), LCTRL(Key_de_X)),      // x cut
    kaleidoscope::plugin::Qukey(0, KeyAddr(1, 1), LCTRL(Key_de_S)),      // s save
    kaleidoscope::plugin::Qukey(0, KeyAddr(1, 0), LCTRL(Key_de_A)),      // a select all
    kaleidoscope::plugin::Qukey(0, KeyAddr(1, 3), LCTRL(Key_de_F)),      // f find
    kaleidoscope::plugin::Qukey(0, KeyAddr(0, 7), LCTRL(Key_de_Z)),      // z undo
    kaleidoscope::plugin::Qukey(0, KeyAddr(3, 0), LCTRL(Key_de_Y)),      // y redo
    kaleidoscope::plugin::Qukey(0, KeyAddr(1, 7), LCTRL(Key_de_H)),      // h search&replace
  )
  Qukeys.setHoldTimeout(1000);
  Qukeys.setOverlapThreshold(50);
  TapDance.time_out = 180; // default value is 200
  Kaleidoscope.setup();
}

void loop() {
  Kaleidoscope.loop();
}

(all bugfixes incorporated)

1 Like

I see you have your Qukeys definitions commented out because of repetitions. This is probably because Qukeys is registered last in KALEIDOSCOPE_INIT_PLUGINS(). It should be first, instead. With those four plugins, the best order is probably:

KALEIDOSCOPE_INIT_PLUGINS(
  Qukeys,
  TapDance,
  Macros,
  ShapeShifter
);
1 Like

Hi Michael, I tried your suggestion and it worked immediately. Thank you a lot!

Another bug is the backtick / tile issue. On a German keyboard, backtick is shift+tick.
When using ShapeShifter

#define Key_de_Tilde ALTGR(Key_RightBracket)
#define Key_de_Backtick LSHIFT(Key_Equals)

static const kaleidoscope::plugin::ShapeShifter::dictionary_t shape_shift_dictionary[] PROGMEM = {
  {Key_de_Backtick, Key_de_Tilde},
  {Key_NoKey, Key_NoKey},
};

it does not generate a tilde. Does anyone know how to solve this?

ShapeShifter doesn’t undo the shift modifier that’s being held, so you’re not just getting AltGr++ (Key_de_Plus == Key_RightBracket); you’re getting shift+AltGr++.

Ok so this is not suitable for my needs, thanks for clarifying.
I introduced a new shift layer to avoid ShifShaper.

How did you make the Keyboard Layout Pics?

Hello Werner,
I created a template on my own, as I could not find any vector files.
The forum does not allow vector file upload, but here is a template:

There are several SVG files in the keyboardio/Atreus-Legends repository.

1 Like

Hi

Thanks seko for the layout.

But i’ve a (timing) problem with the tapDanceActions. When a key combination with an tapdancekey is fast pressed in series like

sd

i get

sds
dd
sds

in result. Or at ‘as’ (e.g. typing ‘das’)

aas
ß
aas

I put the TapDance.time_out to 200/300, but the same result.

Is the result to reproduce? Or could it perhaps the combination between MacOS and Atreus?

I’m not quite sure how to interpret what you wrote here, but I’m guessing you’re seeing extra characters in the output when rolling over from a TapDance key to another key, or vice versa. Could that be the problem?

Or maybe just pressing the next key before the TapDance key times out?

Yes, that’s right, just pressing once ‘a’ ‘s’ (or ‘o’ ‘i’) within the timeout (180ms) and i get as output ‘asa’, ‘ß’ or ‘ss’ (‘oio’, ‘ii’), but not ‘as’ (‘oi’) as expected.

As in the documentation discribed, i thought within the timeout the time will be interrupted and the frist keypress will be typed and than the second keypress, witch is outlaying of the tapdance.

When a tap-dance key is pressed and released, and another key is hit before the timer expires, then the tap-dance key will trigger an action first, perform it, and only then will the firmware continue handling the interrupting key press. This is to preserve the order of keys pressed.

So, it’s only when you tap two different TapDance keys quickly that you see the problem?

If you’re familiar with GitHub, it would be great if you would submit an issue against Kaleidoscope for this. If not, I can do it later. I’m planning a rewrite of TapDance in the near future, and want to make sure all the known bugs are addressed.

In every case when the first tap is a TapDance.

I’ll try to submit an understandable issue on GitHub. But i think, there is allready on kind of the Issue, where the issue get in:

I hope, these works. Thanks.

2 Likes

Hi Matthias,
you are welcome. I had similar issues but could minimize them by removing the custom qukey and tabdance timing settings. But I can confirm your observation.

@Kompost, thanks for the bug report. I’m on it, but it might take a while to get fixed, I’m afraid. I did see some of the behaviour you described, but not all of it. It might help if you could share your whole sketch, as other plugins might be involved in producing the output you see.

In my tests i’ve only the addon tapDance active. I’ll build a sketch, where we could reproduce the issue and post it on GitHub in the issue. Will be some kind of off topic in this thread.

On topic:
I’ve replaced in the sketch from @seko the addon tapDance with Qukeys. I’ve remove the useful Qukeys for copy&paste and replace it with (quick) Qukeys for the umlauts:

void setup() {
  QUKEYS(
    kaleidoscope::plugin::Qukey(0, KeyAddr(1,  0), Key_de_AUml),            // ä
    kaleidoscope::plugin::Qukey(1, KeyAddr(1,  0), LSHIFT(Key_de_AUml)),    // Ä
    kaleidoscope::plugin::Qukey(0, KeyAddr(0,  8), Key_de_UUml),            // ü
    kaleidoscope::plugin::Qukey(1, KeyAddr(0,  8), LSHIFT(Key_de_UUml)),    // Ü
    kaleidoscope::plugin::Qukey(0, KeyAddr(0, 10), Key_de_OUml),            // ä
    kaleidoscope::plugin::Qukey(1, KeyAddr(0, 10), LSHIFT(Key_de_OUml)),    // Ä
    kaleidoscope::plugin::Qukey(0, KeyAddr(1,  1), Key_de_SS),              // ß
  )
  Qukeys.setHoldTimeout(250);
  Qukeys.setOverlapThreshold(80);
  Qukeys.setMinimumHoldTime(50);
  Kaleidoscope.setup();
}

The default timing of the addon Qukeys works fine for me. Perhaps the setHoldTimeout could be reduce, if speed typing is preferred.
I think there is no way for different timeouts for different KeyAddr in Qukeys?

MfG

There isn’t currently a way to set different hold timeouts for individual qukeys. I’m concerned about the amount of space that would take in the firmware, both for the qukey objects themselves (an extra two bytes per qukey), and the extra code to handle the override. It’s not out of the question, but since the primary use of Qukeys is for modifiers, the hold timeout doesn’t matter much for most people, since it’s not what gets used to determine the value of the qukey. If you want this feature, do feel free to submit an issue to Kaleidoscope in GitHub; it might get added, but I make no promises.

For your configuration above, my guess is that 250ms is rather high; it’s unlikely that a tap lasts more than ~100ms, so I would encourage you to try a lower hold timeout and see what that feels like.

Thanks @Kompost for the inspiration. I removed TapDance as well, as I had too much struggle to get the correct tap count.

Here is my latest setup:

/* -*- mode: c++ -*-
 * German keyboard QWERTZ layout with hold for Umlaute (a=ä, o=ö, u=ü, s=ß, q=@, e=€)
 * for the Keyboardio Atreus (2020) keyboard.
 * 
 * Author: Sebastian Korn (2020-10-14)
 * Build environment: Arduino 1.8.13, keyboardio 1.99-2-beta, Kaleidoscope-Languages (2 Oct 2018)
 *
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */ 

#ifndef BUILD_INFORMATION
#define BUILD_INFORMATION "locally built"
#endif

#include "Kaleidoscope.h"
#include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-Qukeys.h"

/* Depends on library https://github.com/keyboardio/Kaleidoscope-Languages
 */
#include "Kaleidoscope-Languages.h"
#include "kaleidoscope/lang/de-qwertz.h"

#define MO(n) ShiftToLayer(n)
#define TG(n) LockLayer(n)

enum {
  MACRO_QWERTZ,
  MACRO_VERSION_INFO,
};

enum {
  QWERTZ,
  SHIFT,
  FUN,
  UPPER,
  NUMROW
};

/* *INDENT-OFF* */
KEYMAPS(
  [QWERTZ] = KEYMAP_STACKED
  (
    Key_de_Q,      Key_de_W,   Key_de_E,       Key_de_R,         Key_de_T,
    Key_de_A,   Key_de_S,   Key_de_D,       Key_de_F,         Key_de_G,
    Key_de_Y,      Key_de_X,   Key_de_C,       Key_de_V,         Key_de_B,         Key_de_Backtick,
    Key_de_Escape, Key_de_Tab, Key_de_LeftGui, MO(SHIFT),        Key_de_Backspace, Key_de_LeftControl,

                      Key_de_Z,        Key_de_U, Key_de_I,     Key_de_O,      Key_de_P,
                      Key_de_H,        Key_de_J, Key_de_K,     Key_de_L,      Key_de_Semicolon,
    Key_de_Backslash, Key_de_N,        Key_de_M, Key_de_Comma, Key_de_Period, Key_de_Slash,
    Key_de_LeftAlt,   Key_de_Spacebar, MO(FUN),  Key_de_Minus, Key_de_Quote,  Key_de_Enter
  ),

  [SHIFT] = KEYMAP_STACKED
  (
    LSHIFT(Key_de_Q), LSHIFT(Key_de_W),   LSHIFT(Key_de_E), LSHIFT(Key_de_R), LSHIFT(Key_de_T),
    LSHIFT(Key_de_A),         LSHIFT(Key_de_S),   LSHIFT(Key_de_D), LSHIFT(Key_de_F), LSHIFT(Key_de_G),
    LSHIFT(Key_de_Y), LSHIFT(Key_de_X),   LSHIFT(Key_de_C), LSHIFT(Key_de_V), LSHIFT(Key_de_B), Key_de_Tilde,
    XXX,              LSHIFT(Key_de_Tab), XXX,              ___,              Key_de_Delete,    XXX,

                            LSHIFT(Key_de_Z),        LSHIFT(Key_de_U),         LSHIFT(Key_de_I),  LSHIFT(Key_de_O),           LSHIFT(Key_de_P),
                            LSHIFT(Key_de_H),        LSHIFT(Key_de_J), LSHIFT(Key_de_K),  LSHIFT(Key_de_L),   Key_de_Colon,
    Key_de_Pipe,            LSHIFT(Key_de_N),        LSHIFT(Key_de_M), Key_de_LessThan,   Key_de_GreaterThan, Key_de_QuestionMark,
    LSHIFT(Key_de_LeftAlt), LSHIFT(Key_de_Spacebar), XXX,              Key_de_Underscore, Key_de_DoubleQuote, LSHIFT(Key_de_Enter)
  ),

  [FUN] = KEYMAP_STACKED
  (
    Key_de_ExlamationMark, Key_de_At,           Key_de_UpArrow,   Key_de_Dollar,     Key_de_Percent,
    Key_de_LeftParen,      Key_de_LeftArrow,    Key_de_DownArrow, Key_de_RightArrow, Key_de_RightParen,
    Key_de_LeftBracket,    Key_de_RightBracket, Key_de_Hash,      Key_de_LeftCurly,  Key_de_RightCurly, Key_de_Circumflex,
    TG(UPPER),             Key_de_Insert,       Key_de_LeftGui,   Key_de_LeftShift,  Key_de_Delete,     Key_de_LeftControl,

                      Key_de_PageUp,         Key_de_7, Key_de_8,      Key_de_9, Key_de_Backspace,
                      Key_de_PageDown,       Key_de_4, Key_de_5,      Key_de_6, ___,
    Key_de_Ampersand, Key_de_KeypadMultiply, Key_de_1, Key_de_2,      Key_de_3, Key_de_Plus,
    Key_de_LeftAlt,   TG(NUMROW),            ___,      Key_de_Period, Key_de_0, Key_de_Equals
   ),

  [UPPER] = KEYMAP_STACKED
  (
    Key_de_Insert,         Key_de_Home,              Key_de_UpArrow,   Key_de_End,        Key_de_PageUp,
    Key_de_Delete,         Key_de_LeftArrow,         Key_de_DownArrow, Key_de_RightArrow, Key_de_PageDown,
    M(MACRO_VERSION_INFO), Consumer_VolumeIncrement, XXX,              XXX,               ___,             ___,
    MoveToLayer(QWERTZ),   Consumer_VolumeDecrement, ___,              ___,               ___,             ___,

         Key_de_UpArrow,   Key_de_F7,           Key_de_F8,          Key_de_F9,         Key_de_F10,
         Key_de_DownArrow, Key_de_F4,           Key_de_F5,          Key_de_F6,         Key_de_F11,
    ___, XXX,              Key_de_F1,           Key_de_F2,          Key_de_F3,         Key_de_F12,
    ___, ___,              MoveToLayer(QWERTZ), Key_de_PrintScreen, Key_de_ScrollLock, Consumer_PlaySlashPause
   ),

  [NUMROW] = KEYMAP_STACKED
  (
    Key_1,               Key_2,      Key_3, Key_4, Key_5,
    XXX,                 XXX,        XXX,   XXX,   XXX,
    XXX,                 XXX,        XXX,   XXX,   XXX,              XXX,
    MoveToLayer(QWERTZ), Key_de_Tab, XXX,   XXX,   Key_de_Backspace, XXX,

                  Key_6,                 Key_7,               Key_8,        Key_9,         Key_0,
                  XXX,                   XXX,                 XXX,          XXX,           XXX,
    Key_de_Slash, Key_de_KeypadMultiply, XXX,                 Key_de_Comma, Key_de_Period, Key_de_Plus,
    XXX,          Key_de_Spacebar,       MoveToLayer(QWERTZ), Key_de_Minus, XXX,           Key_de_Enter
   )
)
/* *INDENT-ON* */

KALEIDOSCOPE_INIT_PLUGINS(
  Qukeys,
  Macros
);

const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
  switch (macroIndex) {
  case MACRO_QWERTZ:
    Layer.move(QWERTZ); // legancy code for compatibility
    break;
  case MACRO_VERSION_INFO:
    if (keyToggledOn(keyState)) {
      Macros.type(PSTR("Keyboardio Atreus - QUERTZ "));
      Macros.type(PSTR(BUILD_INFORMATION));
    }
    break;
  default:
    break;
  }

  return MACRO_NONE;
}

void setup() {
  // see https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/device/keyboardio/Atreus2.h#L64-L73
  QUKEYS(
    //                    Qukey(layer, key_addr, alternate_key)
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(1, 1), Key_de_SS),            // s ß
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(1, 0), Key_de_AUml),          // a ä
    kaleidoscope::plugin::Qukey(SHIFT,  KeyAddr(1, 0), LSHIFT(Key_de_AUml)),  // A Ae
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(0, 10), Key_de_OUml),         // o ö
    kaleidoscope::plugin::Qukey(SHIFT,  KeyAddr(0, 10), LSHIFT(Key_de_OUml)), // o Oe
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(0, 8), Key_de_UUml),          // u ü
    kaleidoscope::plugin::Qukey(SHIFT,  KeyAddr(0, 8), LSHIFT(Key_de_UUml)),  // U Ue
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(0, 0), Key_de_At),            // q @
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(0, 2), Key_de_Euro),          // e €

    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(2, 2), LCTRL(Key_de_C)),      // c copy
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(2, 3), LCTRL(Key_de_V)),      // v paste
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(2, 1), LCTRL(Key_de_X)),      // x cut
    
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(1, 3), LCTRL(Key_de_F)),      // f find
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(0, 7), LCTRL(Key_de_Z)),      // z undo
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(3, 0), LCTRL(Key_de_Y)),      // y redo
    
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(1, 7), LCTRL(Key_de_H)),      // h search&replace
    kaleidoscope::plugin::Qukey(QWERTZ, KeyAddr(0, 11), LCTRL(Key_de_P)),     // p print
  )
  // you may want to tweak those to your needs:
  //Qukeys.setHoldTimeout(1000); // default is 250
  //Qukeys.setOverlapThreshold(80) // default is 80
  Kaleidoscope.setup();
}

void loop() {
  Kaleidoscope.loop();
}