瀏覽代碼

Merge remote-tracking branch 'origin/master' into develop

QMK Bot 2 年之前
父節點
當前提交
4779539543

+ 58 - 0
keyboards/handwired/dqz11n1g/config.h

@@ -0,0 +1,58 @@
+/*
+Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
+  
+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
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xFEED
+#define PRODUCT_ID 0x4451
+#define DEVICE_VER 0x0001
+#define PRODUCT    DQz11N1G Controller Replacement
+
+/* Matrix size */
+#define MATRIX_ROWS 7
+#define MATRIX_COLS 19
+
+/* Pin-out */
+#define MATRIX_ROW_PINS { D1, D0, D4, C6, D7, E6, B4 }
+
+/* The pin connecting to the SN74HC165 SH/~LD in */
+#define ROW_SHIFT_PIN B6
+
+/* Column read via SPI (shift register) */
+/* #define MATRIX_COL_PINS { } */
+#define UNUSED_PINS
+
+#define LED_CAPS_LOCK_PIN F7 /* A0 */
+#define LED_NUM_LOCK_PIN F5 /*A2 */
+#define LED_SCROLL_LOCK_PIN F4 /*A3 */
+
+#define LED_FUN_LOCK_PIN F6 /* A1 (handled in layer_state_set_user()) */
+
+/* audio config */
+#define AUDIO_PIN B5
+#define AUDIO_CLICKY
+#define AUDIO_INIT_DELAY
+#define AUDIO_CLICKY_FREQ_RANDOMNESS 0.0f
+#define NO_MUSIC_MODE
+
+/* diodes go row->col, though this is hard-coded in matrix.c and we drive the
+ * matrix differently: we have pull-down on the columns and drive the selected
+ * row high */
+/* #define DIODE_DIRECTION ROW2COL */

