~ruther/qmk_firmware

6b1009b7a876db1f0cc5674cfa64739139ea4098 — Nikolaus Wittenstein 6 years ago 2a33d2c
[Keyboard] Add DataHand keyboard support (#4847)

A keyboards/handwired/datahand/config.h => keyboards/handwired/datahand/config.h +87 -0
@@ 0,0 1,87 @@
/* Copyright 2017-2019 Nikolaus Wittenstein <nikolaus.wittenstein@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#pragma once

#include "config_common.h"

/* USB Device descriptor parameter */
/* Taken from the DataHand PS/2-USB adaptor. */
#define VENDOR_ID       0x13BA
#define PRODUCT_ID      0x0017
#define DEVICE_VER      0x0001
#define MANUFACTURER    DataHand
#define PRODUCT         DataHand
#define DESCRIPTION     DataHand Teensy++ 2.0 conversion

/* key matrix size */
#define MATRIX_ROWS 13
#define MATRIX_COLS 4

#define DIODE_DIRECTION CUSTOM_MATRIX

/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
#define DEBOUNCING_DELAY 0

/* 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

/*
 * 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

/*
 * Magic Key Options
 *
 * Magic keys are hotkey commands that allow control over firmware functions of
 * the keyboard. They are best used in combination with the HID Listen program,
 * found here: https://www.pjrc.com/teensy/hid_listen.html
 *
 * The options below allow the magic key functionality to be changed. This is
 * useful if your keyboard/keypad is missing keys and you want magic key support.
 */

/* key combination for magic key command */
#define IS_COMMAND() ( \
    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)

/*
 * Command/Windows key option
 *
 * If you define this, the thumb enter key becomes the Command/Windows key. There's still an enter key on the right
 * ring finger, so this key is much better utilized as the otherwise nonexistent Command key. I think some newer
 * DataHands let you remap right ring east as Command, but having it on the thumb is nicer. Comment out this define
 * to use the original layout.
 */
#define DATAHAND_THUMB_RETURN_COMMAND

A keyboards/handwired/datahand/datahand.h => keyboards/handwired/datahand/datahand.h +133 -0
@@ 0,0 1,133 @@
/* Copyright 2017-2019 Nikolaus Wittenstein <nikolaus.wittenstein@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#pragma once

#include "quantum.h"

/* This a shortcut to help you visually see your layout.
 * The first section contains all of the arguements; the second converts the arguments into a two-dimensional array.
 */

/* Each code is three letters
 * l or r - left or right hand
 * p, r, m, i, t - pinky, ring finger, middle finger, index finger, thumb
 * fingers: n, s, e, w, c - north, south, east, west, and center (manual calls this "well" but we already have "west")
 * thumb:   p, n, c, l, u, k - pad, nail, center, lock (harder center), up, knuckle
 */
#define LAYOUT( \
     lpn,             lrn,             lmn,             lin,                rin,             rmn,             rrn,             rpn,      \
lpw, lpc, lpe,   lrw, lrc, lre,   lmw, lmc, lme,   liw, lic, lie,      riw, ric, rie,   rmw, rmc, rme,   rrw, rrc, rre,   rpw, rpc, rpe, \
     lps,             lrs,             lms,             lis,                ris,             rms,             rrs,             rps,      \
                                                       ltp,    ltn,  rtn,    rtp, \
                                                           ltc,          rtc, \
                                                           ltl,          rtl, \
                                                       ltu,    ltk,  rtk,    rtu) \
{ \
  {riw, rin, lpw, lpn},\
  {ric, rie, lpc, lpe},\
  {ris, rms, lps, lrs},\
  {rmw, rmn, lrw, lrn},\
  {rmc, rme, lrc, lre},\
  {rrw, rrn, lmw, lmn},\
  {rrc, rre, lmc, lme},\
  {rrs, rps, lms, lis},\
  {rpw, rpn, liw, lin},\
  {rpc, rpe, lic, lie},\
  {rtk, rtn, ltk, ltn},\
  {rtc, rtl, ltc, ltl},\
  {rtp, rtu, ltp, ltu},\
}

