summaryrefslogtreecommitdiffstats
path: root/keyboards/hhkb
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/hhkb')
-rw-r--r--keyboards/hhkb/yang/config.h130
-rw-r--r--keyboards/hhkb/yang/info.json71
-rw-r--r--keyboards/hhkb/yang/keymaps/default/keymap.c73
-rw-r--r--keyboards/hhkb/yang/keymaps/kanru/config.h21
-rw-r--r--keyboards/hhkb/yang/keymaps/kanru/keymap.c126
-rw-r--r--keyboards/hhkb/yang/matrix.c173
-rw-r--r--keyboards/hhkb/yang/memo.md135
-rw-r--r--keyboards/hhkb/yang/readme.md118
-rw-r--r--keyboards/hhkb/yang/rules.mk27
-rw-r--r--keyboards/hhkb/yang/yang.c118
-rw-r--r--keyboards/hhkb/yang/yang.h36
11 files changed, 1028 insertions, 0 deletions
diff --git a/keyboards/hhkb/yang/config.h b/keyboards/hhkb/yang/config.h
new file mode 100644
index 0000000000..693b2501bb
--- /dev/null
+++ b/keyboards/hhkb/yang/config.h
@@ -0,0 +1,130 @@
+/*
+Copyright 2020 Kan-Ru Chen <kanru@kanru.info>
+Copyright 2012 Jun Wako <wakojun@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
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0x4848 // HH = happy hacking
+#define PRODUCT_ID 0x0001 // ANSI HHKB
+#define DEVICE_VER 0x0104
+#define MANUFACTURER YANG
+#define PRODUCT HHKB BLE Keyboard
+
+/* key matrix size */
+#define MATRIX_ROWS 8
+#define MATRIX_COLS 8
+
+/* matrix power saving */
+#define MATRIX_POWER_SAVE_TIMEOUT_MS 10000
+#define MATRIX_POWER_SAVE_TIMEOUT_L2_MS 1800000
+#define MATRIX_POWER_SAVE_TIMEOUT_L3_MS 7200000
+
+#define LED_CAPS_LOCK_PIN F4
+
+#ifdef BLUETOOTH_ENABLE
+# define OUTPUT_DEFAULT OUTPUT_AUTO
+
+# undef SERIAL_UART_BAUD
+# undef SERIAL_UART_DATA
+# undef SERIAL_UART_UBRR
+# undef SERIAL_UART_RXD_VECT
+# undef SERIAL_UART_TXD_READY
+# undef SERIAL_UART_INIT
+
+# define SERIAL_UART_BAUD 76800
+# define SERIAL_UART_DATA UDR1
+# define SERIAL_UART_UBRR (F_CPU / (8UL * SERIAL_UART_BAUD) - 1)
+# define SERIAL_UART_RXD_VECT USART1_RX_vect
+# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1))
+# define SERIAL_UART_INIT() \
+ do { \
+ cli(); \
+ /* baud rate */ \
+ UBRR1L = SERIAL_UART_UBRR; \
+ /* baud rate */ \
+ UBRR1H = SERIAL_UART_UBRR >> 8; \
+ /* enable TX */ \
+ UCSR1B |= (0 << TXCIE1) | (1 << TXEN1); \
+ /* enable RX */ \
+ UCSR1B |= (1 << RXCIE1) | (1 << RXEN1); \
+ /* parity: none(00), even(01), odd(11) */ \
+ UCSR1C |= (0 << UPM11) | (0 << UPM10); \
+ /* 2x speed (error = 0.2%) */ \
+ UCSR1A |= (1 << U2X1); \
+ sei(); \
+ } while (0)
+#endif
+
+/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
+//#define LOCKING_SUPPORT_ENABLE
+/* Locking resynchronize hack */
+//#define LOCKING_RESYNC_ENABLE
+
+/* If defined, GRAVE_ESC will always act as ESC when CTRL is held.
+ * This is useful for the Windows task manager shortcut (ctrl+shift+esc).
+ */
+//#define GRAVE_ESC_CTRL_OVERRIDE
+
+/*
+ * Force NKRO
+ *
+ * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
+ * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
+ * makefile for this to work.)
+ *
+ * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
+ * until the next keyboard reset.
+ *
+ * NKRO may prevent your keystrokes from being detected in the BIOS, but it is
+ * fully operational during normal computer usage.
+ *
+ * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
+ * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
+ * bootmagic, NKRO mode will always be enabled until it is toggled again during a
+ * power-up.
+ *
+ */
+//#define FORCE_NKRO
+
+/*
+ * Feature disable options
+ * These options are also useful to firmware size reduction.
+ */
+
+/* disable debug print */
+//#define NO_DEBUG
+
+/* disable print */
+//#define NO_PRINT
+
+/* disable action features */
+//#define NO_ACTION_LAYER
+//#define NO_ACTION_TAPPING
+//#define NO_ACTION_ONESHOT
+
+
+/* Bootmagic Lite key configuration */
+//#define BOOTMAGIC_LITE_ROW 0
+//#define BOOTMAGIC_LITE_COLUMN 0
+
+//#define DEBUG_MATRIX_SCAN_RATE
+
+// Disable debounce
+#define DEBOUNCE 0
diff --git a/keyboards/hhkb/yang/info.json b/keyboards/hhkb/yang/info.json
new file mode 100644
index 0000000000..b38b8a6881
--- /dev/null
+++ b/keyboards/hhkb/yang/info.json
@@ -0,0 +1,71 @@
+{
+ "keyboard_name": "YANG HHKB BLE",
+ "url": "",
+ "maintainer": "qmk",
+ "layouts": {
+ "LAYOUT_60_hhkb": {
+ "layout": [
+ { "label": "Esc", "x": 0, "y": 0 },
+ { "label": "!", "x": 1, "y": 0 },
+ { "label": "@", "x": 2, "y": 0 },
+ { "label": "#", "x": 3, "y": 0 },
+ { "label": "$", "x": 4, "y": 0 },
+ { "label": "%", "x": 5, "y": 0 },
+ { "label": "^", "x": 6, "y": 0 },
+ { "label": "&", "x": 7, "y": 0 },
+ { "label": "*", "x": 8, "y": 0 },
+ { "label": "(", "x": 9, "y": 0 },
+ { "label": ")", "x": 10, "y": 0 },
+ { "label": "_", "x": 11, "y": 0 },
+ { "label": "+", "x": 12, "y": 0 },
+ { "label": "|", "x": 13, "y": 0 },
+ { "label": "~", "x": 14, "y": 0 },
+ { "label": "Tab", "x": 0, "y": 1, "w": 1.5 },
+ { "label": "Q", "x": 1.5, "y": 1 },
+ { "label": "W", "x": 2.5, "y": 1 },
+ { "label": "E", "x": 3.5, "y": 1 },
+ { "label": "R", "x": 4.5, "y": 1 },
+ { "label": "T", "x": 5.5, "y": 1 },
+ { "label": "Y", "x": 6.5, "y": 1 },
+ { "label": "U", "x": 7.5, "y": 1 },
+ { "label": "I", "x": 8.5, "y": 1 },
+ { "label": "O", "x": 9.5, "y": 1 },
+ { "label": "P", "x": 10.5, "y": 1 },
+ { "label": "{", "x": 11.5, "y": 1 },
+ { "label": "}", "x": 12.5, "y": 1 },
+ { "label": "Delete", "x": 13.5, "y": 1, "w": 1.5 },
+ { "label": "Control", "x": 0, "y": 2, "w": 1.75 },
+ { "label": "A", "x": 1.75, "y": 2 },
+ { "label": "S", "x": 2.75, "y": 2 },
+ { "label": "D", "x": 3.75, "y": 2 },
+ { "label": "F", "x": 4.75, "y": 2 },
+ { "label": "G", "x": 5.75, "y": 2 },
+ { "label": "H", "x": 6.75, "y": 2 },
+ { "label": "J", "x": 7.75, "y": 2 },
+ { "label": "K", "x": 8.75, "y": 2 },
+ { "label": "L", "x": 9.75, "y": 2 },
+ { "label": ":", "x": 10.75, "y": 2 },
+ { "label": "\"", "x": 11.75, "y": 2 },
+ { "label": "Return", "x": 12.75, "y": 2, "w": 2.25 },
+ { "label": "Shift", "x": 0, "y": 3, "w": 2.25 },
+ { "label": "Z", "x": 2.25, "y": 3 },
+ { "label": "X", "x": 3.25, "y": 3 },
+ { "label": "C", "x": 4.25, "y": 3 },
+ { "label": "V", "x": 5.25, "y": 3 },
+ { "label": "B", "x": 6.25, "y": 3 },
+ { "label": "N", "x": 7.25, "y": 3 },
+ { "label": "M", "x": 8.25, "y": 3 },
+ { "label": "<", "x": 9.25, "y": 3 },
+ { "label": ">", "x": 10.25, "y": 3 },
+ { "label": "?", "x": 11.25, "y": 3 },
+ { "label": "Shift", "x": 12.25, "y": 3, "w": 1.75 },
+ { "label": "Fn", "x": 14, "y": 3 },
+ { "label": "", "x": 1.5, "y": 4 },
+ { "label": "", "x": 2.5, "y": 4, "w": 1.5 },
+ { "x": 4, "y": 4, "w": 6 },
+ { "label": "", "x": 10, "y": 4, "w": 1.5 },
+ { "label": "", "x": 11.5, "y": 4 }
+ ]
+ }
+ }
+}
diff --git a/keyboards/hhkb/yang/keymaps/default/keymap.c b/keyboards/hhkb/yang/keymaps/default/keymap.c
new file mode 100644
index 0000000000..f91e1fc243
--- /dev/null
+++ b/keyboards/hhkb/yang/keymaps/default/keymap.c
@@ -0,0 +1,73 @@
+/* -*- eval: (turn-on-orgtbl); -*-
+ * default HHKB Layout
+ *
+ * Copyright 2021 Kan-Ru Chen <kanru@kanru.info>
+ *
+ * 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 custom_layers {
+ BASE,
+ HHKB,
+};
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ /* BASE Level: Default Layer
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | \ | ` |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Tab | Q | W | E | R | T | Y | U | I | O | P | [ | ] | Backs | |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Cont | A | S | D | F | G | H | J | K | L | ; | ' | Ent | | |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Shift | Z | X | C | V | B | N | M | , | . | / | Shift | Fn0 | | |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+
+ |------+------+-----------------------+------+------|
+ | LAlt | LGUI | ******* Space ******* | RGUI | RAlt |
+ |------+------+-----------------------+------+------|
+ */
+
+ [BASE] = LAYOUT_60_hhkb( // default layer
+ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSLS, KC_GRV,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSPC,
+ KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, MO(HHKB),
+ KC_LALT, KC_LGUI, /* */ KC_SPC, KC_RGUI, KC_RALT),
+
+ /* Layer HHKB: HHKB mode (HHKB Fn)
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | Pwr | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | Ins | Del |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | Caps | | | | | | | | Psc | Slk | Pus | Up | | Backs | |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | | VoD | VoU | Mut | | | * | / | Hom | PgU | Lef | Rig | Enter | | |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | | | | | | | + | - | End | PgD | Dow | | | | |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+
+ |------+------+----------------------+------+------+
+ | **** | **** | ******************** | **** | **** |
+ |------+------+----------------------+------+------+
+
+ */
+
+ [HHKB] = LAYOUT_60_hhkb(
+ KC_PWR, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_INS, KC_DEL,
+ KC_CAPS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_SLCK, KC_PAUS, KC_UP, KC_TRNS, KC_BSPC,
+ KC_TRNS, KC_VOLD, KC_VOLU, KC_MUTE, KC_TRNS, KC_TRNS, KC_PAST, KC_PSLS, KC_HOME, KC_PGUP, KC_LEFT, KC_RGHT, KC_PENT,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PPLS, KC_PMNS, KC_END, KC_PGDN, KC_DOWN, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS)};
diff --git a/keyboards/hhkb/yang/keymaps/kanru/config.h b/keyboards/hhkb/yang/keymaps/kanru/config.h
new file mode 100644
index 0000000000..81fef2ea5e
--- /dev/null
+++ b/keyboards/hhkb/yang/keymaps/kanru/config.h
@@ -0,0 +1,21 @@
+/* Copyright 2021 Kan-Ru Chen <kanru@kanru.info>
+ *
+ * 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 MOUSEKEY_DELAY 90
+#define MOUSEKEY_INTERVAL 16
+#define MOUSEKEY_MAX_SPEED 4
+#define MOUSEKEY_WHEEL_INTERVAL 50
diff --git a/keyboards/hhkb/yang/keymaps/kanru/keymap.c b/keyboards/hhkb/yang/keymaps/kanru/keymap.c
new file mode 100644
index 0000000000..c5d57c4cb3
--- /dev/null
+++ b/keyboards/hhkb/yang/keymaps/kanru/keymap.c
@@ -0,0 +1,126 @@
+/* -*- eval: (turn-on-orgtbl); -*-
+ * kanru's HHKB Layout
+ *
+ * Copyright 2021 Kan-Ru Chen <kanru@kanru.info>
+ *
+ * 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
+#include <stdio.h>
+
+enum custom_layers {
+ BASE,
+ HHKB,
+ MOUSE,
+};
+
+#define BATTERY_FULL 550
+#define BATTERY_EMPTY 326
+
+enum my_keycodes { KC_VBAT = SAFE_RANGE };
+
+uint32_t adafruit_ble_read_battery_voltage(void);
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+#ifdef BLUETOOTH_ENABLE
+ case KC_VBAT:
+ if (record->event.pressed) {
+ char vbat[8];
+ uint8_t level = (adafruit_ble_read_battery_voltage() - BATTERY_EMPTY) / (float)(BATTERY_FULL - BATTERY_EMPTY) * 100;
+ snprintf(vbat, sizeof(vbat), "%d", level);
+ send_string(vbat);
+ }
+ return false;
+#endif
+ default:
+ return true;
+ }
+}
+
+// clang-format off
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ /* BASE Level: Default Layer
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | \ | ` |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Tab | Q | W | E | R | T | Y | U | I | O | P | [ | ] | Backs | |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Cont | A | S | D | F | G | H | J | K | L | ; | ' | Ent | | |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+ | Shift | Z | X | C | V | B | N | M | , | . | / | Shift | Fn0 | | |
+ |-------+---+---+---+---+---+---+---+---+---+---+-------+-----+-------+---|
+
+ |------+------+-----------------------+------+------|
+ | LAlt | LGUI | ******* Space ******* | RGUI | RAlt |
+ |------+------+-----------------------+------+------|
+ */
+
+ [BASE] = LAYOUT_60_hhkb( // default layer
+ LT(MOUSE, KC_ESC), KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSLS, KC_GRV,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSPC,
+ KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, MO(HHKB),
+ KC_LALT, KC_LGUI, /* */ KC_SPC, KC_RGUI, KC_RALT),
+
+ /* Layer HHKB: HHKB mode (HHKB Fn)
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | Pwr | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | Ins | Del |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | Caps | | | BAT | | | | | Psc | Slk | Pus | Up | | Backs | |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | | VoD | VoU | Mut | | | * | / | Hom | PgU | Lef | Rig | Enter | | |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+ | | | | | | | + | - | End | PgD | Dow | | | | |
+ |------+-----+-----+-----+----+----+----+----+-----+-----+-----+-----+-------+-------+-----|
+
+ |------+------+----------------------+------+------+
+ | **** | **** | ******************** | **** | **** |
+ |------+------+----------------------+------+------+
+
+ */
+
+ [HHKB] = LAYOUT_60_hhkb(
+ KC_PWR, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_INS, KC_DEL,
+ KC_CAPS, KC_TRNS, KC_TRNS, KC_VBAT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_SLCK, KC_PAUS, KC_UP, KC_TRNS, KC_BSPC,
+ KC_TRNS, KC_VOLD, KC_VOLU, KC_MUTE, KC_TRNS, KC_TRNS, KC_PAST, KC_PSLS, KC_HOME, KC_PGUP, KC_LEFT, KC_RGHT, KC_PENT,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PPLS, KC_PMNS, KC_END, KC_PGDN, KC_DOWN, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
+
+ /* Layer MOUSE: Mouse Key mode (ESC)
+ |------+------+------+-----+----+----+----+----+----+----+-----+-----+-------+-------+----- |
+ | | | | | | | | | | | | | | | |
+ |------+------+------+-----+----+----+----+----+----+----+-----+-----+-------+-------+-----|
+ | | BTN1 | WH_U | | | | | | | | | | | | |
+ |------+------+------+-----+----+----+----+----+----+----+-----+-----+-------+-------+-----|
+ | | BTN2 | WH_D | | | |MS_L|MS_D|MS_U|MS_R| | | | | |
+ |------+------+------+-----+----+----+----+----+----+----+-----+-----+-------+-------+-----|
+ | | BTN3 | | | | | | | | | | | | | |
+ |------+------+------+-----+----+----+----+----+----+----+-----+-----+-------+-------+-----|
+
+ |------+------+----------------------+------+------+
+ | **** | **** | ******************** | **** | **** |
+ |------+------+----------------------+------+------+
+
+ */
+
+ [MOUSE] = LAYOUT_60_hhkb(
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_BTN1, KC_WH_U, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_BTN2, KC_WH_D, KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_U, KC_MS_R, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_BTN3, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS)
+};
+// clang-format on
diff --git a/keyboards/hhkb/yang/matrix.c b/keyboards/hhkb/yang/matrix.c
new file mode 100644
index 0000000000..f0eccc899d
--- /dev/null
+++ b/keyboards/hhkb/yang/matrix.c
@@ -0,0 +1,173 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+Copyright 2020 Kan-Ru Chen <kanru@kanru.info>
+
+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"
+
+#ifdef BLUETOOTH_ENABLE
+# include "adafruit_ble.h"
+#endif
+
+#define RELAX_TIME_US 5
+#define ADC_READ_TIME_US 5
+
+uint8_t power_save_level;
+
+static uint32_t matrix_last_modified = 0;
+
+static inline void key_strobe_high(void) { writePinLow(B6); }
+static inline void key_strobe_low(void) { writePinHigh(B6); }
+static inline bool key_state(void) { return readPin(D7); }
+static inline void key_prev_on(void) { writePinHigh(B7); }
+static inline void key_prev_off(void) { writePinLow(B7); }
+static inline bool key_power_state(void) { return !readPin(D6); }
+
+static inline void suspend_power_down_longer(void) {
+ uint8_t times = 60;
+ while (--times) suspend_power_down();
+}
+
+void matrix_power_up(void) {
+ dprint("[matrix_on]\n");
+ // change pins output
+ DDRB = 0xFF;
+ PORTB = 0x40;
+ // switch MOS FET on
+ setPinOutput(D6);
+ writePinLow(D6);
+}
+
+void matrix_power_down(void) {
+ dprint("[matrix_off]\n");
+ // input with pull-up consumes less than without it when pin is open
+ DDRB = 0x00;
+ PORTB = 0xFF;
+ // switch MOS FET off
+ setPinOutput(D6);
+ writePinHigh(D6);
+}
+
+static inline void key_select_row(uint8_t row) { PORTB = (PORTB & 0b11111000) | ((row)&0b111); }
+static inline void key_select_col(uint8_t col) { PORTB = (PORTB & 0b11000111) | (((col)&0b111) << 3); }
+static inline bool key_prev_was_on(matrix_row_t matrix[], uint8_t row, uint8_t col) { return matrix[row] & (1 << col); }
+
+void matrix_init_custom(void) { power_save_level = 0; }
+
+bool matrix_scan_custom(matrix_row_t current_matrix[]) {
+ bool matrix_has_changed = false;
+
+ // power on
+ if (!key_power_state()) {
+ matrix_power_up();
+ }
+ for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+ matrix_row_t last_row_value = current_matrix[row];
+
+ key_select_row(row);
+ wait_us(RELAX_TIME_US);
+
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ // Hysteresis control: assert(1) when previous key state is on
+ if (key_prev_was_on(current_matrix, row, col)) {
+ key_prev_on();
+ } else {
+ key_prev_off();
+ }
+
+ // Disable interrupts to encure the ADC timing is correct
+ cli();
+
+ // strobe
+ key_select_col(col);
+ key_strobe_high();
+
+ // Wait for ADC to outputs its value.
+ // 1us was ok on one HHKB, but not worked on another.
+ // no wait doesn't work on Teensy++ with pro(1us works)
+ // no wait does work on tmk PCB(8MHz) with pro2
+ // 1us wait does work on both of above
+ // 1us wait doesn't work on tmk(16MHz)
+ // 5us wait does work on tmk(16MHz)
+ // 5us wait does work on tmk(16MHz/2)
+ // 5us wait does work on tmk(8MHz)
+ // 10us wait does work on Teensy++ with pro
+ // 10us wait does work on 328p+iwrap with pro
+ // 10us wait doesn't work on tmk PCB(8MHz) with pro2(very lagged scan)
+ wait_us(ADC_READ_TIME_US);
+
+ if (key_state()) {
+ current_matrix[row] &= ~(1 << col);
+ } else {
+ current_matrix[row] |= (1 << col);
+ }
+
+ key_strobe_low();
+ sei();
+
+ // Make sure enough time has elapsed since the last call
+ // This is to ensure the matrix voltages have relaxed
+ wait_us(RELAX_TIME_US);
+ }
+ if (current_matrix[row] ^ last_row_value) {
+ matrix_has_changed = true;
+ matrix_last_modified = timer_read32();
+ }
+ }
+
+ // Power saving
+ uint32_t time_diff = timer_elapsed32(matrix_last_modified);
+ if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_L3_MS) {
+ power_save_level = 3;
+ suspend_power_down_longer();
+ } else if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_L2_MS) {
+ power_save_level = 2;
+#ifdef BLUETOOTH_ENABLE
+ if (!adafruit_ble_is_connected()) {
+ power_save_level = 3;
+ }
+#endif
+ suspend_power_down_longer();
+ } else if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_MS) {
+ power_save_level = 1;
+ suspend_power_down();
+ } else {
+ if (power_save_level != 0) {
+ power_save_level = 0;
+ suspend_wakeup_init();
+ }
+ }
+
+ return matrix_has_changed;
+}
+
+bool adafruit_ble_delbonds(void);
+bool adafruit_ble_reconnect(void);
+
+bool command_extra(uint8_t code) {
+ switch (code) {
+#ifdef BLUETOOTH_ENABLE
+ case KC_R:
+ adafruit_ble_delbonds();
+ return true;
+ case KC_S:
+ adafruit_ble_reconnect();
+ return true;
+#endif
+ default:
+ return false;
+ }
+}
diff --git a/keyboards/hhkb/yang/memo.md b/keyboards/hhkb/yang/memo.md
new file mode 100644
index 0000000000..5c710482b3
--- /dev/null
+++ b/keyboards/hhkb/yang/memo.md
@@ -0,0 +1,135 @@
+## Hardware Information
+
+The YANG HHKB BLE controller design is similiar to hasu's
+controller. Most pins are compatiable.
+
+**MCU**: ATmega32U4
+**Bluetooth**: MDBT40 (nRF51822-based), with Adafruit Bluefruit LE UART Friend firmware.
+**Power**: 3.3V
+**CPU Frequency**: 8MHz
+**Bootloader**: Lufa MassStorage
+
+## Pin usage
+
+| Description | HASU pin usage | YANG mod changed |
+|:------------------------------------ | ---------------------- | -------------------------- |
+| ~KEY: Lo(0) when key is pressed | PD7 input(with pullup) | |
+| Hysteresis: Hi(1) if key was pressed | PB7 output | |
+| Row selector bit0 | PB0 output | |
+| Row selector bit1 | PB1 output | |
+| Row selector bit2 | PB2 output | |
+| Col selector bit0 | PB3 output | |
+| Col selector bit1 | PB4 output | |
+| Col selector bit2 | PB5 output | |
+| Key unable | PB6 output | |
+| Switch power | PD4 output | PD6 output (PMOS FET) |
+| Bluetooth UART Rx | PC4 input | PD2 |
+| Bluetooth UART Tx | PC5 output | PD3 |
+| Bluetooth power | | PD5 output (low: power on) |
+| LED 0 | | PF4 |
+| LED 2 | | PF1 |
+| LED 4 | | PF0 |
+| Unused for PRO2 | PC6 | |
+| Unused for PRO2 | PC7 | |
+| Inner USB power | | PF7 |
+
+## How to flash LUFA MassStorage bootloader on Linux
+
+The FAT filesystem on Linux very often cannot flush the write cache,
+leading to broken firmware in the flash.
+
+We can use `dd` to write to the virtual block storage directly to
+bypass the vfs layer.
+
+```
+dd if=FLASH.bin of=<path of virtual block device> seek=4
+```
+
+Skip 4 sectors because the default sector size of the virtual device
+and dd is 512 bytes and the emulated flash file starts at 5th sector.
+
+## How to find the path of the virtual block device
+
+After the keyboard boots into flash mode, on Linux system you should
+be able to find the block device in `dmesg` logs.
+
+For exmaple if you type
+
+```
+sudo dmesg
+```
+
+You should find something like
+
+```
+[357885.143593] usb 1-1.4: USB disconnect, device number 24
+[357885.627740] usb 1-1.4: new full-speed USB device number 25 using xhci_hcd
+[357885.729486] usb 1-1.4: New USB device found, idVendor=03eb, idProduct=1962, bcdDevice= 0.01
+[357885.729492] usb 1-1.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0
+[357885.745620] SCSI subsystem initialized
+[357885.746712] usb-storage 1-1.4:1.0: USB Mass Storage device detected
+[357885.746818] scsi host0: usb-storage 1-1.4:1.0
+[357885.746919] usbcore: registered new interface driver usb-storage
+[357885.747689] usbcore: registered new interface driver uas
+[357886.766755] scsi 0:0:0:0: Direct-Access LUFA Bootloader 0.00 PQ: 0 ANSI: 0
+[357886.773216] scsi 0:0:0:0: Attached scsi generic sg0 type 0
+[357886.777474] sd 0:0:0:0: [sdx] 134 512-byte logical blocks: (68.6 kB/67.0 KiB)
+[357886.780300] sd 0:0:0:0: [sdx] Write Protect is off
+[357886.780302] sd 0:0:0:0: [sdx] Mode Sense: 00 00 00 00
+[357886.783113] sd 0:0:0:0: [sdx] Asking for cache data failed
+[357886.783114] sd 0:0:0:0: [sdx] Assuming drive cache: write through
+[357886.842676] sdx:
+[357886.859528] sd 0:0:0:0: [sdx] Attached SCSI removable disk
+```
+
+The `sdx` is the block device name and the full path is at `/dev/sdx`
+The above flash command will become
+
+```
+dd if=FLASH.bin of=/dev/sdx seek=4
+```
+
+## Adafruit Bluefruit LE UART configuraton
+
+The default baud rate used by the firmware is 76800 although adafruit
+do not recommend using higher baudrates than 9600 because the nRF51
+UART can drop characters.
+
+Double speed mode to get more accurate async reading because the F_CPU
+speed is 8MHz.
+
+## Power saving mode design
+
+Power saving is only enabled when USB is detached and using battery
+power. Here we define several levels of power saving mode, each saves
+more power but takes longer to resume operation.
+
+1. Level 1: idle mode is activated after a short configurable time
+ (MATRIX_POWER_SAVE_TIMEOUT_MS) MCU is put into sleep mode and only
+ scan the matrix per 15ms. PORTB pins are set to input with pull-up
+ to save power. Sensing PCB is powered down between scans.
+
+2. Level 2: after idling for longer (MATRIX_POWER_SAVE_TIMEOUT_L2_MS)
+ we entry this state. Matrix scan is skipped until the time lapses
+ 900ms.
+
+2. Level 3: sleep mode is activated after a longer timeout
+ (MATRIX_POWER_SAVE_TIMEOUT_L3_MS) Bluetooth module is powered down.
+
+## Battery reading
+
+VBAT is connected to AIN6 pin on the MDBT40 module and the AREF pin is
+the reference voltage. Doing a ADC with AT+HWDAC=6 will return the
+difference between VBAT and VREF.
+
+It seems when fully charged the ADC read is 550. Likely VREF is 3311mV
+and the fully charged VBAT is thus 3861mV.
+
+Enable battery service with AT+BLEBATTEN=1 first then we can update the
+battery level by using AT+BLEBATTVAL=%d
+
+## References
+
+* https://github.com/joric/qmk/wiki/hhkb_ble
+* https://github.com/tomsmalley/custom-topre-guide
+* https://github.com/abcminiuser/lufa/blob/master/Bootloaders/MassStorage/Lib/VirtualFAT.h
diff --git a/keyboards/hhkb/yang/readme.md b/keyboards/hhkb/yang/readme.md
new file mode 100644
index 0000000000..6f85c0f198
--- /dev/null
+++ b/keyboards/hhkb/yang/readme.md
@@ -0,0 +1,118 @@
+# HHKB Alternate Controller (YANG HHKB BLE Mod)
+
+![YANG HHKB BLE Mod](https://i.imgur.com/aZP1GYc.jpeg)
+
+An alternative controler for the HHKB designed by YANG (yangdigi)
+based on the hasu controller.
+
+* Keyboard Maintainer: [Kan-Ru Chen](https://github.com/kanru)
+* Hardware Supported: YANG HHKB BLE Controller
+* Hardware Availability: https://kbdfans.com/products/hhkb-ble-mod-upgrade-module
+
+Make example for this keyboard (after setting up your build environment):
+
+ make hhkb/yang:default
+
+To flash, first boot your keyboard into bootloader (hold ESC and attach usb cable)
+then a virtual USB storage should appear. You can copy the `hhkb_yang_default.bin`
+file to the virtual USB storage and override the `HHKB_BLE.BIN` file in there.
+
+Make sure to unmount and eject the virtual USB storage.
+
+## Features:
+
+- [x] QMK (via USB)
+- [x] Bluetooth (BLE)
+- [x] Power saving mode
+ - [x] Idle mode
+ - [x] Deep sleep mode
+- [x] LEDs
+- [x] Battery service
+- [x] Special commands
+ - [x] Switch BT peer
+
+## Entering flash mode
+
+Different ways to enter flash mode:
+
+* Press and hold the ESC key. Insert the USB cable to enter the flash
+ mode. When the OS shows the drive disk, you can release the key.
+
+* Use the magic command LSHIFT+RSHIFT+B to reboot to bootloader then
+ quickly hold the ESC key.
+
+If you reflash the wrong firmware or did not reflash successfully, you
+can no longer enter the flash mode, especially the wireless keyboard
+with battery. You need to turn off the keyboard's power switch, and
+re-enter the flash mode, reflash the correct firmware.
+
+After entering the bootloader(flash mode), three indicators on the top
+right of the HHKB BLE controller will flash. LED3(green) will flash
+quickly when writing firmware to the controller.
+
+If these three leds are not soldered or your hhkb case is black, you
+can't know their status, but you can still see LED3 under the right
+USB port.
+
+## How to reliably flash LUFA MassStorage bootloader on Linux
+
+The FAT filesystem on Linux very often cannot flush the write cache,
+leading to broken firmware in the flash.
+
+We can use `dd` to write to the virtual block storage directly to
+bypass the vfs layer.
+
+```
+dd if=FLASH.bin of=<path of virtual block device> seek=4
+```
+
+Skip 4 sectors because the default sector size of the virtual device
+and dd is 512 bytes and the emulated flash file starts at 5th sector.
+
+## How to find the path of the virtual block device
+
+After the keyboard boots into flash mode, on Linux system you should
+be able to find the block device in `dmesg` logs.
+
+For exmaple if you type
+
+```
+sudo dmesg
+```
+
+You should find something like
+
+```
+[357885.143593] usb 1-1.4: USB disconnect, device