+ 51 - 0
keyboards/handwired/dqz11n1g/dqz11n1g.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
+ *
+ * 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
+
+#include "quantum.h"
+
+#define XXX KC_NO
+
+/* Fill actually existing keys into the 7x19 keyboard matrix */
+#define LAYOUT(                                                \
+    k00, k01, k02, k03, k04, k05,   k06, k07, k08, k09, k0A, k0B, k0C,   k0D, k0E, k0F, k0G, k0H, k0J, \
+    k10, k11, k12, k13, k14, k15,   k16, k17, k18, k19, k1A, k1B, k1C,   k1D, k1E, k1F, k1G, k1H, k1J, \
+    k20, k21, k22, k23, k24, k25,   k26, k27, k28, k29, k2A, k2B, k2C,   k2D, k2E, k2F, k2G, k2H, k2J, \
+    k30, k31, k32, k33, k34, k35,   k36, k37, k38, k39, k3A, k3B, k3C,   k3D, k3E, k3F, k3G, k3H, k3J, \
+    k40, k41, k42, k43, k44, k45,                                        k4D, k4E, k4F, k4G, k4H, k4J, \
+         k51, k52, k53, k54,                                                  k5E, k5F, k5G, k5H, \
+                                    k46, k47, k48,      k4A, k4B, k4C,  \
+                                    k56, k57, k58,      k5A, k5B, k5C,  \
+                                              k68,      k6A             \
+) {                                                                     \
+   /* left hand */                      /* middle/thumb block */                      /* right hand */ \
+    { k00, k01, k02, k03, k04, k05,   k06, k07, k08, k09, k0A, k0B, k0C,   k0D, k0E, k0F, k0G, k0H, k0J }, \
+    { k10, k11, k12, k13, k14, k15,   k16, k17, k18, k19, k1A, k1B, k1C,   k1D, k1E, k1F, k1G, k1H, k1J }, \
+    { k20, k21, k22, k23, k24, k25,   k26, k27, k28, k29, k2A, k2B, k2C,   k2D, k2E, k2F, k2G, k2H, k2J }, \
+    { k30, k31, k32, k33, k34, k35,   k36, k37, k38, k39, k3A, k3B, k3C,   k3D, k3E, k3F, k3G, k3H, k3J }, \
+    { k40, k41, k42, k43, k44, k45,   k46, k47, k48, XXX, k4A, k4B, k4C,   k4D, k4E, k4F, k4G, k4H, k4J }, \
+    { XXX, k51, k52, k53, k54, XXX,   k56, k57, k58, XXX, k5A, k5B, k5C,   XXX, k5E, k5F, k5G, k5H, XXX }, \
+    { XXX, XXX, XXX, XXX, XXX, XXX,   XXX, XXX, k68, XXX, k6A, XXX, XXX,   XXX, XXX, XXX, XXX, XXX, XXX }, \
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * fill-column: 76
+ * End:
+ */

+ 141 - 0
keyboards/handwired/dqz11n1g/info.json

@@ -0,0 +1,141 @@
+{
+    "keyboard_name": "DQz11N1G",
+    "url": "https://github.com/dvdkhlng/qmk_firmware_dqz11n1g",
+    "maintainer": "dvdkhlng",
+    "layouts": {
+        "LAYOUT": {
+            "layout": [
+                {"x": 0, "y": 0, "matrix": [0, 0] },
+                {"x": 1, "y": 0, "matrix": [0, 1] },
+                {"x": 2, "y": 0, "matrix": [0, 2] },
+                {"x": 3, "y": 0, "matrix": [0, 3] },
+                {"x": 4, "y": 0, "matrix": [0, 4] },
+                {"x": 5, "y": 0, "matrix": [0, 5] },
+
+                {"x": 7, "y": 0, "matrix": [0, 6] },
+                {"x": 8, "y": 0, "matrix": [0, 7] },
+                {"x": 9, "y": 0, "matrix": [0, 8] },
+                {"x": 10, "y": 0, "matrix": [0, 9] },
+                {"x": 11, "y": 0, "matrix": [0, 10] },
+                {"x": 12, "y": 0, "matrix": [0, 11] },
+                {"x": 13, "y": 0, "matrix": [0, 12] },
+
+                {"x": 15, "y": 0, "matrix": [0, 13] },
+                {"x": 16, "y": 0, "matrix": [0, 14] },
+                {"x": 17, "y": 0, "matrix": [0, 15] },
+                {"x": 18, "y": 0, "matrix": [0, 16] },
+                {"x": 19, "y": 0, "matrix": [0, 17] },
+                {"x": 20, "y": 0, "matrix": [0, 18] },
+
+                {"x": 0, "y": 1, "matrix": [1, 0] },
+                {"x": 1, "y": 1, "matrix": [1, 1] },
+                {"x": 2, "y": 1, "matrix": [1, 2] },
+                {"x": 3, "y": 1, "matrix": [1, 3] },
+                {"x": 4, "y": 1, "matrix": [1, 4] },
+                {"x": 5, "y": 1, "matrix": [1, 5] },
+
+                {"x": 7, "y": 1, "matrix": [1, 6] },
+                {"x": 8, "y": 1, "matrix": [1, 7] },
+                {"x": 9, "y": 1, "matrix": [1, 8] },
+                {"x": 10, "y": 1, "matrix": [1, 9] },
+                {"x": 11, "y": 1, "matrix": [1, 10] },
+                {"x": 12, "y": 1, "matrix": [1, 11] },
+                {"x": 13, "y": 1, "matrix": [1, 12] },
+
+                {"x": 15, "y": 1, "matrix": [1, 13] },
+                {"x": 16, "y": 1, "matrix": [1, 14] },
+                {"x": 17, "y": 1, "matrix": [1, 15] },
+                {"x": 18, "y": 1, "matrix": [1, 16] },
+                {"x": 19, "y": 1, "matrix": [1, 17] },
+                {"x": 20, "y": 1, "matrix": [1, 18] },
+
+                {"x": 0, "y": 2, "matrix": [2, 0] },
+                {"x": 1, "y": 2, "matrix": [2, 1] },
+                {"x": 2, "y": 2, "matrix": [2, 2] },
+                {"x": 3, "y": 2, "matrix": [2, 3] },
+                {"x": 4, "y": 2, "matrix": [2, 4] },
+                {"x": 5, "y": 2, "matrix": [2, 5] },
+
+                {"x": 7, "y": 2, "matrix": [2, 6] },
+                {"x": 8, "y": 2, "matrix": [2, 7] },
+                {"x": 9, "y": 2, "matrix": [2, 8] },
+                {"x": 10, "y": 2, "matrix": [2, 9] },
+                {"x": 11, "y": 2, "matrix": [2, 10] },
+                {"x": 12, "y": 2, "matrix": [2, 11] },
+                {"x": 13, "y": 2, "matrix": [2, 12] },
+
+                {"x": 15, "y": 2, "matrix": [2, 13] },
+                {"x": 16, "y": 2, "matrix": [2, 14] },
+                {"x": 17, "y": 2, "matrix": [2, 15] },
+                {"x": 18, "y": 2, "matrix": [2, 16] },
+                {"x": 19, "y": 2, "matrix": [2, 17] },
+                {"x": 20, "y": 2, "matrix": [2, 18] },
+
+                {"x": 0, "y": 3, "matrix": [3, 0] },
+                {"x": 1, "y": 3, "matrix": [3, 1] },
+                {"x": 2, "y": 3, "matrix": [3, 2] },
+                {"x": 3, "y": 3, "matrix": [3, 3] },
+                {"x": 4, "y": 3, "matrix": [3, 4] },
+                {"x": 5, "y": 3, "matrix": [3, 5] },
+
+                {"x": 7, "y": 3, "matrix": [3, 6] },
+                {"x": 8, "y": 3, "matrix": [3, 7] },
+                {"x": 9, "y": 3, "matrix": [3, 8] },
+                {"x": 10, "y": 3, "matrix": [3, 9] },
+                {"x": 11, "y": 3, "matrix": [3, 10] },
+                {"x": 12, "y": 3, "matrix": [3, 11] },
+                {"x": 13, "y": 3, "matrix": [3, 12] },
+
+                {"x": 15, "y": 3, "matrix": [3, 13] },
+                {"x": 16, "y": 3, "matrix": [3, 14] },
+                {"x": 17, "y": 3, "matrix": [3, 15] },
+                {"x": 18, "y": 3, "matrix": [3, 16] },
+                {"x": 19, "y": 3, "matrix": [3, 17] },
+                {"x": 20, "y": 3, "matrix": [3, 18] },
+
+                {"x": 0, "y": 4, "h": 2, "matrix": [4, 0] },
+                {"x": 1, "y": 4, "matrix": [4, 1] },
+                {"x": 2, "y": 4, "matrix": [4, 2] },
+                {"x": 3, "y": 4, "matrix": [4, 3] },
+                {"x": 4, "y": 4, "matrix": [4, 4] },
+                {"x": 5, "y": 4, "matrix": [4, 5] },
+
+                {"x": 15, "y": 4, "matrix": [4, 13] },
+                {"x": 16, "y": 4, "matrix": [4, 14] },
+                {"x": 17, "y": 4, "matrix": [4, 15] },
+                {"x": 18, "y": 4, "matrix": [4, 16] },
+                {"x": 19, "y": 4, "matrix": [4, 17] },
+                {"x": 20, "y": 4, "h": 2, "matrix": [4, 18] },
+
+                {"x": 1, "y": 5, "matrix": [5, 1] },
+                {"x": 2, "y": 5, "matrix": [5, 2] },
+                {"x": 3, "y": 5, "matrix": [5, 3] },
+                {"x": 4, "y": 5, "matrix": [5, 4] },
+
+                {"x": 16, "y": 5, "matrix": [5, 14] },
+                {"x": 17, "y": 5, "matrix": [5, 15] },
+                {"x": 18, "y": 5, "matrix": [5, 16] },
+                {"x": 19, "y": 5, "matrix": [5, 17] },
+
+                {"x": 5, "y": 7, "matrix": [4, 6] },
+                {"x": 6, "y": 7, "matrix": [4, 7] },
+                {"x": 7, "y": 7, "matrix": [4, 8] },
+
+                {"x": 13, "y": 7, "matrix": [4, 10] },
+                {"x": 14, "y": 7, "matrix": [4, 11] },
+                {"x": 15, "y": 7, "matrix": [4, 12] },
+
+                {"x": 5, "y": 8, "h": 2, "matrix": [5, 6] },
+                {"x": 6, "y": 8, "h": 2, "matrix": [5, 7] },
+                {"x": 7, "y": 8, "matrix": [5, 8] },
+
+                {"x": 13, "y": 8, "matrix": [5, 10] },
+                {"x": 14, "y": 8, "h": 2, "matrix": [5, 11] },
+                {"x": 15, "y": 8, "h": 2, "matrix": [5, 12] },
+
+                {"x": 7, "y": 9, "matrix": [6, 8] },
+                {"x": 13, "y": 9, "matrix": [6, 10] }
+            ]
+        }
+    }
+}

+ 72 - 0
keyboards/handwired/dqz11n1g/keymaps/default/keymap.c

@@ -0,0 +1,72 @@
+/* Copyright (c) 2022 David Kuehling < dvdkhlng TA posteo TOD de >
+ *
+ * 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
+
+enum layer_names { _DEFAULT, _FUNCTION };
+#define KC_FUN TG(_FUNCTION)
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+    [_DEFAULT] = LAYOUT(
+        KC_F1,  KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,  KC_FUN,  KC_NUM, KC_P7, KC_P8, KC_P9, KC_PSLS, KC_PSCR,  KC_F7,  KC_F8,  KC_F9,  KC_F10, KC_F11, KC_F12,
+     
+        KC_1,   KC_2,   KC_3,   KC_4,   KC_5,   KC_6,   KC_VOLU, KC_ESC, KC_P4, KC_P5, KC_P6, KC_PAST, KC_SCRL,  KC_7,   KC_8,   KC_9,   KC_0,   KC_MINS,KC_EQL, 
+        KC_NUBS,KC_Q,   KC_W,   KC_E,   KC_R,   KC_T,   KC_VOLD, KC_GRV, KC_P1, KC_P2, KC_P3, KC_PMNS, KC_BRK,   KC_Y,   KC_U,   KC_I,   KC_O,   KC_P,   KC_LBRC, 
+        KC_CAPS,KC_A,   KC_S,   KC_D,   KC_F,   KC_G,   KC_MUTE, KC_WSCH,KC_P0,KC_PDOT,KC_PENT,KC_PPLS,KC_INS,   KC_H,   KC_J,   KC_K,   KC_L,   KC_SCLN,KC_QUOT, 
+        KC_LSFT,KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,                                                            KC_N,   KC_M,   KC_COMM,KC_DOT, KC_SLSH,KC_RSFT, 
+        /* */  KC_LCTL, KC_LGUI,KC_LALT,KC_RBRC,                                                                         KC_NUHS,KC_RALT,KC_APP, KC_RCTL, /* */
+        
+        /* thumb keys: */                      KC_BSPC, KC_HOME, KC_END,                       KC_LEFT, KC_RGHT, KC_DEL,
+        /* thumb keys: */                      KC_SPC,  KC_TAB,  KC_PGUP,                      KC_UP,   KC_ENT,  KC_SPC,
+        /* thumb keys: */                                        KC_PGDN,                      KC_DOWN
+        ),
+    
+    /* This is the "function key locked" layer.  It is not documented by
+     * Maltron, so just putting some "Quantum" keycodes here for testing that
+     * the layer exists and Fun Lock LED works. */
+    [_FUNCTION] = LAYOUT(
+        KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_TRNS,KC_TRNS,KC_BTN3,KC_MS_U,KC_WH_U,KC_NO, KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO, 
+        
+        KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  CK_UP,  AU_ON,  KC_MS_L,KC_BTN1,KC_MS_R,KC_NO, KC_TRNS,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  
+        KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  CK_DOWN,AU_OFF, KC_BTN2,KC_MS_D,KC_WH_D,KC_NO, KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,   
+        KC_TRNS,KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  CK_TOGG,KC_NO,  KC_ACL0,KC_ACL1,KC_ACL2,KC_NO, KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,   
+        KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,                                                           KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,   
+        /* */  KC_NO,   KC_NO,  KC_NO,  KC_NO,                                                                           KC_NO,  KC_NO,  KC_NO,  KC_NO,   /* */
+        
+        /* thumb keys: */                      KC_NO,   KC_NO,   KC_NO,                         KC_NO,   KC_NO,   KC_NO, 
+        /* thumb keys: */                      KC_NO,   KC_NO,   KC_NO,                         KC_NO,   KC_NO,   KC_NO, 
+        /* thumb keys: */                                        KC_NO,                         KC_NO
+        )
+};
+
+/* Show "Fun Lock" layer state via the "Fun Lock" LED */
+layer_state_t layer_state_set_user(layer_state_t state) {
+   
+    setPinOutput(LED_FUN_LOCK_PIN);
+   
+    if (layer_state_cmp(state, _FUNCTION))
+        writePinHigh(LED_FUN_LOCK_PIN);
+    else
+        writePinLow(LED_FUN_LOCK_PIN);
+
+    return state;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * fill-column: 76
+ * End:
+ */

+ 17 - 0
keyboards/handwired/dqz11n1g/keymaps/default/readme.md

@@ -0,0 +1,17 @@
+![DQz11N1G-DE Layout Image](https://u.cubeupload.com/ddklg/OPBN5q.jpg)
+
+# Default Layout for DQz11N1G-DE
+
+This is the layout corresponding to what the Maltron keyboard DQz11N1G-DE I
+own came with (using the original pre-installed controller).  Note that this
+differs from German Maltron layout as published on [Maltron's
+website](https://www.maltron.com/germany.html).  Use the photo above as a
+reference for the layout implemented here.
+
+I did not find any official documentation about the the Function Lock key on
+the original Maltron keyboards.  It seems that it implements some of the
+features that are documented for the one-handed Maltron keyboards.  Most
+keys don't send any keycodes at all when function lock is enabed.
+
+We instead map some of the Quantum keycodes (mouse keys and audio control)
+in the middle (keypad) section of the keypad, when Function Lock is enabled.

+ 131 - 0
keyboards/handwired/dqz11n1g/matrix.c

@@ -0,0 +1,131 @@
+/*
+  Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
+
+  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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <avr/io.h>
+
+#include "spi_master.h"
+#include "quantum.h"
+#include "matrix.h"
+
+static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+
+static void unselect_rows(void);
+
+void matrix_init_custom(void) {
+    /* initialize row pins */
+    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+        setPinOutput(row_pins[row]);
+    }
+    unselect_rows();
+
+    /* columns read via shift-register on SPI lines */
+
+    /* Enable SPI, Master, set clock rate fck/2.  First bit already at Qh
+     * output before clock edge (CPHA=0).  SN74HC165 shift register shifts
+     * on low-to-high transition (CPOL=1).  Receive the LSB first (DORD=1).
+     */
+    bool lsbFirst = true;
+    uint8_t mode = 2;  /* CPOL=1, CPHA=0 */
+    uint16_t divisor = 16;
+
+    /* According to Atmega32U4 datasheet, PB0 *must* be set to output,
+     * otherwise it will interfere with SPI master operation.  On pro-micro
+     * it's connected to a yellew LED. */
+    pin_t slavePin = PB0;
+    spi_init();
+    spi_start(slavePin, lsbFirst, mode, divisor);
+
+    /* Initialize pin controlling the shift register's SH/~LD pin */
+    setPinOutput(ROW_SHIFT_PIN);
+}
+
+static void select_row(uint8_t row) {
+    pin_t pin = row_pins[row];
+    if (pin != NO_PIN) {
+        writePinHigh(pin);
+    }
+}
+
+static void unselect_row(uint8_t row) {
+    pin_t pin = row_pins[row];
+    if (pin != NO_PIN) {
+        writePinLow(pin);
+    }
+}
+
+static void unselect_rows(void) {
+    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+        unselect_row(row);
+    }
+}
+
+bool matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+    /* Start with a clear matrix row */
+    matrix_row_t current_row_value = 0;
+
+    /* Set shift register SH/~LD pin to "load" mode */
+    writePinLow(ROW_SHIFT_PIN);
+    select_row(current_row);
+    matrix_output_select_delay();
+
+    /* Set shift register SH/~LD pin to "shift" mode */
+    writePinHigh(ROW_SHIFT_PIN);
+
+    /* For each octet of columns... */
+    for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index += 8) {
+        spi_status_t read_result = spi_read();
+        if (read_result >= 0) {
+            /* only if SPI read successful: populate the matrix row with the
+               state of the 8 consecutive column bits */
+            current_row_value |= ((matrix_row_t)read_result << col_index);
+        }
+    }
+
+    /* Unselect row & wait for all columns signals to go high. */
+    unselect_row(current_row);
+    matrix_output_unselect_delay(current_row, current_row_value != 0); 
+
+    /* Update row in matrix. */
+    if (current_row_value != current_matrix[current_row]) {
+        current_matrix[current_row] = current_row_value;
+        return true;
+    }
+
+    return false;
+}
+
+bool matrix_scan_custom(matrix_row_t curr_matrix[]) {
+    bool changed = false;
+
+    /* set row, read cols */
+    for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
+        changed |= matrix_read_cols_on_row(curr_matrix, current_row);
+    }
+
+    return changed;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * fill-column: 76
+ * End:
+ */

