German NEO layout variant


(Stefan Gojan) #1


Puh, after reading a lot in this forum I tried to make a Model 01 layout of the German NEO layout you can find here:

The site is written in German but you can find that interactive (hover over “Ebene 3” and the other buttons) version of the layout in the middle of the frontpage:

This beast has 6 levels but I “only” need lvl 1 to 4. This is my latest version so far:

You can find the code on github:

I’m on linux and use setxkbmap de nodeadkeys as OS Layout.

Spoiler alarm … it doesn’t work … completely :cry:


My first try was to use setxkbmap de neo as normal in combination with the default Model 01 layout as base. I only mapped the palm keys to MOD3 (caps lock) to get to lvl 3 (parens layer). With this I don’t know how I can customize this level with keys from other levels, as the OS “shifts” the normal keys. Other problem was that I can’t get the SZ (ß) symbol to work. I think there was also a problem with lvl 4 (number/cursor layer), but not sure anymore.

Luckily I found this post from @michael which made key codes for the german nodeadkeys/basic OS map, which I used for my second try as you can see in the Github repo. Now I have different set of problems:

Keys created with the LSHIFT macro like double quote don’t work in vim with various problems. I can’t type a " character at all and can’t use it in commands like "+p to paste from clipboard. As of writing this I tested it again and now it works … so this is probably fixed. I saw @algernon uses this here as well. Do you have any problems spotted so far?