/* Mode LEDs are active-low on Port B on the Teensy. */
#define LED_MODE_PORT PORTB
#define LED_TENKEY    (1<<3)
#define LED_FN        (1<<4)
#define LED_NORMAL    (1<<5)
#define LED_NAS       (1<<6)

/* Lock LEDs are active-low on Port F on the Teensy. */
#define LED_LOCK_PORT   PORTF
#define LED_CAPS_LOCK   (1<<4)
#define LED_MOUSE_LOCK  (1<<5)
#define LED_NUM_LOCK    (1<<6)
#define LED_SCROLL_LOCK (1<<7)


/* Appendix:
 * Table based on https://geekhack.org/index.php?topic=12212.msg2059319#msg2059319
 * Some pin assignments (e.g. for PS/2 I/O) have been fixed.
 *
 * Teensy    Datahand     8051   pin     pin      8051    Datahand             Teensy
 * ------    --------     ----   ---     ---      ----    --------             ------
 * GND       Mtrx send A  P1.0     1      40      VCC     VCC                  VCC
 * PB7       Mtrx send B  P1.1     2      39      P0.0    LED RH NAS           PB6
 * PD0       Mtrx send C  P1.2     3      38      P0.1    LED RH NORM          PB5
 * PD1       Mtrx send D  P1.3     4      37      P0.2    LED RH FCTN          PB4
 * PD2       RH rcv 0     P1.4     5      36      P0.3    LED RH 10K           PB3
 * PD3       RH rcv 1     P1.5     6      35      P0.4    LED RH unused        PB2
 * PD4       LH rcv 0     P1.6     7      34      P0.5    LED RH unused        PE1
 * PD5       LH rcv 1     P1.7     8      33      P0.6    LED RH unused        PE0
 * PD6       Reset button RST      9      32      P0.7    ?                    PE7
 * PD7       ?            P3.0    10      31      VPP     -                    PE6
 * PE0       ?            P3.1    11      30      ALE     -                    GND
 * PE1       kbd data     P3.2    12      29      PSEN    -                    AREF
 * PC0       ?            P3.3    13      28      P2.7    ?                    PF0
 * PC1       kbd clk      P3.4    14      27      P2.6    ?                    PF1
 * PC2       ?            P3.5    15      26      P2.5    ?                    PF2
 * PC3       RAM          P3.6    16      25      P2.4    ?                    PF3
 * PC4       RAM          P3.7    17      24      P2.3    LED D15 LH (CAPLK)   PF4
 * PC5       XTAL2        XTAL2   18      23      P2.2    LED D13 LH (MSELK)   PF5
 * PC6       XTAL1        XTAL1   19      22      P2.1    LED D6  LH (NUMLK)   PF6
 * PC7       GND          GND     20      21      P2.0    LED D14 LH (SCRLK)   PF7
 *
 * JP3 Pinout
 * 2 - keyboard data
 * 3 - keyboard clock
 *
 * In order to get the Teensy to work, we need to move pin 1 to a different pin. This is
 * because on the Teensy pin 1 is ground, but we need to write to pin 1 in order to read
 * the keyboard matrix. An ideal pin to move it to is VPP (pin 31), because this pin tells
 * the 8051 whether it should read from external or internal memory. The Teensy doesn't
 * care about that.
 *
 * The easiest way to reassign the pin is to use standoffs. You can check out this thread:
 * https://geekhack.org/index.php?topic=12212.msg235382#msg235382 for a picture of what
 * this looks like. Note that in the picture the pin has been reassigned to pin 12. We
 * don't want to do that because we're going to use that pin to send data over PS/2.
 *
 * We could if we wanted also reassign the PS/2 pins to Teensy hardware UART pins, but
 * that's more work. Instead we'll just bit-bang PS/2 because it's an old, slow protocol
 * (and because there's already a bit-banged PS/2 host implementation in QMK - we just
 * need to add the device side).
 *
 * So overall, we want the following inputs and outputs:
 * Outputs:
 *   Matrix:
 *     PB7
 *     PD0
 *     PD1
 *     PE6 (moved from pin1, GND)
 *   LEDs:
 *     PB3-6
 *     PF4-7
 * Inputs:
 *   Matrix:
 *     PD2-5
 * I/Os (start up as inputs):
 *   PS/2:
 *     PC1
 *     PE1
 */