+ 80 - 0
keyboards/handwired/dqz11n1g/readme.md

@@ -0,0 +1,80 @@
+# DQz11N1G
+
+![DQz11N1G](https://u.cubeupload.com/ddklg/OPBN5q.jpg)
+
+Firmware for a DIY controller replacement for one of the ortholinear contoured
+keyboards manufactured by [PCD Maltron Ltd](https://www.maltron.com)
+
+This work here in no way officially associated with PCD Maltron Ltd and comes
+with NO WARRANTY.  Modifying your Maltron keyboard as described below will
+certainly void your warranty and may cause damage to your keyboard.  Proceed
+at your own risk!
+
+* maintainer: [David Kuehling](https://github.com/dvdkhlng/qmk_firmware_dqz11n1g)
+* Hardware Supported: Maltron DQz11N1G with a replacement controller board
+  assembled as described below.  The work here is based on a german version
+  of the keyboard: DQz11N1G-DE.  I assume, but don't know for sure, that
+  minor or no changes at all are required to make this work on different
+  language versions of the keyboard.
+* Hardware Availability:
+  * [PCD Maltron Ltd](https://www.maltron.com), for the original keyboard
+  * 1x [Arduino Pro Micro](https://www.sparkfun.com/products/12640)
+  * 3x [SN74HC165](https://www.ti.com/product/SN74HC165)
+  * 1x DIL connector 2 rows a 17 pins.
+  * 19x pull-down resistors (10k Ohm),
+  * 4 LED current limiting resistors (not sure about the correct resistance,
+    using 470 Ohm here)
+
+Make example for this keyboard (after setting up your build environment):
+
+    make handwired/dqz11n1g:default
+
+## In Detail
+
+[PCD Maltron Ltd](https://www.maltron.com) manufacturs ergonomic keyboards
+that appear to be hand-wired internally.  For the Maltron DQz11N1G-DE
+keyboard that I happen to own, the keyboard matrix is wired to a 34-pin DIL
+connector.  This makes it rather easy to replace the proprietary
+controller-board with a self-made board based on the QMK firmware.
+
+I don't really like the default layout of my Maltron DQz11N1G-DE keyboard,
+and modding it to work with QMK allows me to adapt it to my needs.  It
+especially allows for the two space keys to assume different roles, thereby
+creating an additional easily reachable thumb-key.
+
+### Internal Details of Keyboard Matrix and DIL Connector
+
+![DQz11N1G-DE keyboard matrix](https://u.cubeupload.com/ddklg/OJFue6.jpg)
+
+![DQz11N1G-DE keyboard matrix connector](https://u.cubeupload.com/ddklg/fjFXeL.png)
+
+### Replacement Keyboard Controller Board
+
+Due to supply chain problems, I decided to base this on an
+Arduino-compatible [Pro Micro](https://www.sparkfun.com/products/12640)
+board which is still easy to source.
+
+Unfortunately pin-count of the DQz11N1G-DE's keyboard matrix is way beyond
+the Pro Micro's available I/O pin count.  I'm using three 8-bit
+shift-registers ([SN74HC165](https://www.ti.com/product/SN74HC165) ) to
+connect the 19 colums of the keyboard matrix for readout.  Due to diode
+direction in DQz11N1G-DE we also need 19 pull-down resistors one for each of
+the utilized shift-register inputs.
+
+This is a design sketch of the replacement board this is based on.  Note how
+we need a custom matrix.c source file to deal with the shift register based
+keyboard readout.
+
+![Sketch of Keyboard Controller Board](https://u.cubeupload.com/ddklg/GBZgSf.png)
+
+This is how the assembled controller board looks like, on the right side you
+see the original PIC-based controller the keyboard ships with.
+
+![The assembled controller next to the original controller the keyboard ships with](https://u.cubeupload.com/ddklg/KLYF2V.jpg)
+
+Inside of the keyboard after installing the new controller board:
+
+![Installed controller](https://u.cubeupload.com/ddklg/Br0aiF.jpg)
+
+(Not visible in the photo: I drilled hole into the keyboard above the USB
+connector for a reset switch to simplify flashing controller firmware)

+ 24 - 0
keyboards/handwired/dqz11n1g/rules.mk

@@ -0,0 +1,24 @@
+# MCU name
+MCU = atmega32u4
+
+# Bootloader selection
+BOOTLOADER = caterina
+
+# Keyboard matrix uses shift-registers read via SPI
+CUSTOM_MATRIX = lite
+SRC += matrix.c 
+QUANTUM_LIB_SRC += spi_master.c
+
+# Build Options
+#   change yes to no to disable
+#
+BOOTMAGIC_ENABLE = no       # Enable Bootmagic Lite
+MOUSEKEY_ENABLE = yes       # Mouse keys
+EXTRAKEY_ENABLE = yes       # Audio control and System control
+CONSOLE_ENABLE = no         # Console for debug
+COMMAND_ENABLE = yes        # Commands for debug and configuration
+NKRO_ENABLE = no            # Enable N-Key Rollover
+BACKLIGHT_ENABLE = no       # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no        # Enable keyboard RGB underglow
+AUDIO_ENABLE = yes          # Audio output
+