diff --git a/blog/zsa-moonlander-review-2020-11-06.markdown b/blog/zsa-moonlander-review-2020-11-06.markdown new file mode 100644 index 0000000..0f180b1 --- /dev/null +++ b/blog/zsa-moonlander-review-2020-11-06.markdown @@ -0,0 +1,442 @@ +--- +title: ZSA Moonlander Review +date: 2020-11-06 +series: keeb +tags: + - moonlander + - keyboard + - nixos +--- + +# ZSA Moonlander Review + +I am nowhere near qualified to review things objectively. Therefore this +blogpost will mostly be about what I like about this keyboard. I plan to go into +a fair bit of detail, however please do keep in mind that this is subjective as +all hell. Also keep in mind that this is partially also going to be a review of +my own keyboard layout too. I'm going to tackle this in a few parts that I will +label with headings. + +This review is NOT sponsored. I paid for this device with my own money. I have +no influence pushing me either way on this keyboard. + +![a picture of the keyboard on my +desk](https://cdn.christine.website/file/christine-static/img/keeb/Elm3dN8XUAAYHws.jpg) + +[That 3d printed brain is built from the 3D model that was made as a part of this +blogpost.](conversation://Mara/hacker) + +## tl;dr + +I like the Moonlander. It gets out of my way and lets me focus on writing and +code. I don't like how limited the Oryx configurator is, but the fact that I can +build my own firmware from source and flash it to the keyboard on my own makes +up for that. I think this was a purchase well worth making, but I can understand +why others would disagree. I can easily see this device becoming a core part of +my workflow for years to come. + +## Build Quality + +The Moonlander is a solid keyboard. Once you set it up with the tenting legs and +adjust the key cluster, the keyboard is rock solid. The only give I've noticed +is because my desk mat is made of a rubber-like material. The construction of +the keyboard is all plastic but there isn't any deck flex that I can tell. +Compare this to cheaper laptops where the entire keyboard bends if you so much +as touch the keys too hard. + +The palmrests are detachable and when they are off it gives the keyboard a +space-age vibe to it: + +![the left half of the keyboard without the palmrest +attached](https://cdn.christine.website/file/christine-static/img/keeb/EmJ1bqNXUAAJy4d.jpg) + +The palmrests feel very solid and fold up into the back of the keyboard for +travel. However folding up the palmrest does mess up the tenting stability, so +you can't fold in the palmrest and type very comfortably. This makes sense +though, the palmrest is made out of smooth plastic so it feels nicer on the +hands. + +ZSA said that iPad compatibility is not guaranteed due to the fact that the iPad +might not put out enough juice to run it, however in my testing with an iPad Pro +2018 (12", 512 GB storage) it works fine. The battery drains a little faster, +but the Moonlander is a much more active keyboard than the smart keyboard so I +can forgive this. + +## Switches + +I've been using mechanical keyboards for years, but most of them have been +clicky switches (such as cloned Cherry MX blues, actual legit Cherry MX blues +and the awful Razer Green switches). This is my first real experience with +Cherry MX brown switches. There are many other options when you are about to +order a moonlander, but I figured Cherry MX browns would be a nice neutral +choice. + +The keyswitches are hot-swappable (no disassembly or soldering required), and +changing out keyswitches **DOES NOT** void your warranty. I plan to look into +[Holy Pandas](https://www.youtube.com/watch?v=QLm8DNH5hJk) and [Zilents +V2](https://youtu.be/uGVw85solnE) in the future. There is even a clever little +tool in the box that makes it easy to change out keyswitches. + +Overall, this has been one of the best typing experiences I have ever had. The +noise is a little louder than I would have liked (please note that I tend to +bottom out the keycaps as I type, so this may end up factoring into the noise I +experience); but overall I really like it. It is far better than I have ever had +with clicky switches. + +## Typing Feel + +The Moonlander uses an ortholinear layout as opposed to the staggered layout +that you find on most keyboards. This took some getting used to, but I have +found that it is incredibly comfortable and + +## My Keymap + +Each side of the keyboard has the following: + +- 20 alphanumeric keys (some are used for `;`, `,`, `.` and `/` like normal + keyboards) +- 12 freely assignable keys (useful for layer changes, arrow keys, symbols and + modifiers) +- 4 thumb keys + +In total, this keyboard has 72 keys, making it about a 70% keyboard (assuming +the math in my head is right). + +My keymap uses all but two of these keys. The two keys I haven't figured out how +to best use yet are the ones that I currently have the `[` and `]` keycaps on. +Right now they are mapped to the left and right arrow keys. This was the +default. + +My keymap is organized into +[layers](https://docs.qmk.fm/#/keymap?id=keymap-and-layers). In each of these +subsections I will go into detail about what these layers are, what they do and +how they help me. My keymap code is +[here](https://tulpa.dev/cadey/kadis-layouts/src/branch/master/moonlander) and I +have a limited view of it embedded below: + +
+ +
+ +If you want to flash my layout to your Moonlander for some reason, you can find +the firmware binary +[here](https://cdn.christine.website/file/christine-static/img/keeb/moonlander_kadis.bin). +You can then flash this to your keyboard with +[Wally](https://ergodox-ez.com/pages/wally). + +### Base Layers + +I have a few base layers that contain the main set of letters and numbers that I +type. The main base layer is my Colemak layer. I have the keys arranged to a +standard [Colemak](https://Colemak.com/) layout and it is currently the layer I +type the fastest on. I have the RGB configured so that it is mostly pink with +the homerow using a lighter shade of pink. The color codes come from my logo +that you can see in the favicon [or here for a larger +version](https://christine.website/static/img/avatar_large.png). + +I also have a qwerty layer for gaming. Most games expect qwerty keyboards and +this is an excellent stopgap to avoid having to rebind every game that I want to +play. The left side of the keyboard is the active one with the controller board +in it too, so I can unplug the other half of the keyboard and give my mouse a +lot of room to roam. + +Thanks to a friend of mine, I am also playing with Dvorak. I have not gotten far +in Dvorak yet, but it is interesting to play with. + +I'll cover the leader key in the section below dedicated to it, but the other +major thing that I have is a colon key on my right hand thumb cluster. This has +been a huge boon for programming. The colon key is typed a lot. Having it on the +thumb cluster means that I can just reach down and hit it when I need to. This +makes writing code in Go and Rust so much easier. + +### Symbol/Number Layer + +If you look at the base layer keymap, you will see that I do not have square +brackets mapped anywhere there. Yet I write code with it effortlessly. This is +because of the symbol/number layer that I access with the lower right and lower +left keys on the keyboard. I have it positioned there so I can roll my hand to +the side and then unlock the symbols there. I have access to every major symbol +needed for programming save `<` and `>` (which I can easily access on the base +layer with the shift key). I also get a nav cluster and a number pad. + +I also have [dynamic macros](https://docs.qmk.fm/#/feature_dynamic_macros) on +this layer which function kinda like vim macros. The only difference is that +there's only two macros instead of many like vim. They are convenient though. + +### Media Layer + +One of the cooler parts of the Moonlander is that it can act as a mouse. It is a +very terrible mouse (understandably, mostly because the digital inputs of +keypresses cannot match the analog precision of a mouse). This layer has an +arrow key cluster too. I normally use the arrow keys along the bottom of the +keyboard with my thumbs, but sometimes it can help to have a dedicated inverse T +arrow cluster for things like old MS-DOS games. + +I also have media control keys here. They aren't the most useful on my linux +desktop, however when I plug it into my iPad they are amazing. + +### dwm Layer + +I use [dwm](/blog/why-i-use-suckless-tools-2020-06-05) as my main window manager +in Linux. dwm is entirely controlled using the keyboard. I have a dedicated +keyboard layer to control dwm and send out its keyboard shortcuts. It's really +nice and lets me get all of the advantages of my tiling setup without needing to +hit weird keycombos. + +### Leader Macros + +[Leader macros](https://docs.qmk.fm/#/feature_leader_key) are one of the killer +features of my layout. I have a [huge +bank](https://tulpa.dev/cadey/kadis-layouts/src/branch/master/doc/leader.md) of +them and use them to do type out things that I type a lot. Most common git and +Kubernetes commands are just a leader macro away. + +The Go `if err != nil` macro that got me on /r/programmingcirclejerk twice is +one of my leader macros, but I may end up promoting it to its own key if I keep +getting so much use out of it (maybe one of the keys I don't use can become my +`if err != nil` key). I'm sad that the threads got deleted (I love it when my +content gets on there, it's one of my favorite subreddits), but such is life. + +## NixOS, the Moonlander and Colemak + +When I got this keyboard, flashed the firmware and plugged it in, I noticed that +my keyboard was sending weird inputs. It was rendering things that look like +this: + +``` +The quick brown fox jumps over the lazy yellow dog. +``` + +into this: + +``` +Ghf qluce bpywk tyx nlm;r yvfp ghf iazj jfiiyw syd. +``` + +This is because I had configured my NixOS install to interpret the keyboard as +if it was Colemak. However the keyboard is able to lie and sends out normal +keycodes (even though I am typing them in Colemak) as if I was typing in qwerty. +This double Colemak meant that a lot of messages and commands were completely +unintelligible until I popped into my qwerty layer. + +I quickly found the culprit in my config: + +```nix +console.useXkbConfig = true; +services.xserver = { + layout = "us"; + xkbVariant = "colemak"; + xkbOptions = "caps:escape"; +}; +``` + +This config told the X server to always interpret my keyboard as if it was +Colemak, meaning that I needed to tell it not to. As a stopgap I commented this +section of my config out and rebuilt my system. + +X11 allows you to specify keyboard configuration for keyboards individually by +device product/vendor names. The easiest way I know to get this information is +to open a terminal, run `dmesg -w` to get a constant stream of kernel logs, +unplug and plug the keyboard back in and see what the kernel reports: + +```console +[242718.024229] usb 1-2: USB disconnect, device number 8 +[242948.272824] usb 1-2: new full-speed USB device number 9 using xhci_hcd +[242948.420895] usb 1-2: New USB device found, idVendor=3297, idProduct=1969, bcdDevice= 0.01 +[242948.420896] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 +[242948.420897] usb 1-2: Product: Moonlander Mark I +[242948.420898] usb 1-2: Manufacturer: ZSA Technology Labs +[242948.420898] usb 1-2: SerialNumber: 0 +``` + +The product is named `Moonlander Mark I`, which means we can match for it and +tell X11 to not colemakify the keycodes using something like this: + +``` +Section "InputClass" + Identifier "moonlander" + MatchIsKeyboard "on" + MatchProduct "Moonlander" + Option "XkbLayout" "us" + Option "XkbVariant" "basic" +EndSection +``` + +[For more information on what you can do in an `InputClass` section, see here +in the X11 documentation.](conversation://Mara/hacker) + +This configuration fragment can easily go in the normal X11 configuration +folder, but doing it like this would mean that I would have to manually drop +this file in on every system I want to colemakify. This does not scale and +defeats the point of doing this in NixOS. + +Thankfully NixOS has [an +option](https://search.nixos.org/options?channel=20.09&show=services.xserver.inputClassSections&from=0&size=30&sort=relevance&query=inputClassSections) +to solve this very problem. Using this module we can write something like this: + +```nix +services.xserver = { + layout = "us"; + xkbVariant = "colemak"; + xkbOptions = "caps:escape"; + + inputClassSections = [ + '' + Identifier "yubikey" + MatchIsKeyboard "on" + MatchProduct "Yubikey" + Option "XkbLayout" "us" + Option "XkbVariant" "basic" + '' + '' + Identifier "moonlander" + MatchIsKeyboard "on" + MatchProduct "Moonlander" + Option "XkbLayout" "us" + Option "XkbVariant" "basic" + '' + ]; +}; +``` + +But this is NixOS and that allows us to go one step further and make the +identifier and product matching string configurable as will with our own [NixOS +options](https://nixos.org/manual/nixos/stable/index.html#sec-writing-modules). +Let's start by lifting all of that above config into its own module: + +```nix +# Colemak.nix + +{ config, lib, ... }: with lib; { + options = { + cadey.colemak = { + enable = mkEnableOption "Enables colemak for the default X config"; + }; + }; + + config = mkIf config.cadey.Colemak.enable { + services.xserver = { + layout = "us"; + xkbVariant = "colemak"; + xkbOptions = "caps:escape"; + + inputClassSections = [ + '' + Identifier "yubikey" + MatchIsKeyboard "on" + MatchProduct "Yubikey" + Option "XkbLayout" "us" + Option "XkbVariant" "basic" + + '' + '' + Identifier "moonlander" + MatchIsKeyboard "on" + MatchProduct "Moonlander" + Option "XkbLayout" "us" + Option "XkbVariant" "basic" + '' + ]; + }; + }; +} +``` + +[This also has Yubikey inputs not get processed into Colemak so that Yubikey OTPs +still work as expected. Keep in mind that a Yubikey in this mode pretends to be +a keyboard, so without this configuration the OTP will be processed into +Colemak. The Yubico verification service will not be able to understand OTPs +that are typed out in Colemak.](conversation://Mara/hacker) + +Then we can turn the identifier and product values into options with +[mkOption](https://nixos.org/manual/nixos/stable/index.html#sec-option-declarations) +and string interpolation: + +```nix +# ... + cadey.colemak = { + enable = mkEnableOption "Enables Colemak for the default X config"; + ignore = { + identifier = mkOption { + type = types.str; + description = "Keyboard input identifier to send raw keycodes for"; + default = "moonlander"; + }; + product = mkOption { + type = types.str; + description = "Keyboard input product to send raw keycodes for"; + default = "Moonlander"; + }; + }; + }; +# ... + '' + Identifier "${config.cadey.colemak.ignore.identifier}" + MatchIsKeyboard "on" + MatchProduct "${config.cadey.colemak.ignore.product}" + Option "XkbLayout" "us" + '' +# ... +``` + +Adding this to the default load path and enabling it with `cadey.Colemak.enable += true;` in my tower's `configuration.nix` + +This section was made possible thanks to help from [Graham +Christensen](https://twitter.com/grhmc) who seems to be in search of a job. If +you are wanting someone on your team that is kind and more than willing to help +make your team flourish, I highly suggest looking into putting him in your +hiring pipeline. See +[here](https://twitter.com/grhmc/status/1324765493534875650) for contact +information. + +## Oryx + +[Oryx](https://configure.ergodox-ez.com) is the configurator that ZSA created to +allow people to create keymaps without needing to compile your own firmware or +install the [QMK](https://qmk.fm) toolchain. + +[QMK is the name of the firmware that the Moonlander (and a lot of other +custom/split mechanical keyboards) use. It works on AVR and Arm +processors.](conversation://Mara/hacker) + +For most people, Oryx should be sufficient. I actually started my keymap using +Oryx and sorta outgrew it as I learned more about QMK. It would be nice if Oryx +added leader key support, however this is more of an advanced feature so I +understand why it doesn't have that. + +## Things I Don't Like + +This keyboard isn't flawless, but it gets so many things right that this is +mostly petty bickering at this point. I had to look hard to find these. + +I would have liked having another thumb key for things like layer toggling. I +can make do with what I have, but another key would have been nice. Maybe add a +1u key under the red shaped key? + +At the point I ordered the Moonlander, I was unable to order a black keyboard +with white keycaps. I am told that ZSA will be selling keycap sets as early as +next year. When that happens I will be sure to order a white one so that I can +have an orca vibe. + +ZSA ships with UPS. Normally UPS is fine for me, but the driver that was slated +to deliver it one day just didn't deliver it. I was able to get the keyboard +eventually though. Contrary to their claims, the UPS website does NOT update +instantly and is NOT the most up to date source of information about your +package. + +The cables aren't braided. I would have liked braided cables. + +Like I said, these are _really minor_ things, but it's all I can really come up +with as far as downsides go. + +## Conclusion + +Overall this keyboard is amazing. I would really suggest it to anyone that wants +to be able to have control over their main tool and craft it towards their +desires instead of making do with what some product manager somewhere decided +what keys should do what. It's expensive at USD$350, but for the right kind of +person this will be worth every penny. Your mileage may vary, but I like it.