A keyboards/handwired/datahand/keymaps/default/keymap.c => keyboards/handwired/datahand/keymaps/default/keymap.c +313 -0
@@ 0,0 1,313 @@
/* Copyright 2017-2019 Nikolaus Wittenstein <nikolaus.wittenstein@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include QMK_KEYBOARD_H

#include <stdbool.h>

/* Datahand features not supported:
 * * All online reprogramming (user settings using the reset button).
 *   * Program Selection features.
 *   * Macros.
 *   * Direct substitutions.
 * * L/R Modf.
 * * Mouse Click Lock (Function Direct Access + Mouse Button key).
 * * Different mouse movement speeds with the two pointer fingers, and using both pointer fingers to move even faster.
 *
 * As far as I know, everything else works.
 */

enum layer {
  NORMAL,
#ifdef DATAHAND_THUMB_RETURN_COMMAND
  NORMAL_THUMB_RETURN_COMMAND,
#endif
  FUNCTION_MOUSE,
  FUNCTION_ARROWS,
  NAS,
  NAS_NUMLOCK,
  NAS_TENKEY,
  NAS_TENKEY_NUMLOCK,

  NUM_LAYERS
};

enum custom_keycodes {
  N = SAFE_RANGE,   /* Normal */
  NS,               /* NAS */
  NSL,              /* NAS Lock */
  NLK,              /* Numlock */
  FN,               /* Function mode - needs to be able to switch to mouse or arrow layer */
  TK0,              /* Ten-key off button */
  TK1,              /* Ten-key on button */
  AR,               /* FN arrow mode */
  MS,               /* FN mouse mode */
  DZ,               /* Double zero button */
};

static bool mouse_enabled = true;
static bool tenkey_enabled = false;
static bool numlock_enabled = false;
static bool nas_locked = false;