I need a keys (for programming) which produces ^ and backtick () with a single key press. For this I went with thenodeadkeyskeymap variant instead ofbasic. But how I now get a key which make aâafter typinga ^(Key A + the key left of1`)? I don’t need them really, but would good to have it. Lucky me I don’t work with people which has these characters in their names at the moment :grin:

Pressing SHIFT and the number keys (top level row) produces the wrong symbols, as well as Comma, Period and SZ key. I’m not tried to fixed them yet, but I hope this can be done with that shift plugin I saw somewhere and can’t recall at the moment. One thing I don’t know though: How can you make that German quotes which look slightly different and on lvl 2 (shift + X) on the keys 8, 9 and 0?

As using nodeadkeys I assume I can’t build a full neo layout, because there are a lot of symbols missing in that keymap which neo keymap has. I guess the only way is to get the Model 01 layout working with the neo keymap? Brings me to the question how @michael did that mapping?

Also wanted to mention @chrisSCM as she also talked about NEO :wink:

This was a hard peace of work so far and without the work of @michael I would probably lying somewhere crying.

my biggest question, by far

Is this the way to go or is there another/better way to do this?

not so big as the other question

Should I try to use the neo variant again?
Do I need to setup my own keymap on Linux (I don’t not even now how to start)?

I would love to get some tips :grinning::wink:

(michael) #2

Hi @hoschi,

there are a lot of questions in your post.

I’ve built a layout which currently uses a pretty standard german layout plus layer 3 and 4 of neo. That layout works with the standard windows german layout. I would expect it to work with a “normal” german keymap on linux as well.

In order to type characters like the backtick without having to additionally press the spacebar I set up makros which do just that (Press “Backtick” and then Press “Spacebar”). That works perfectly well. Of course I’m not able to use that key in order to type something like â. But you can easily set up another key to type just the ^.

So I think it is not necessary to change the keymap on the Host when you are able to have full control over what your keyboard does for you :slight_smile:

(Stefan Gojan) #3

I know :sweat_smile:

Can you share it? Where do you put your modifier keys?

Hm, need to try if this then still works with vim. Vim uses ^ to go to the beginning of the line.

I don’t get this, but “full control” brings me to another question :grin:
Neo has this feature that you can activate “caps lock mode” when you press both shift keys and switch back to normal mode by press them again together. How do I do this with the Model 01?

(Gergely Nagy) #4

The MagicCombo plugin can help here: you set it up so that both shift keys (by position) toggle CapsLock, something along these lines:

static const KaleidoscopePlugins::MagicCombo::combo_t magic_combos[] PROGMEM = {
  {R3C7, // left hand,
   R3C8  // right hand
  {0, 0}

void magicComboActions(uint8_t combo_index, 
                       uint32_t left_hand, uint32_t right_hand) {
  switch (combo_index) {
  case 0:

(Stefan Gojan) #5

Thanks, that works great! commit

(Jordihs) #6

Note that the namespace KaleidoscopePlugins does not exist, one must instead use kaleidoscope, as in:

static const kaleidoscope::MagicCombo::combo_t magic_combos[] PROGMEM = {
  {R2C7, // left hand,
   R2C8  // right hand
  {0, 0}

(Christine) #7

@hoschi - I second @michael :wink: one reason for buying this keyboard was its programmability, i.e. being able to define the layout “in hardware”, in order to avoid having to setup the neo2 layout on various OSs. So if you want have a look at my layout! It’s not perfect or complete, but it works for me. I have never used the layers beyond MOD3, so I haven’t implemented them. Let me know when you make improvements! (feel free to fork or contribute)

(Stefan Gojan) #8

Don’t get me wrong, I like the fact of the programmable Firmware A LOT. It is just much harder to come to first version when it is not a QWERTY layout, imo.

Also I think it is not possible to build Neo with QWERTZ at the host, because ShapeShifter can’t put arbitrary keys on the shifted layer. But as you and @michael said, a correct Neo implementation is not your goal. Working more and more with the keyboard I’m now at the same page. With QWERTZ as the host layout I can now have “my Neo” where ever I plug my keyboard in. This gives me more than having keys I don’t use much.

Your layout looks pretty solid!

I made a good amount of changes and testing things out, make sure to have a look:

I tried to use DualUse/Qukeys to make modifier keys even more useful. This ended still in modifier keys on both sides of the keyboard. So one of the last commits uses a OneShot centric approach like @algernon has it in his setup.

(Stefan Gojan) #9

Fotos of my setup and the current layout as picture:

(Michael Richters) #10

On my todo list is a plugin that will allow arbitrary keycode remapping of individual keys based on modifiers held (possibly limited to shift, but that’s the really useful one).

In the meantime, it occurs to me that Qukeys could be used as a sort of “long-press shift” to get arbitrary alternate keycodes, even with modifiers applied. It’s not Qukeys’ raison d’être, but you could have a key the produces # when tapped, but ! when “long-pressed”, for example. I wouldn’t want to use an alternate keycode like that for a character that appears frequently when typing, but for less-frequent characters, a 200ms delay might not be much different to holding a modifier or layer-shift key.


Hi michael,

got my own Keyboardio yesterday, and that would be exaclty the layout i would like to have.

Can you share your firmware/code/changelist/whatever, so i do not have to reinvent it?

Would be really nice!

(michael) #12

With pleasure:

Beware that you need to include this pull-request in order for the sketch to work. It defines all the Key_de_* constants.

Good luck!

// -*- mode: c++ -*-
// Copyright 2016 Keyboardio, inc. <>
// See "LICENSE" for license details

#define BUILD_INFORMATION "locally built"

 * These #include directives pull in the Kaleidoscope firmware core,
 * as well as the Kaleidoscope plugins we use in the Model 01's firmware

// The Kaleidoscope core
#include "Kaleidoscope.h"

// Support for keys that move the mouse
#include "Kaleidoscope-MouseKeys.h"

// Support for macros
#include "Kaleidoscope-Macros.h"

// Support for controlling the keyboard's LEDs
#include "Kaleidoscope-LEDControl.h"

// Support for "Numpad" mode, which is mostly just the Numpad specific LED mode
// #include "Kaleidoscope-NumPad.h"

#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-LED-ActiveModColor.h"

//#include "Kaleidoscope-DualUse.h"

// The better Dual-Use
#include "Kaleidoscope-Qukeys.h"

// The Matrix-LED-Effect
//#include "Kaleidoscope-LEDEffect-DigitalRain.h"

// Support for an "LED off mode"
#include "LED-Off.h"

// Support for the "Boot greeting" effect, which pulses the 'LED' button for 10s
// when the keyboard is connected to a computer (or that computer is powered on)
#include "Kaleidoscope-LEDEffect-BootGreeting.h"

// Support for LED modes that set all LEDs to a single color
#include "Kaleidoscope-LEDEffect-SolidColor.h"

// Support for LED modes that pulse the keyboard's LED in a rainbow pattern
#include "Kaleidoscope-LEDEffect-Rainbow.h"

// Support for an LED mode that lights up the keys as you press them
#include "Kaleidoscope-LED-Stalker.h"

// Support for an LED mode that prints the keys you press in letters 4px high
// #include "Kaleidoscope-LED-AlphaSquare.h"

// Support for Keyboardio's internal keyboard testing mode
// #include "Kaleidoscope-Model01-TestMode.h"

/** This 'enum' is a list of all the macros used by the Model 01's firmware
  * The names aren't particularly important. What is important is that each
  * is unique.
  * These are the names of your macros. They'll be used in two places.
  * The first is in your keymap definitions. There, you'll use the syntax
  * `M(MACRO_NAME)` to mark a specific keymap position as triggering `MACRO_NAME`
  * The second usage is in the 'switch' statement in the `macroAction` function.
  * That switch statement actually runs the code associated with a macro when
  * a macro key is pressed.


/** The Model 01's key layouts are defined as 'keymaps'. By default, there are three
  * keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad"
  * keymap.
  * Each keymap is defined as a list using the 'KEYMAP_STACKED' macro, built
  * of first the left hand's layout, followed by the right hand's layout.
  * Keymaps typically consist mostly of `Key_` definitions. There are many, many keys
  * defined as part of the USB HID Keyboard specification. You can find the names
  * (if not yet the explanations) for all the standard `Key_` defintions offered by
  * Kaleidoscope in these files:
  * Additional things that should be documented here include
  *   using ___ to let keypresses fall through to the previously active layer
  *   using XXX to mark a keyswitch as 'blocked' on this layer
  *   using ShiftToLayer() and LockLayer() keys to change the active keymap.
  *   the special nature of the PROG key
  *   keeping NUM and FN consistent and accessible on all layers
  * The "keymaps" data structure is a list of the keymaps compiled into the firmware.
  * The order of keymaps in the list is important, as the ShiftToLayer(#) and LockLayer(#)
  * macros switch to key layers based on this list.

  * A key defined as 'ShiftToLayer(FUNCTION)' will switch to FUNCTION while held.
  * Similarly, a key defined as 'LockLayer(NUMPAD)' will switch to NUMPAD when tapped.

  * Layers are "0-indexed" -- That is the first one is layer 0. The second one is layer 1.
  * The third one is layer 2.
  * This 'enum' lets us use names like QWERTY, FUNCTION, and NUMPAD in place of
  * the numbers 0, 1 and 2.


/* This comment temporarily turns off astyle's indent enforcement
 *   so we can make the keymaps actually resemble the physical key layout better

const Key keymaps[][ROWS][COLS] PROGMEM = {

  (Key_de_Escape,            Key_de_F1, Key_de_F2, Key_de_F3, Key_de_F4, Key_de_F5, Key_de_F6,
   Key_de_Backtick,          Key_de_Q,  Key_de_W,  Key_de_E,  Key_de_R,  Key_de_T,  Key_de_Tab,
   OSL(LAYER3),              Key_de_A,  Key_de_S,  Key_de_D,  Key_de_F,  Key_de_G,
   ShiftToLayer(NAVIGATION), Key_de_Y,  Key_de_X,  Key_de_C,  Key_de_V,  Key_de_B,  Key_de_Escape,
   Key_de_LeftControl, OSM(LeftShift), Key_de_LeftAlt, Key_de_LeftGui,

   Key_de_F7,      Key_de_F8, Key_de_F9, Key_de_F10,   Key_de_F11,    Key_de_F12,   Key_de_F13,
   Key_de_Enter,   Key_de_Z,  Key_de_U,  Key_de_I,     Key_de_O,      Key_de_P,     Key_de_UE,
                   Key_de_H,  Key_de_J,  Key_de_K,     Key_de_L,      Key_de_OE,    Key_de_AE,
   Key_de_LeftGui, Key_de_N,  Key_de_M,  Key_de_Comma, Key_de_Period, Key_de_Minus, Key_de_RightShift,
   OSL(MOUSE), Key_de_Backspace, Key_de_Spacebar, OSL(FKEYS),

  (___, ___, ___, ___, ___, ___, ___,
   ___, Key_de_Euro,      Key_de_Underscore, Key_de_LeftBracket, Key_de_RightBracket, M(MACRO_CIRCUMFLEX), ___,
   ___, Key_de_Backslash, Key_de_Slash,      Key_de_LeftCurly,   Key_de_RightCurly,   Key_de_Asterisk,
   ___, Key_de_Hash,      Key_de_Dollar,     Key_de_Pipe,        Key_de_Tilde,        M(MACRO_BACKTICK), ___,
   ___, ___, ___, ___,

   ___,  ___, ___, ___,   ___, ___, Key_de_Tick,
   ___,  Key_de_ExlamationMark, M(MACRO_LESSTHAN), M(MACRO_GREATERTHAN), Key_de_Equals,  Key_de_Ampersand, Key_de_SZ, /* ! < > = & ß */
         Key_de_QuestionMark,   Key_de_LeftParen,  Key_de_RightParen,    M(MACRO_MINUS), Key_de_Colon,     Key_de_At, /* ? ( ) - : @ */
   ___,  Key_de_Plus,           Key_de_Percent,    Key_de_DoubleQuote,   Key_de_Quote,   Key_de_Semicolon, ___,       /* + % " ' ; */
   ___, ___, ___, ___,

  (Key_de_PrintScreen,   ___, ___, ___, ___, ___, Key_LEDEffectNext,
   ___, Key_de_PageUp,   Key_de_Backspace, Key_de_UpArrow,   Key_de_Delete,     Key_de_PageDown, ___,
   ___, Key_de_Home,     Key_de_LeftArrow, Key_de_DownArrow, Key_de_RightArrow, Key_de_End,
   ___, ___,             Key_de_Spacebar,  Key_de_Insert,    Key_de_Enter,      Key_mouseBtnL,   ___,
   ___, ___, ___, Key_de_PcApplication,

   ___,                  Key_KeypadDivide,   XXX,      XXX,          XXX,             ___,           Consumer_Mute,
   ___,                  Key_KeypadMultiply, Key_de_7, Key_de_8,     Key_de_9,        Key_de_Colon,  Consumer_VolumeIncrement,
                         Key_KeypadSubtract, Key_de_4, Key_de_5,     Key_de_6,        Key_de_Comma,  Consumer_VolumeDecrement,
   Key_de_PcApplication, Key_KeypadAdd,      Key_de_1, Key_de_2,     Key_de_3,        Key_de_Period, ___,
   ___, ___, ___, Key_de_0,

  (Key_de_PrintScreen,   ___, ___, ___, ___, ___, Key_LEDEffectNext,
   ___, Key_de_PageUp,   Key_de_Backspace, Key_de_UpArrow,   Key_de_Delete,     Key_de_PageDown, ___,
   ___, Key_de_Home,     Key_de_LeftArrow, Key_de_DownArrow, Key_de_RightArrow, Key_de_End,
   ___, ___,             Key_de_Spacebar,  Key_de_Insert,    Key_de_Enter,      Key_mouseBtnL,   ___,
   ___, ___, ___, Key_de_PcApplication,

   ___, XXX,               XXX,             Key_de_Slash,     Key_de_Asterisk, ___,              Consumer_Mute,
   ___, Key_mouseScrollUp, Key_mouseWarpNW, Key_mouseUp,      Key_mouseWarpNE, Key_mouseBtnM,    Consumer_VolumeIncrement,
        Key_mouseScrollDn, Key_mouseL,      Key_mouseDn,      Key_mouseR,      Key_mouseBtnL,    Consumer_VolumeDecrement,
   ___, Key_mouseBtnR,     Key_mouseWarpSW, Key_mouseWarpEnd, Key_mouseWarpSE, Key_mouseScrollL, Key_mouseScrollR,
   ___, ___, ___, ___,

  (___, ___, ___, ___, ___, ___, ___,
   ___, ___, ___, ___, ___, ___, ___,
   ___, ___, ___, ___, ___, ___,
   ___, ___, ___, ___, ___, ___, ___,
   ___, ___, ___, ___,

   ___, ___, Key_de_F10, Key_de_F11, Key_de_F12, ___, ___,
   ___, ___, Key_de_F7,  Key_de_F8,  Key_de_F9,  ___, ___,
        ___, Key_de_F4,  Key_de_F5,  Key_de_F6,  ___, ___,
   ___, ___, Key_de_F1,  Key_de_F2,  Key_de_F3,  ___, ___,
   ___, ___, ___, ___,

/* Re-enable astyle's indent enforcement */

/** versionInfoMacro handles the 'firmware version info' macro
 *  When a key bound to the macro is pressed, this macro
 *  prints out the firmware build information as virtual keystrokes

static void versionInfoMacro(uint8_t keyState) {
  if (keyToggledOn(keyState)) {
    Macros.type(PSTR("Keyboardio Model 01 - Kaleidoscope "));

/** anyKeyMacro is used to provide the functionality of the 'Any' key.
 * When the 'any key' macro is toggled on, a random alphanumeric key is
 * selected. While the key is held, the function generates a synthetic
 * keypress event repeating that randomly selected key.

static void anyKeyMacro(uint8_t keyState) {
  static Key lastKey;
  if (keyToggledOn(keyState))
    lastKey.keyCode = Key_A.keyCode + (uint8_t)(millis() % 36);

  if (keyIsPressed(keyState))

/** macroAction dispatches keymap events that are tied to a macro
    to that macro. It takes two uint8_t parameters.

    The first is the macro being called (the entry in the 'enum' earlier in this file).
    The second is the state of the keyswitch. You can use the keyswitch state to figure out
    if the key has just been toggled on, is currently pressed or if it's just been released.

    The 'switch' statement should have a 'case' for each entry of the macro enum.
    Each 'case' statement should call out to a function to handle the macro in question.


const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
  switch (macroIndex) {

    case MACRO_ANY:

    case MACRO_SHIFT1:
      return MACRODOWN(I(10), D(LeftShift), T(1), U(LeftShift));

      return MACRODOWN(I(10), U(LeftShift), T(de_LessThan));

      return MACRODOWN(I(10), D(LeftShift), T(de_LessThan), U(LeftShift));

      return MACRODOWN(I(10), T(de_Backtick), T(de_Spacebar));

      return MACRODOWN(I(10), T(de_Circumflex), T(de_Spacebar));

    case MACRO_MINUS:
      return MACRODOWN(I(10), U(LeftShift), D(de_Minus));

  return MACRO_NONE;

// These 'solid' color effect definitions define a rainbow of
// LED color modes calibrated to draw 500mA or less on the
// Keyboardio Model 01.

static kaleidoscope::LEDSolidColor solidRed(160, 0, 0);
static kaleidoscope::LEDSolidColor solidOrange(140, 70, 0);
static kaleidoscope::LEDSolidColor solidYellow(130, 100, 0);
static kaleidoscope::LEDSolidColor solidGreen(0, 160, 0);
static kaleidoscope::LEDSolidColor solidBlue(0, 70, 130);
static kaleidoscope::LEDSolidColor solidIndigo(0, 0, 170);
static kaleidoscope::LEDSolidColor solidViolet(130, 0, 120);

/** The 'setup' function is one of the two standard Arduino sketch functions.
  * It's called when your keyboard first powers up. This is where you set up
  * Kaleidoscope and any plugins.

void setup() {
  // First, call Kaleidoscope's internal setup function

  // Next, tell Kaleidoscope which plugins you want to use.
  // The order can be important. For example, LED effects are
  // added in the order they're listed here.
    // the better DualUse Plugin

    // The boot greeting effect pulses the LED button for 10 seconds after the keyboard is first connected

    // The hardware test mode, which can be invoked by tapping Prog, LED and the left Fn button at the same time.
    // &TestMode,

    // OneShot Modifiers

    // LEDControl provides support for other LED modes

    // We start with the LED effect that turns off all the LEDs.
    // The rainbow wave effect lights up your keyboard with all the colors of a rainbow
    // and slowly moves the rainbow across your keyboard

    // These static effects turn your keyboard's LEDs a variety of colors

    // The stalker effect lights up the keys you've pressed recently

    // The numpad plugin is responsible for lighting up the 'numpad' mode
    // with a custom LED effect
    // &NumPad,

    // The macros plugin adds support for macros

    // The MouseKeys plugin lets you add keys to your keymap which move the mouse.

    //kaleidoscope::Qukey(0, 3, 1, ShiftToLayer(NAVIGATION)),      // Y/Navigation-Layer
    kaleidoscope::Qukey(QWERTY, 3, 1, LALT(Key_de_LeftControl))    // Y/Ctrl+Alt

  // Cancel OneShot action after xx ms
  OneShot.time_out = 300;
  // If a key is held longer then xx ms consider it not to be a one-shot.
  OneShot.hold_time_out = 250;
  OneShot.double_tap_sticky = false;
  ActiveModColorEffect.sticky_color = CRGB(0x2, 0xff, 0x00);

  // While we hope to improve this in the future, the NumPad plugin
  // needs to be explicitly told which keymap layer is your numpad layer
  // NumPad.numPadLayer = LAYER3;

  // We set the brightness of the rainbow effects to 150 (on a scale of 0-255)
  // This draws more than 500mA, but looks much nicer than a dimmer effect

  // The LED Stalker mode has a few effects. The one we like is
  // called 'BlazingTrail'. For details on other options,
  // see
  StalkerEffect.variant = STALKER(BlazingTrail);

  // We want to make sure that the firmware starts with LED effects off
  // This avoids over-taxing devices that don't have a lot of power to share
  // with USB devices

  MouseKeys.accelSpeed = 2;
  MouseKeys.accelDelay = 30;

/** loop is the second of the standard Arduino sketch functions.
  * As you might expect, it runs in a loop, never exiting.
  * For Kaleidoscope-based keyboard firmware, you usually just want to
  * call Kaleidoscope.loop(); and not do anything custom here.

void loop() {