/* Declared weak so that it can easily be overridden. */
__attribute__((weak)) const uint16_t PROGMEM keymaps[NUM_LAYERS][MATRIX_ROWS][MATRIX_COLS] = {
[NORMAL] = LAYOUT(
        KC_Q,                     KC_W,                 KC_E,                 KC_R,                       KC_U,                   KC_I,                     KC_O,                    KC_P,
KC_DEL, KC_A, KC_LBRC,    KC_ESC, KC_S, KC_B,   KC_GRV, KC_D, KC_T,   KC_DQT, KC_F, KC_G,           KC_H, KC_J, KC_QUOT,   KC_Y,  KC_K,   KC_COLN,   KC_N,  KC_L, KC_ENT,   KC_RBRC, KC_SCLN, KC_BSLS,
        KC_Z,                     KC_X,                 KC_C,                 KC_V,                       KC_M,                   KC_COMM,                  KC_DOT,                  KC_SLSH,
                                                                          KC_ENT,    KC_TAB,   KC_BSPC,  KC_SPC,
                                                                              KC_LSFT,              NS,
                                                                              KC_CAPS,              NSL,
                                                                          N,         KC_LCTL,  KC_LALT,  FN),

#ifdef DATAHAND_THUMB_RETURN_COMMAND
[NORMAL_THUMB_RETURN_COMMAND] = LAYOUT(
         _______,                    _______,                    _______,                    _______,                       _______,                    _______,                    _______,                    _______,
_______, _______, _______,  _______, _______, _______,  _______, _______, _______,  _______, _______, _______,     _______, _______, _______,  _______, _______, _______,  _______, _______, _______,  _______, _______, _______,
         _______,                    _______,                    _______,                    _______,                       _______,                    _______,                    _______,                    _______,
                                                                                            KC_LCMD,   _______,   _______,   _______,
                                                                                                 _______,              _______,
                                                                                                 _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
#endif

[FUNCTION_MOUSE] = LAYOUT(
         KC_F2,                     KC_F4,                  KC_F6,                   KC_MS_U,                      KC_MS_U,                    KC_F8,                   KC_F10,                  KC_PGUP,
_______, KC_NO, KC_SLCK,   _______, KC_BTN3, NLK,  KC_BTN1, MS, KC_BTN2,    KC_MS_L, KC_BTN1, KC_MS_R,    KC_MS_L, KC_BTN2, KC_MS_R,   KC_END, AR,  KC_LSFT,    KC_INS, KC_9,  KC_ENT,   KC_F11, KC_0,   KC_F12,
         KC_F1,                     KC_F3,                  KC_F5,                   KC_MS_D,                      KC_MS_D,                    KC_F7,                   KC_F9,                   KC_PGDN,
                                                                                             _______,   _______,   _______,   _______,
                                                                                                  _______,              _______,
                                                                                                  _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
[FUNCTION_ARROWS] = LAYOUT(
         _______,                     _______,                     _______,                     KC_UP,                              KC_UP,                       _______,                     _______,                     _______,
_______, _______, _______,   _______, KC_LCTL, _______,   _______, _______, _______,   KC_LEFT, KC_HOME, KC_RGHT,          KC_LEFT, KC_HOME, KC_RGHT,   _______, _______, _______,   _______, _______, _______,   _______, _______, _______,
         _______,                     _______,                     _______,                     KC_DOWN,                            KC_DOWN,                     _______,                     _______,                     _______,
                                                                                             _______,   _______,   _______,   _______,
                                                                                                  _______,              _______,
                                                                                                  _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
[NAS] = LAYOUT(
         KC_EXLM,                    KC_AT,                KC_HASH,                    KC_DLR,                      KC_AMPR,                    KC_ASTR,                    KC_LPRN,                KC_RPRN,
_______, KC_1,   KC_TILD,   _______, KC_2, NLK,   KC_LABK, KC_3,   KC_RABK,   KC_SLSH, KC_4,   KC_5,          KC_6, KC_7,   KC_UNDS,   KC_CIRC, KC_8,   KC_ENT,   KC_SCLN,  KC_9,   KC_BSLS,   TK0, KC_0,   TK1,
         KC_EQL,                     KC_X,                 KC_PERC,                    KC_MINS,                     KC_PLUS,                    KC_DOT,                     KC_SLSH,                KC_QUES,
                                                                                             _______,   _______,   _______,   _______,
                                                                                                  _______,              _______,
                                                                                                  _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
[NAS_NUMLOCK] = LAYOUT(
         _______,                     _______,                     _______,                     _______,                            _______,                     KC_PAST,                     _______,                     _______,
_______, KC_KP_1, _______,   _______, KC_KP_2, _______,   _______, KC_KP_3, _______,   KC_PSLS, KC_KP_4, KC_KP_5,          KC_KP_6, KC_KP_7, _______,   _______, KC_KP_8, _______,   _______, KC_KP_9, KC_PENT,   _______, KC_KP_0, _______,
         KC_PEQL,                     _______,                     _______,                     KC_PMNS,                            KC_PPLS,                     _______,                     KC_PDOT,                     _______,
                                                                                             _______,   _______,   _______,   _______,
                                                                                                  _______,              _______,
                                                                                                  _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
[NAS_TENKEY] = LAYOUT(
         _______,                     _______,                   _______,                    KC_UP,                       KC_7,               KC_8,                   KC_9,                   KC_ASTR,
_______, KC_QUOT, _______,   _______, KC_DLR, _______,  _______, KC_AMPR, _______,  KC_LEFT, KC_HOME, KC_RGHT,      KC_0, KC_4, DZ,  KC_PLUS, KC_5, KC_MINS,  KC_EQL, KC_6, KC_ENT,  _______, KC_DOT, _______,
         KC_LPRN,                     KC_RPRN,                   _______,                    KC_DOWN,                     KC_1,               KC_2,                   KC_3,                   KC_SLSH,
                                                                                             _______,   _______,   _______,   _______,
                                                                                                  _______,              _______,
                                                                                                  _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
[NAS_TENKEY_NUMLOCK] = LAYOUT(
         _______,                    _______,                    _______,                    _______,                       KC_KP_7,                    KC_KP_8,                    KC_KP_9,                    KC_PAST,
_______, _______, _______,  _______, _______, _______,  _______, _______, _______,  _______, _______, _______,     KC_KP_0, KC_KP_4, _______,  KC_PPLS, KC_KP_5, KC_PMNS,  KC_PEQL, KC_KP_6, KC_PENT,  _______, KC_PDOT, _______,
         _______,                    _______,                    _______,                    _______,                       KC_KP_1,                    KC_KP_2,                    KC_KP_3,                    KC_PSLS,
                                                                                             _______,   _______,   _______,   _______,
                                                                                                  _______,              _______,
                                                                                                  _______,              _______,
                                                                                             _______,   _______,   _______,   _______),
};

static void lock_led_set(bool on, uint8_t led) {
  if (on) {
    LED_LOCK_PORT &= ~led;
  } else {
    LED_LOCK_PORT |= led;
  }
}

static void mode_led_set(uint8_t led) {
  static const uint8_t ALL_MODE_LEDS = LED_FN | LED_NORMAL | LED_NAS | LED_TENKEY;
  LED_MODE_PORT |= ALL_MODE_LEDS;
  LED_MODE_PORT &= ~led;
}

static void layer_set(bool on, uint8_t layer) {
  if (on) {
    layer_on(layer);
  } else {
    layer_off(layer);
  }

  if (layer_state_is(NAS) || layer_state_is(NAS_NUMLOCK) || layer_state_is(NAS_TENKEY) || layer_state_is(NAS_TENKEY_NUMLOCK)) {
    if (tenkey_enabled) {
      mode_led_set(LED_NAS | LED_TENKEY);
    } else {
      mode_led_set(LED_NAS);
    }
  } else if (layer_state_is(FUNCTION_MOUSE) || layer_state_is(FUNCTION_ARROWS)) {
    mode_led_set(LED_FN);
  } else if (layer_state_is(NORMAL)) {
    mode_led_set(LED_NORMAL);
  }
}

static void set_normal(void) {
  layer_move(NORMAL);

#ifdef DATAHAND_THUMB_RETURN_COMMAND
  layer_set(true, NORMAL_THUMB_RETURN_COMMAND);
#endif

  /* Then call layer_set to update LEDs. */
  layer_set(true, NORMAL);
}

static void set_nas(bool on) {
  /* Always turn on the base NAS layer so other layers can fall through. */
  layer_set(on, NAS);

  layer_set(on && numlock_enabled, NAS_NUMLOCK);
  layer_set(on && tenkey_enabled, NAS_TENKEY);
  layer_set(on && tenkey_enabled && numlock_enabled, NAS_TENKEY_NUMLOCK);
}

static void set_tenkey(bool on) {
  tenkey_enabled = on;
  
  /* We have to be on the NAS layer in order to be able to toggle TK.
   * Re-toggle it on so that we move to the right layer (and set the right LED).
   */
  set_nas(true);
}

static void toggle_numlock(void) {
  numlock_enabled = !numlock_enabled;
  lock_led_set(numlock_enabled, LED_NUM_LOCK);
  
  if (layer_state_is(NAS)) {
    /* If we're already in NAS, re-set it so that we activate the numlock layer. */
    set_nas(true);
  }
}

static void set_function(void) {
  /* Make sure to turn off NAS if we're entering function */
  set_nas(false);

  /* Always turn on the mouse layer so the arrow layer can fall through. */
  layer_set(true, FUNCTION_MOUSE);
  layer_set(!mouse_enabled, FUNCTION_ARROWS);
}

static void set_mouse_enabled(bool on) {
  mouse_enabled = on;

  /* Re-run set_function to set our layers correctly. */
  set_function();
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  bool pressed = record->event.pressed;
  
  switch(keycode) {
    case N:
    if (pressed) {
      set_normal();
    }
    break;

    case NS:
    if (pressed) {
      nas_locked = false;
    }
    set_nas(pressed);
    break;
    
    case NSL:
    if (pressed) {
      nas_locked = true;
      set_nas(true);
    }
    break;
    
    case NLK:
    if (pressed) {
      toggle_numlock();
      SEND_STRING(SS_DOWN(X_NUMLOCK));
    } else {
      SEND_STRING(SS_UP(X_NUMLOCK));
    }
    break;
    
    case FN:
    if (pressed) {
      set_function();
    }
    break;
    
    case TK0:
    if (pressed) {
      set_tenkey(false);
    }
    break;
    
    case TK1:
    if (pressed) {
      set_tenkey(true);
    }
    break;

    case MS:
    if (pressed) {
      set_mouse_enabled(true);
    }
    break;

    case AR:
    if (pressed) {
      set_mouse_enabled(false);
    }
    break;
    
    case DZ:
    if (pressed) {
      SEND_STRING(SS_TAP(X_KP_0) SS_TAP(X_KP_0));
    }
    break;
  }

  return true;
};

void matrix_init_user(void) {
#ifdef DATAHAND_THUMB_RETURN_COMMAND
  set_normal();
#endif
}

void matrix_scan_user(void) {

}

void led_set_user(uint8_t usb_led) {
  lock_led_set(usb_led & (1<<USB_LED_NUM_LOCK), LED_NUM_LOCK);
  lock_led_set(usb_led & (1<<USB_LED_CAPS_LOCK), LED_CAPS_LOCK);
  lock_led_set(usb_led & (1<<USB_LED_SCROLL_LOCK), LED_SCROLL_LOCK);
}

A keyboards/handwired/datahand/matrix.c => keyboards/handwired/datahand/matrix.c +125 -0
@@ 0,0 1,125 @@
/* Copyright 2017-2019 Nikolaus Wittenstein <nikolaus.wittenstein@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include "datahand.h"

#include "matrix.h"
#include "action.h"

#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>

static matrix_row_t matrix[MATRIX_ROWS];

static matrix_row_t read_cols(void);
static void select_row(uint8_t row);

void matrix_init(void) {
  /* See datahand.h for more detail on pins. */

  /* 7 - matrix scan; 6-3 - mode LEDs */
  DDRB = 0b11111000;

  /* 1-0 - matrix scan */
  DDRD = 0b00000011;

  /* 6 - matrix scan */
  DDRE = 0b01000000;

  /* 7-4 - lock LEDs */
  DDRF = 0b11110000;

  /* Turn off the non-Normal LEDs (they're active low). */
  PORTB |= LED_TENKEY | LED_FN | LED_NAS;

  /* Turn off the lock LEDs. */
  PORTF |= LED_CAPS_LOCK | LED_NUM_LOCK | LED_SCROLL_LOCK | LED_MOUSE_LOCK;

  matrix_init_user();
}

uint8_t matrix_scan(void) {
  for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    select_row(row);
    /* The default hardware works down to at least 100us, but I have a replacement
     * photodiode that responds a little more slowly. Cranking it up to 1000us fixes
     * shadowing issues.
     */
    _delay_us(1000);
    matrix[row] = read_cols();
  }

  matrix_scan_user();

  return 1;
}

matrix_row_t matrix_get_row(uint8_t row) {
  return matrix[row];
}

void matrix_print(void) {
  print("\nr/c 01234567\n");

  for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
    phex(row);
    print(": ");
    print_bin_reverse8(matrix_get_row(row));
    print("\n");
  }
}

bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
  return process_record_user(keycode, record);
}

static void select_row(uint8_t row) {
  /* Original 8051: P1 bits 0-3 (pins 1-4)
   * Teensy++: PE0, PB7, PD0, PD1
   */

  if (row & (1<<0)) {
    PORTE |= (1<<6);
  } else {
    PORTE &= ~(1<<6);
  }

  if (row & (1<<1)) {
    PORTB |= (1<<7);
  } else {
    PORTB &= ~(1<<7);
  }

  if (row & (1<<2)) {
    PORTD |= (1<<0);
  } else {
    PORTD &= ~(1<<0);
  }

  if (row & (1<<3)) {
    PORTD |= (1<<1);
  } else {
    PORTD &= ~(1<<1);
  }
}

static matrix_row_t read_cols(void) {
  /* Original 8051: P1 bits 4-7 (pins 5-8)
   * Teensy++: PD bits 2-5
   */

  return (PIND & 0b00111100) >> 2;
}

A keyboards/handwired/datahand/readme.md => keyboards/handwired/datahand/readme.md +15 -0
@@ 0,0 1,15 @@
# DataHand

A keyboard designed to prevent RSI. See [Wikipedia](https://en.wikipedia.org/wiki/DataHand) and [this website](http://octopup.org/computer/datahand) for more info.

To use this firmware, you have to replace the stock microcontroller with a Teensy++ 2.0. This is relatively easy and also reversible. See the notes at the bottom of datahand.h for more info.

Keyboard Maintainer: [Nikolaus Wittenstein](https://github.com/adzenith)  
Hardware Supported: DataHand Personal or Pro II  
Hardware Availability: No longer in production

Make example for this keyboard (after setting up your build environment):

    make handwired/datahand:default

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

A keyboards/handwired/datahand/rules.mk => keyboards/handwired/datahand/rules.mk +59 -0
@@ 0,0 1,59 @@
# Project-specific includes
SRC = matrix.c

# MCU name
MCU = at90usb1286

# Processor frequency.
#     This will define a symbol, F_CPU, in all source code files equal to the
#     processor frequency in Hz. You can then use this symbol in your source code to
#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done
#     automatically to create a 32-bit value in your source code.
#
#     This will be an integer division of F_USB below, as it is sourced by
#     F_USB after it has run through any CPU prescalers. Note that this value
#     does not *change* the processor frequency - it should merely be updated to
#     reflect the processor speed set externally so that the code can use accurate
#     software delays.
F_CPU = 16000000

#
# LUFA specific
#
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8

# Input clock frequency.
#     This will define a symbol, F_USB, in all source code files equal to the
#     input clock frequency (before any prescaling is performed) in Hz. This value may
#     differ from F_CPU if prescaling is used on the latter, and is required as the
#     raw input clock is fed directly to the PLL sections of the AVR for high speed
#     clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
#     at the end, this will be done automatically to create a 32-bit value in your
#     source code.
#
#     If no clock division is performed on the input clock inside the AVR (via the
#     CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_USB = $(F_CPU)

# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT

BOOTLOADER = halfkay

# Build Options
BOOTMAGIC_ENABLE  = no   # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE   = yes  # Mouse keys(+4700)
EXTRAKEY_ENABLE   = yes  # Audio control and System control(+450)
CONSOLE_ENABLE    = yes  # Console for debug(+400)
COMMAND_ENABLE    = yes  # Commands for debug and configuration
NKRO_ENABLE       = yes  # USB Nkey Rollover
BACKLIGHT_ENABLE  = no   # Enable keyboard backlight functionality on B7 by default
MIDI_ENABLE       = no   # MIDI controls
UNICODE_ENABLE    = no   # Unicode
BLUETOOTH_ENABLE  = no   # Enable Bluetooth with the Adafruit EZ-Key HID
AUDIO_ENABLE      = no   # Audio output on port C6
CUSTOM_MATRIX     = yes  # We definitely have a nonstandard matrix

# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
SLEEP_LED_ENABLE = no       # Breathing sleep LED during USB suspend

M keyboards/readme.md => keyboards/readme.md +1 -0
@@ 38,6 38,7 @@ These keyboards are part of the QMK repository, but their manufacturers are not 
* [Arrow Pad](/keyboards/arrow_pad) &mdash; A custom creation by IBNobody.
* [Atreus](/keyboards/atreus) &mdash; Made by Technomancy.
* [Bantam44](/keyboards/bantam44) &mdash; It is a 44-key 40% staggered keyboard.
* [DataHand](/keyboards/handwired/datahand) &mdash; DataHand keyboard converted to use a Teensy board.
* [Ergodox Infinity](/keyboards/ergodox_infinity) - Ergonomic Split Keyboard by Input Club.
* [GH60](/keyboards/gh60) &mdash; A 60% Geekhack community-driven project.
* [GON NerD](/keyboards/gonnerd) &mdash; Korean custom 60% PCB