Keyboard: Fixing spelling, updating code, finalizing keymap for Dichotomy (#4539)

* Fixing spelling, updating code, finalizing keymap for Dichotomy

* Fixing requested changes in PR

* Further PR-requested changes for convention

* Making macros functionable, removing unecessary defs

* Fixing keymap to properly use previously-changed macros
This commit is contained in:
Snipeye 2018-12-05 19:31:21 -07:00 committed by Drashna Jaelre
parent 8ad561c8f0
commit 57678238a9
10 changed files with 651 additions and 495 deletions

View File

@ -1,67 +0,0 @@
#ifndef DICHOTEMY_H
#define DICHOTEMY_H
#include "quantum.h"
#include "matrix.h"
#include "backlight.h"
#include <stddef.h>
#define red_led_off PORTF |= (1<<5)
#define red_led_on PORTF &= ~(1<<5)
#define blu_led_off PORTF |= (1<<4)
#define blu_led_on PORTF &= ~(1<<4)
#define grn_led_off PORTD |= (1<<1)
#define grn_led_on PORTD &= ~(1<<1)
#define set_led_off red_led_off; grn_led_off; blu_led_off
#define set_led_red red_led_on; grn_led_off; blu_led_off
#define set_led_blue red_led_off; grn_led_off; blu_led_on
#define set_led_green red_led_off; grn_led_on; blu_led_off
#define set_led_yellow red_led_on; grn_led_on; blu_led_off
#define set_led_magenta red_led_on; grn_led_off; blu_led_on
#define set_led_cyan red_led_off; grn_led_on; blu_led_on
#define set_led_white red_led_on; grn_led_on; blu_led_on
/*
#define LED_B 5
#define LED_R 6
#define LED_G 7
#define all_leds_off PORTF &= ~(1<<LED_B) & ~(1<<LED_R) & ~(1<<LED_G)
#define red_led_on PORTF |= (1<<LED_R)
#define red_led_off PORTF &= ~(1<<LED_R)
#define grn_led_on PORTF |= (1<<LED_G)
#define grn_led_off PORTF &= ~(1<<LED_G)
#define blu_led_on PORTF |= (1<<LED_B)
#define blu_led_off PORTF &= ~(1<<LED_B)
#define set_led_off PORTF &= ~(1<<LED_B) & ~(1<<LED_R) & ~(1<<LED_G)
#define set_led_red PORTF = PORTF & ~(1<<LED_B) & ~(1<<LED_G) | (1<<LED_R)
#define set_led_blue PORTF = PORTF & ~(1<<LED_G) & ~(1<<LED_R) | (1<<LED_B)
#define set_led_green PORTF = PORTF & ~(1<<LED_B) & ~(1<<LED_R) | (1<<LED_G)
#define set_led_yellow PORTF = PORTF & ~(1<<LED_B) | (1<<LED_R) | (1<<LED_G)
#define set_led_magenta PORTF = PORTF & ~(1<<LED_G) | (1<<LED_R) | (1<<LED_B)
#define set_led_cyan PORTF = PORTF & ~(1<<LED_R) | (1<<LED_B) | (1<<LED_G)
#define set_led_white PORTF |= (1<<LED_B) | (1<<LED_R) | (1<<LED_G)
*/
// 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
#define LAYOUT( \
k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, \
k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, \
k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B, \
k33, k34, k35, k36, k37, k38, \
k43, k44, k45, k46, k47, k48 \
) \
{ \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B }, \
{ k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B }, \
{ k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B }, \
{ KC_NO, KC_NO, KC_NO, k33, k34, k35, k36, k37, k38, KC_NO, KC_NO, KC_NO }, \
{ KC_NO, KC_NO, KC_NO, k43, k44, k45, k46, k47, k48, KC_NO, KC_NO, KC_NO } \
}
#endif

View File

@ -1,394 +0,0 @@
// this is the style you want to emulate.
// This is the canonical layout file for the Quantum project. If you want to add another keyboard,
#include QMK_KEYBOARD_H
#include "pointing_device.h"
// Each layer gets a name for readability, which is then used in the keymap matrix below.
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
// Layer names don't all need to be of the same length, obviously, and you can also skip them
// entirely and just use numbers.
enum dichotemy_layers
{
_BS,
_SF,
_NM,
_NS,
_MS
};
#define LONGPRESS_COUNT 4
enum dichotemy_keycodes
{
CK_1G = SAFE_RANGE,
CK_BSPE,
CK_QE,
CK_TE, //these 4 CK_XXXX keys are special "alternate long-press" keys controlled with unique timers. Make sure you understand them before you mess with them.
NS_HYPH,
NS_EQU,
NUMKEY,
SFTKEY,
MOUSE,
MS_BTN1,
MS_BTN2
//MS_BTN3
};
// Macro definitions for readability
enum dichotemy_macros
{
VOLU,
VOLD,
ESCM
};
#define LONGPRESS_DELAY 150
#define MAX_TOGGLE_LENGTH 300
#define TAPPING_TOGGLE 1
// Fillers to make layering more clear
#define _______ KC_TRNS
#define XXXXXXX KC_NO
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BS] = LAYOUT( /* Base layout, nearly qwerty but with modifications because it's not a full keyboard. Obviously. */
CK_TE, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
NUMKEY, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, CK_QE,
SFTKEY, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, MOUSE,
KC_LCTL, KC_LALT, KC_LGUI, KC_RGUI, KC_RALT, KC_RCTL,
KC_LBRC, KC_LPRN, KC_QUOT, KC_SPC, KC_RPRN, KC_RBRC
),
[_SF] = LAYOUT( /* Shifted layout, small changes (because angle brackets have been moved to thumb cluster buttons) */
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, NS_HYPH, KC_UNDS, _______, _______,
_______, _______, _______, _______, _______, _______,
_______, KC_LABK, _______, _______, KC_RABK, _______
),
[_NM] = LAYOUT( /* Number layout, basically the main function layer */
_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, _______,
_______, CK_1G, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, CK_BSPE,
_______, KC_F11, KC_F12, KC_F13, KC_F14, KC_F15, KC_F16, KC_F17, KC_F18, KC_F19, KC_F20, _______,
_______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______
),
[_NS] = LAYOUT( /* Shifted number/function layout, for per-key control. Only active when shift is held, and number is toggled or held */
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PLUS, NS_EQU, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______
),
[_MS] = LAYOUT( /* Mouse layer, including buttons for clicking. */
_______, _______, _______, _______, _______, _______, KC_VOLU, KC_HOME, KC_PGUP, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, MS_BTN1, MS_BTN2, _______, _______, _______,
_______, _______, _______, _______, _______, _______, KC_VOLD, KC_END, KC_PGDN, _______, _______, _______,
_______, _______, _______, _______, KC_UP, _______,
_______, _______, _______, KC_LEFT, KC_DOWN, KC_RGHT
)
};
const uint16_t PROGMEM fn_actions[] = {
};
static uint16_t special_timers[LONGPRESS_COUNT] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF};
static bool special_key_states[LONGPRESS_COUNT] = {0,0,0,0};
static uint16_t shift_timer;
static uint16_t num_timer;
static uint16_t mouse_timer;
static bool shift_singular_key = false;
static bool number_singular_key = false;
static bool mouse_singular_key = false;
static bool shift_held = false;
static bool shift_suspended = false;
report_mouse_t currentReport = {};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
//uint8_t layer;
//layer = biton32(layer_state); // get the current layer //Or don't, I didn't use it.
//custom layer handling for tri_layer,
switch (keycode) {
case NUMKEY:
if (record->event.pressed) {
num_timer = timer_read();
number_singular_key = true;
layer_invert(_NM);
} else {
if (timer_elapsed(num_timer) < MAX_TOGGLE_LENGTH && number_singular_key) {
//do nothing, the layer has already been inverted
} else {
layer_invert(_NM);
}
}
update_tri_layer(_NM, _SF, _NS);
return false;
break;
//SHIFT is handled as LSHIFT in the general case - 'toggle' shoudl activate caps, while the layer is only active when shift is held.
case SFTKEY:
if (record->event.pressed) {
shift_held = true;
shift_suspended = false;
shift_timer = timer_read();
shift_singular_key = true;
layer_on(_SF);
register_code(KC_LSFT);
} else {
shift_held = false;
if (timer_elapsed(shift_timer) < MAX_TOGGLE_LENGTH && shift_singular_key) {
//this was basically a toggle, so activate/deactivate caps lock.
SEND_STRING(SS_TAP(X_CAPSLOCK));
}
layer_off(_SF);
unregister_code(KC_LSFT);
}
update_tri_layer(_NM, _SF, _NS);
return false;
break;
//MOUSE layer needs to be handled the same way as NUMKEY, but differently from shift
case MOUSE:
if (record->event.pressed) {
mouse_timer = timer_read();
mouse_singular_key = true;
layer_invert(_MS);
} else {
if (timer_elapsed(mouse_timer) < MAX_TOGGLE_LENGTH && number_singular_key){
//do nothing, it was a toggle (and it's already been toggled)
} else {
layer_invert(_MS);
}
}
return false;
break;
//Custom macros for strange keys with different long-tap behavior
case CK_1G:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
shift_singular_key = false;
number_singular_key = false;
mouse_singular_key = false;
if (record->event.pressed) {
special_timers[CK_1G-SAFE_RANGE] = timer_read();
} else {
if (special_key_states[CK_1G-SAFE_RANGE]){
//key was activated after longpress_delay, need to close those keycodes
special_key_states[CK_1G-SAFE_RANGE] = 0;
unregister_code(KC_GRAVE);
} else {
//key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_1));
}
special_timers[CK_1G-SAFE_RANGE] = 0xFFFF;
}
break;
case CK_BSPE:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
shift_singular_key = false;
number_singular_key = false;
mouse_singular_key = false;
if (record->event.pressed) {
special_timers[CK_BSPE-SAFE_RANGE] = timer_read();
} else {
if (special_key_states[CK_BSPE-SAFE_RANGE]){
//key was activated after longpress_delay, need to close those keycodes
special_key_states[CK_BSPE-SAFE_RANGE] = 0;
unregister_code(KC_ENTER);
} else {
//key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_BSLASH));
}
special_timers[CK_BSPE-SAFE_RANGE] = 0xFFFF;
}
break;
case CK_QE:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
shift_singular_key = false;
number_singular_key = false;
mouse_singular_key = false;
if (record->event.pressed) {
special_timers[CK_QE-SAFE_RANGE] = timer_read();
} else {
if (special_key_states[CK_QE-SAFE_RANGE]){
//key was activated after longpress_delay, need to close those keycodes
special_key_states[CK_QE-SAFE_RANGE] = 0;
unregister_code(KC_ENTER);
} else {
//key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_QUOTE));
}
special_timers[CK_QE-SAFE_RANGE] = 0xFFFF;
}
break;
case CK_TE:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
if (record->event.pressed) {
special_timers[CK_TE-SAFE_RANGE] = timer_read();
} else {
if (special_key_states[CK_TE-SAFE_RANGE]){
//key was activated after longpress_delay, need to close those keycodes
special_key_states[CK_TE-SAFE_RANGE] = 0;
unregister_code(KC_ENTER);
} else {
//key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_TAB));
}
special_timers[CK_TE-SAFE_RANGE] = 0xFFFF;
}
break;
//No-shift keys, they unregister the KC_LSFT code so they can send
//unshifted values - but they don't change the bool. if any other
//key is pressed and the bool is set, KC_LSFT is registered again.
case NS_HYPH:
if (record->event.pressed) {
shift_suspended = true;
unregister_code(KC_LSFT);
register_code(KC_MINS);
} else {
unregister_code(KC_MINS);
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
}
break;
case NS_EQU:
if (record->event.pressed) {
shift_suspended = true;
unregister_code(KC_LSFT);
register_code(KC_EQUAL);
} else {
unregister_code(KC_EQUAL);
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
}
break;
//mouse buttons, for 1-3, to update the mouse report:
case MS_BTN1:
currentReport = pointing_device_get_report();
if (record->event.pressed) {
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
//update mouse report here
currentReport.buttons |= MOUSE_BTN1; //MOUSE_BTN1 is a const defined in report.h
} else {
//update mouse report here
currentReport.buttons &= ~MOUSE_BTN1;
}
pointing_device_set_report(currentReport);
break;
case MS_BTN2:
currentReport = pointing_device_get_report();
if (record->event.pressed) {
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
//update mouse report here
currentReport.buttons |= MOUSE_BTN2; //MOUSE_BTN2 is a const defined in report.h
} else {
//update mouse report here
}
pointing_device_set_report(currentReport);
break;
//there is a case for button 3, but that's handled in dichotemy.c, and this is being
//disabled to avoid any conflict.
/*case MS_BTN3:
currentReport = pointing_device_get_report();
if (record->event.pressed) {
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
//update mouse report here
currentReport.buttons |= MOUSE_BTN3; //MOUSE_BTN2 is a const defined in report.h
} else {
//update mouse report here
}
pointing_device_set_report(currentReport);
break;*/
//If any other key was pressed during the layer mod hold period,
//then the layer mod was used momentarily, and should block latching
//Additionally, if NS_ keys are in use, then shift may be held (but is
//disabled for the unshifted keycodes to be send. Check the bool and
//register shift as necessary.
default:
if (shift_held){
register_code(KC_LSFT);
}
shift_singular_key = false;
number_singular_key = false;
mouse_singular_key = false;
break;
}
return true;
};
void matrix_scan_user(void) {
uint8_t layer = biton32(layer_state);
for (uint8_t i = 0; i<LONGPRESS_COUNT; i++){
if (timer_elapsed(special_timers[i]) >= LONGPRESS_DELAY && !special_key_states[i]){
switch (i + SAFE_RANGE){
case CK_1G:
register_code(KC_GRAVE);
break;
case CK_BSPE:
register_code(KC_ENTER);
break;
case CK_QE:
register_code(KC_ENTER);
break;
case CK_TE:
register_code(KC_ESCAPE);
break;
}
special_key_states[i] = 1;
}
}
switch (layer) {
case _BS:
set_led_off;
break;
case _NM:
set_led_blue;
break;
case _SF:
set_led_red;
break;
case _NS:
set_led_green;
break;
default:
break;
}
};

View File

@ -24,10 +24,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0xACC7
#define DEVICE_VER 0x0001
#define MANUFACTURER unknown
#define PRODUCT Dichotemy
#define DESCRIPTION q.m.k. keyboard firmware for Dichotemy
#define DEVICE_VER 0x0002
#define MANUFACTURER Broekhuijsen
#define PRODUCT Dichotomy
#define DESCRIPTION q.m.k. keyboard firmware for Dichotomy
/* key matrix size */
#define MATRIX_ROWS 5

View File

@ -1,13 +1,11 @@
#include "dichotemy.h"
#include "pointing_device.h"
#include "report.h"
#include "dichotomy.h"
void uart_init(void) {
SERIAL_UART_INIT();
}
void pointing_device_task(void){
report_mouse_t currentReport = {};
/*report_mouse_t currentReport = {};
SERIAL_UART_INIT();
uint32_t timeout = 0;
@ -25,28 +23,31 @@ void pointing_device_task(void){
while(!SERIAL_UART_RXD_PRESENT){
timeout++;
if (timeout > 10000){
xprintf("\r\nTIMED OUT");
break;
}
}
xprintf("\r\nGOT DATA for %d",i);
uart_data[i] = SERIAL_UART_DATA;
}
//check for the end packet, bits 1-4 are movement and scroll
//but bit 5 has bits 0-3 for the scroll button state
//check for the end packet, bytes 1-4 are movement and scroll
//but byte 5 has bits 0-3 for the scroll button state
//(1000 if pressed, 0000 if not) and bits 4-7 are always 1
//We can use this to verify the report sent properly.
if (uart_data[4] == 0x0F || uart_data[4] == 0x8F)
{
xprintf("\r\nREQUESTED MOUSE, RECEIVED %i, %i, %i, %i, %i",uart_data[0],uart_data[1],uart_data[2],uart_data[3],uart_data[4]);
currentReport = pointing_device_get_report();
//shifting and transferring the info to the mouse report varaible
//mouseReport.x = 127 max -127 min
currentReport.x = uart_data[0];
currentReport.x = (int8_t) uart_data[0];
//mouseReport.y = 127 max -127 min
currentReport.y = uart_data[1];
currentReport.y = (int8_t) uart_data[1];
//mouseReport.v = 127 max -127 min (scroll vertical)
currentReport.v = uart_data[2];
currentReport.v = (int8_t) uart_data[2];
//mouseReport.h = 127 max -127 min (scroll horizontal)
currentReport.h = uart_data[3];
currentReport.h = (int8_t) uart_data[3];
//mouseReport.buttons = 0x31 max (bitmask for mouse buttons 1-5) 0x00 min
//mouse buttons 1 and 2 are handled by the keymap, but not 3
if (uart_data[4] == 0x0F) { //then 3 is not pressed
@ -55,7 +56,9 @@ void pointing_device_task(void){
currentReport.buttons |= MOUSE_BTN3;
}
pointing_device_set_report(currentReport);
}
} else {
xprintf("\r\nRequested packet, data 4 was %d",uart_data[4]);
}*/
pointing_device_send();
}

46
keyboards/dichotomy/dichotomy.h Executable file
View File

@ -0,0 +1,46 @@
#ifndef DICHOTOMY_H
#define DICHOTOMY_H
#include QMK_KEYBOARD_H
#include "report.h"
#include "pointing_device.h"
#include "quantum.h"
#include "matrix.h"
#include "backlight.h"
#include <stddef.h>
#define red_led_off() PORTF |= (1<<6)
#define red_led_on() PORTF &= ~(1<<6)
#define blu_led_off() PORTF |= (1<<5)
#define blu_led_on() PORTF &= ~(1<<5)
#define grn_led_off() PORTD |= (1<<1)
#define grn_led_on() PORTD &= ~(1<<1)
#define set_led_off() red_led_off(); grn_led_off(); blu_led_off()
#define set_led_red() red_led_on(); grn_led_off(); blu_led_off()
#define set_led_blue() red_led_off(); grn_led_off(); blu_led_on()
#define set_led_green() red_led_off(); grn_led_on(); blu_led_off()
#define set_led_yellow() red_led_on(); grn_led_on(); blu_led_off()
#define set_led_magenta() red_led_on(); grn_led_off(); blu_led_on()
#define set_led_cyan() red_led_off(); grn_led_on(); blu_led_on()
#define set_led_white() red_led_on(); grn_led_on(); blu_led_on()
// 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
#define LAYOUT( \
k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, \
k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, \
k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B, \
k33, k34, k35, k36, k37, k38, \
k42, k43, k44, k45, k46, k47, k48, k49 \
) \
{ \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B }, \
{ k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B }, \
{ k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B }, \
{ KC_NO, KC_NO, KC_NO, k33, k34, k35, k36, k37, k38, KC_NO, KC_NO, KC_NO }, \
{ KC_NO, KC_NO, k42, k43, k44, k45, k46, k47, k48, k49, KC_NO, KC_NO } \
}
#endif

View File

@ -1,5 +1,5 @@
{
"keyboard_name": "Dichotemy",
"keyboard_name": "Dichotomy",
"url": "",
"maintainer": "qmk",
"width": 13,

View File

@ -0,0 +1,506 @@
// this is the style you want to emulate.
// This is the canonical layout file for the Quantum project. If you want to add another keyboard,
#include "dichotomy.h"
// Each layer gets a name for readability, which is then used in the keymap matrix below.
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
// Layer names don't all need to be of the same length, obviously, and you can also skip them
// entirely and just use numbers.
enum dichotomy_layers {
_BS,
_SF,
_NM,
_NS,
_MS
};
#define LONGPRESS_COUNT 4
enum dichotomy_keycodes
{
CK_1G = SAFE_RANGE,
CK_BSPE,
CK_QE,
CK_TE, //these 4 CK_XXXX keys are special "alternate long-press" keys controlled with unique timers. Make sure you understand them before you mess with them.
NS_HYPH,
NS_EQU,
NUMKEY,
SFTKEY,
MOUKEY,
MS_BTN1,
MS_BTN2,
MS_BTN3
};
#define CUSTOM_LONGPRESS 150
#define CUSTOM_TOGGLE_TIME 300
#define RED_BRIGHTNESS 3
#define GREEN_BRIGHTNESS 2
#define BLUE_BRIGHTNESS 2
// Fillers to make layering more clear
#define _______ KC_TRNS
#define XXXXXXX KC_NO
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BS] = LAYOUT( /* Base layout, nearly qwerty but with modifications because it's not a full keyboard. Obviously. */
CK_TE, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
NUMKEY, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, CK_QE,
SFTKEY, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, MOUKEY,
KC_LCTL, KC_LALT, KC_LGUI, KC_RGUI, KC_RALT, KC_RCTL,
MS_BTN3, KC_LBRC, KC_LPRN, KC_SPC, KC_SPC, KC_RPRN, KC_RBRC, MS_BTN3
),
[_SF] = LAYOUT( /* Shifted layout, small changes (because angle brackets have been moved to thumb cluster buttons) */
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, NS_HYPH, KC_UNDS, _______, _______,
_______, _______, _______, _______, _______, _______,
_______, _______, KC_LABK, _______, _______, KC_RABK, _______, _______
),
[_NM] = LAYOUT( /* Number layout, basically the main function layer */
_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, _______,
_______, CK_1G, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, CK_BSPE,
_______, KC_F11, KC_F12, KC_F13, KC_F14, KC_F15, KC_F16, KC_F17, KC_F18, KC_F19, KC_F20, _______,
_______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______
),
[_NS] = LAYOUT( /* Shifted number/function layout, for per-key control. Only active when shift is held, and number is toggled or held */
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PLUS, NS_EQU, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______
),
[_MS] = LAYOUT( /* Mouse layer, including buttons for clicking. */
_______, _______, _______, _______, _______, _______, KC_VOLU, KC_HOME, KC_PGUP, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, MS_BTN1, MS_BTN2, _______, _______, _______,
_______, _______, _______, _______, _______, _______, KC_VOLD, KC_END, KC_PGDN, _______, _______, _______,
_______, _______, _______, _______, KC_UP, _______,
_______, _______, _______, _______, KC_LEFT, KC_DOWN, KC_RGHT, _______
)
};
const uint16_t PROGMEM fn_actions[] = {
};
static uint16_t special_timers[LONGPRESS_COUNT] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF};
static bool special_key_states[LONGPRESS_COUNT] = {0,0,0,0};
static bool special_key_pressed[LONGPRESS_COUNT] = {0,0,0,0};
static uint16_t shift_timer;
static uint16_t num_timer;
static uint16_t mouse_timer;
static uint8_t red_timer;
static uint8_t green_timer;
static uint8_t blue_timer;
static bool shift_singular_key = false;
static bool number_singular_key = false;
static bool mouse_singular_key = false;
static bool capsLED = false;
static bool shiftLED = false;
static bool numLED = false;
static bool mouseLED = false;
static bool shift_held = false;
static bool shift_suspended = false;
report_mouse_t currentReport = {};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
//uint8_t layer;
//layer = biton32(layer_state); // get the current layer //Or don't, I didn't use it.
bool returnVal = true; //this is to determine if more key processing is needed.
//custom layer handling for tri_layer,
switch (keycode) {
case NUMKEY:
if (record->event.pressed) {
num_timer = timer_read();
number_singular_key = true;
layer_invert(_NM);
numLED = !numLED;
} else {
if (timer_elapsed(num_timer) < CUSTOM_TOGGLE_TIME && number_singular_key) {
//do nothing, the layer has already been inverted
} else {
layer_invert(_NM);
numLED = !numLED;
}
}
update_tri_layer(_NM, _SF, _NS);
returnVal = false;
break;
//SHIFT is handled as LSHIFT in the general case - 'toggle' shoudl activate caps, while the layer is only active when shift is held.
case SFTKEY:
if (record->event.pressed) {
shift_held = true;
shiftLED = true;
shift_suspended = false;
shift_timer = timer_read();
shift_singular_key = true;
layer_on(_SF);
register_code(KC_LSFT);
} else {
shift_held = false;
shiftLED = false;
if (timer_elapsed(shift_timer) < CUSTOM_TOGGLE_TIME && shift_singular_key) {
//this was basically a toggle, so activate/deactivate caps lock.
SEND_STRING(SS_TAP(X_CAPSLOCK));
capsLED = !capsLED;
}
layer_off(_SF);
unregister_code(KC_LSFT);
}
update_tri_layer(_NM, _SF, _NS);
returnVal = false;
break;
//MOUSE layer needs to be handled the same way as NUMKEY, but differently from shift
case MOUKEY:
if (record->event.pressed) {
mouse_timer = timer_read();
mouse_singular_key = true;
layer_invert(_MS);
mouseLED = !mouseLED;
} else {
if (timer_elapsed(mouse_timer) < CUSTOM_TOGGLE_TIME && mouse_singular_key){
//do nothing, it was a toggle (and it's already been toggled)
} else {
layer_invert(_MS);
mouseLED = !mouseLED;
}
}
returnVal = false;
break;
//Custom macros for strange keys with different long-tap behavior
case CK_1G:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
if (record->event.pressed) {
special_timers[CK_1G-SAFE_RANGE] = timer_read();
special_key_pressed[CK_1G-SAFE_RANGE] = 1;
} else {
if (special_key_states[CK_1G-SAFE_RANGE]){
//key was activated after custom_longpress, need to close those keycodes
special_key_states[CK_1G-SAFE_RANGE] = 0;
unregister_code(KC_GRAVE);
} else {
if (special_key_pressed[CK_1G-SAFE_RANGE]){
//key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_1));
special_key_pressed[CK_1G-SAFE_RANGE] = 0;
} else {
//the short key was already sent, because another key was pressed.
//Do nothing.
}
}
}
returnVal = false;
break;
case CK_BSPE:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
if (record->event.pressed) {
special_timers[CK_BSPE-SAFE_RANGE] = timer_read();
special_key_pressed[CK_BSPE-SAFE_RANGE] = 1;
} else {
if (special_key_states[CK_BSPE-SAFE_RANGE]){
//key was activated after custom_longpress, need to close those keycodes
special_key_states[CK_BSPE-SAFE_RANGE] = 0;
unregister_code(KC_ENTER);
} else {
if (special_key_pressed[CK_BSPE-SAFE_RANGE]){
//key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_BSLASH));
special_key_pressed[CK_BSPE-SAFE_RANGE] = 0;
} else {
//the short key was already sent, because another key was pressed.
//Do nothing.
}
}
}
returnVal = false;
break;
case CK_QE:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
if (record->event.pressed) {
special_timers[CK_QE-SAFE_RANGE] = timer_read();
special_key_pressed[CK_QE-SAFE_RANGE] = 1;
} else {
if (special_key_states[CK_QE-SAFE_RANGE]){
//key was activated after custom_longpress, need to close those keycodes
special_key_states[CK_QE-SAFE_RANGE] = 0;
unregister_code(KC_ENTER);
} else {
if (special_key_pressed[CK_QE-SAFE_RANGE]){
//the long-press key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_QUOTE));
special_key_pressed[CK_QE-SAFE_RANGE] = 0;
} else {
//the short key was already sent, because another key was pressed.
//Do nothing.
}
}
}
returnVal = false;
break;
case CK_TE:
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
if (record->event.pressed) {
special_timers[CK_TE-SAFE_RANGE] = timer_read();
special_key_pressed[CK_TE-SAFE_RANGE] = 1;
} else {
if (special_key_states[CK_TE-SAFE_RANGE]){
//key was activated after custom_longpress, need to close those keycodes
special_key_states[CK_TE-SAFE_RANGE] = 0;
unregister_code(KC_ESCAPE);
} else {
if (special_key_pressed[CK_TE-SAFE_RANGE]){
//the long-press key was not activated, return macro activating proper, pre-long-tap key
SEND_STRING(SS_TAP(X_TAB));
special_key_pressed[CK_TE-SAFE_RANGE] = 0;
} else {
//the short key was already sent, because another key was pressed.
//Do nothing.
}
}
}
returnVal = false;
break;
//No-shift keys, they unregister the KC_LSFT code so they can send
//unshifted values - but they don't change the bool. if any other
//key is pressed and the bool is set, KC_LSFT is registered again.
case NS_HYPH:
if (record->event.pressed) {
shift_suspended = true;
unregister_code(KC_LSFT);
register_code(KC_MINS);
} else {
unregister_code(KC_MINS);
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
}
returnVal = false;
break;
case NS_EQU:
if (record->event.pressed) {
shift_suspended = true;
unregister_code(KC_LSFT);
register_code(KC_EQUAL);
} else {
unregister_code(KC_EQUAL);
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
}
returnVal = false;
break;
//mouse buttons, for 1-3, to update the mouse report:
case MS_BTN1:
currentReport = pointing_device_get_report();
if (record->event.pressed) {
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
//update mouse report here
currentReport.buttons |= MOUSE_BTN1; //MOUSE_BTN1 is a const defined in report.h
} else {
//update mouse report here
currentReport.buttons &= ~MOUSE_BTN1;
}
pointing_device_set_report(currentReport);
returnVal = false;
break;
case MS_BTN2:
currentReport = pointing_device_get_report();
if (record->event.pressed) {
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
//update mouse report here
currentReport.buttons |= MOUSE_BTN2; //MOUSE_BTN2 is a const defined in report.h
} else {
//update mouse report here
currentReport.buttons &= ~MOUSE_BTN2;
}
pointing_device_set_report(currentReport);
returnVal = false;
break;
case MS_BTN3:
currentReport = pointing_device_get_report();
if (record->event.pressed) {
if (shift_held && shift_suspended){
register_code(KC_LSFT);
shift_suspended = false;
}
//update mouse report here
currentReport.buttons |= MOUSE_BTN3; //MOUSE_BTN3 is a const defined in report.h
} else {
//update mouse report here
currentReport.buttons &= ~MOUSE_BTN3;
}
pointing_device_set_report(currentReport);
returnVal = false;
break;
//Additionally, if NS_ keys are in use, then shift may be held (but is
//disabled for the unshifted keycodes to be send. Check the bool and
//register shift as necessary.
default:
if (shift_held){
register_code(KC_LSFT);
}
break;
}
switch (keycode){
case KC_BSPC:
case KC_NO:
case NUMKEY:
case SFTKEY:
case MOUKEY:
//don't want to reset single key variables
break;
default:
//If any other key was pressed during the layer mod hold period,
//then the layer mod was used momentarily, and should block latching
shift_singular_key = false;
number_singular_key = false;
mouse_singular_key = false;
break;
}
switch (keycode){
case KC_BSPC:
case KC_NO:
case NUMKEY:
case SFTKEY:
case MOUKEY:
case MOUSE_BTN1:
case MOUSE_BTN2:
case MOUSE_BTN3:
case KC_LCTL:
case KC_LALT:
case KC_LGUI:
case KC_RCTL:
case KC_RALT:
case KC_RGUI:
case CK_1G:
case CK_BSPE:
case CK_QE:
case CK_TE:
//Do nothing, don't want to trigger the timer key rollover
break;
default:
//Now we're checking to see if any of the special timer keys are pressed
//if so, we need to activate their short-press features
if (record->event.pressed) {
for (uint8_t i = 0; i<LONGPRESS_COUNT; i++){
if ((!special_key_states[i]) && special_key_pressed[i]){
switch (i + SAFE_RANGE){
case CK_1G:
SEND_STRING(SS_TAP(X_1));
break;
case CK_BSPE:
SEND_STRING(SS_TAP(X_BSLASH));
break;
case CK_QE:
SEND_STRING(SS_TAP(X_QUOTE));
break;
case CK_TE:
SEND_STRING(SS_TAP(X_TAB));
break;
}
special_key_pressed[i] = 0;
}
}
} else {
//do nothing, we don't want to trigger short presses on key releases.
}
break;
}
return returnVal;
};
void matrix_scan_user(void) {
//uint8_t layer = biton32(layer_state);
for (uint8_t i = 0; i<LONGPRESS_COUNT; i++){
if ((timer_elapsed(special_timers[i]) >= CUSTOM_LONGPRESS) && (!special_key_states[i]) && special_key_pressed[i]){
switch (i + SAFE_RANGE){
case CK_1G:
register_code(KC_GRAVE);
break;
case CK_BSPE:
register_code(KC_ENTER);
break;
case CK_QE:
register_code(KC_ENTER);
break;
case CK_TE:
register_code(KC_ESCAPE);
break;
}
special_key_pressed[i] = 0;
special_key_states[i] = 1;
}
}
if (shiftLED || capsLED){
red_timer++;
if (red_timer < RED_BRIGHTNESS){
red_led_on();
} else {
red_timer = 0;
red_led_off();
}
} else {
red_timer = 0;
red_led_off();
}
if (numLED){
green_timer++;
if (green_timer < GREEN_BRIGHTNESS){
grn_led_on();
} else {
green_timer = 0;
grn_led_off();
}
} else {
green_timer = 0;
grn_led_off();
}
if (mouseLED){
blue_timer++;
if (blue_timer < BLUE_BRIGHTNESS){
blu_led_on();
} else {
blue_timer = 0;
blu_led_off();
}
} else {
blue_timer = 0;
blu_led_off();
}
};

View File

@ -26,6 +26,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "util.h"
#include "matrix.h"
#include "timer.h"
#include "dichotomy.h"
#include "pointing_device.h"
#include "report.h"
#if (MATRIX_COLS <= 8)
# define print_matrix_header() print("\nr/c 01234567\n")
@ -45,11 +48,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#define MAIN_ROWMASK 0xFFF0;
#define LOWER_ROWMASK 0x1F80;
#define LOWER_ROWMASK 0x3FC0;
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
__attribute__ ((weak))
void matrix_init_quantum(void) {
matrix_init_kb();
}
__attribute__ ((weak))
void matrix_scan_quantum(void) {
matrix_scan_kb();
}
__attribute__ ((weak))
void matrix_init_kb(void) {
matrix_init_user();
@ -79,13 +92,16 @@ uint8_t matrix_cols(void) {
}
void matrix_init(void) {
DDRF |= (1<<6);
DDRF |= (1<<5);
DDRD |= (1<<1);
matrix_init_quantum();
}
uint8_t matrix_scan(void)
{
SERIAL_UART_INIT();
//xprintf("\r\nTRYING TO SCAN");
uint32_t timeout = 0;
@ -93,16 +109,17 @@ uint8_t matrix_scan(void)
SERIAL_UART_DATA = 's';
//trust the external keystates entirely, erase the last data
uint8_t uart_data[7] = {0};
uint8_t uart_data[11] = {0};
//there are 10 bytes corresponding to 10 columns, and an end byte
for (uint8_t i = 0; i < 7; i++) {
for (uint8_t i = 0; i < 11; i++) {
//wait for the serial data, timeout if it's been too long
//this only happened in testing with a loose wire, but does no
//harm to leave it in here
while(!SERIAL_UART_RXD_PRESENT){
timeout++;
if (timeout > 10000){
xprintf("\r\nTime out in keyboard.");
break;
}
}
@ -111,7 +128,16 @@ uint8_t matrix_scan(void)
//check for the end packet, the key state bytes use the LSBs, so 0xE0
//will only show up here if the correct bytes were recieved
if (uart_data[6] == 0x96) { //this is an arbitrary binary checksum (10010110)
uint8_t checksum = 0x00;
for (uint8_t z=0; z<10; z++){
checksum = checksum^uart_data[z];
}
checksum = checksum ^ (uart_data[10] & 0xF0);
// Smash the checksum from 1 byte into 4 bits
checksum = (checksum ^ ((checksum & 0xF0)>>4)) & 0x0F;
//xprintf("\r\nGOT RAW PACKET: \r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d",uart_data[0],uart_data[1],uart_data[2],uart_data[3],uart_data[4],uart_data[5],uart_data[6],uart_data[7],uart_data[8],uart_data[9],uart_data[10],checksum);
if ((uart_data[10] & 0x0F) == checksum) { //this is an arbitrary binary checksum (1001) (that would be 0x9.)
//xprintf("\r\nGOT PACKET: \r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d",uart_data[0],uart_data[1],uart_data[2],uart_data[3],uart_data[4],uart_data[5]);
//shifting and transferring the keystates to the QMK matrix variable
//bits 1-12 are row 1, 13-24 are row 2, 25-36 are row 3,
//bits 37-42 are row 4 (only 6 wide, 1-3 are 0, and 10-12 are 0)
@ -121,15 +147,49 @@ uint8_t matrix_scan(void)
matrix[1] = ((uint16_t) uart_data[1] << 12) | ((uint16_t) uart_data[2] << 4);
matrix[2] = (((uint16_t) uart_data[3] << 8) | ((uint16_t) uart_data[4])) & MAIN_ROWMASK;
matrix[3] = (((uint16_t) uart_data[4] << 9) | ((uint16_t) uart_data[5] << 1)) & LOWER_ROWMASK;
matrix[4] = ((uint16_t) uart_data[5] << 7) & LOWER_ROWMASK;
matrix[4] = (((uint16_t) uart_data[5] << 7) | ((uart_data[10] & 1<<7) ? 1:0) << 13 | ((uart_data[10] & 1<<6) ? 1:0) << 6) & LOWER_ROWMASK;
/* OK, TURNS OUT THAT WAS A BAD ASSUMPTION */
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
//I've unpacked these into the mirror image of what QMK expects them to be, so...
matrix[i] = ((matrix[i] * 0x0802LU & 0x22110LU) | (matrix[i] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
/*uint8_t halfOne = (matrix[i]>>8);
uint8_t halfTwo = (matrix[i] & 0xFF);
halfOne = ((halfOne * 0x0802LU & 0x22110LU) | (halfOne * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
halfTwo = ((halfTwo * 0x0802LU & 0x22110LU) | (halfTwo * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
matrix[i] = ((halfTwo<<8) & halfOne);*/
//matrix[i] = ((matrix[i] * 0x0802LU & 0x22110LU) | (matrix[i] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
matrix[i] = bitrev16(matrix[i]);
//bithack mirror! Doesn't make any sense, but works - and efficiently.
}
}
//if (uart_data[6]!=0 || uart_data[7]!=0){
//if (maxCount<101){
// xprintf("\r\nMouse data: x=%d, y=%d",(int8_t)uart_data[6],(int8_t)uart_data[7]);
//}
report_mouse_t currentReport = {};
//check for the end packet, bytes 1-4 are movement and scroll
//but byte 5 has bits 0-3 for the scroll button state
//(1000 if pressed, 0000 if not) and bits 4-7 are always 1
//We can use this to verify the report sent properly.
currentReport = pointing_device_get_report();
//shifting and transferring the info to the mouse report varaible
//mouseReport.x = 127 max -127 min
currentReport.x = (int8_t) uart_data[6];
//mouseReport.y = 127 max -127 min
currentReport.y = (int8_t) uart_data[7];
//mouseReport.v = 127 max -127 min (scroll vertical)
currentReport.v = (int8_t) uart_data[8];
//mouseReport.h = 127 max -127 min (scroll horizontal)
currentReport.h = (int8_t) uart_data[9];
/*
currentReport.x = 0;
currentReport.y = 0;
currentReport.v = 0;
currentReport.h = 0;*/
pointing_device_set_report(currentReport);
} else {
//xprintf("\r\nRequested packet, data 10 was %d but checksum was %d",(uart_data[10] & 0x0F), (checksum & 0x0F));
}
//matrix_print();
matrix_scan_quantum();
return 1;

View File

@ -1,4 +1,4 @@
Dichotemy Keyboard Firmware
Dichotomy Keyboard Firmware
======================
These configuration files were based off the Mitosis keyboard. This keyboard uses a completely different 'matrix scan' system to other keyboards, it relies on an external nRF51822 microcontroller maintaining a matrix of keystates received from the keyboard halves - it also receives mouse pointer information from the keyboard halves, which is implemented through a new feature, "Pointing Device". The matrix.c file contains the code to poll the external microcontroller for the key matrix, and the keymap.c file contains similar code to obtain the mouse report. As long as the relavant functions in these files are not changed, all other QMK features are supported.

View File

@ -1,6 +1,6 @@
OPT_DEFS += -DDICHOTEMY_PROMICRO
DICHOTEMY_UPLOAD_COMMAND = while [ ! -r $(USB) ]; do sleep 1; done; \
OPT_DEFS += -DDICHOTOMY_PROMICRO
DICHOTOMY_UPLOAD_COMMAND = while [ ! -r $(USB) ]; do sleep 1; done; \
avrdude -p $(MCU) -c avr109 -U flash:w:$(TARGET).hex -P $(USB)
# # project specific files
@ -24,6 +24,8 @@ MCU = atmega32u4
# software delays.
F_CPU = 16000000
#
# LUFA specific
#
# Target architecture (see library "Board Types" documentation).
@ -43,10 +45,10 @@ ARCH = AVR8
F_USB = $(F_CPU)
# Bootloader
# This definition is optional, and if your keyboard supports multiple bootloaders of
# different sizes, comment this out, and the correct address will be loaded
# automatically (+60). See bootloader.mk for all options.
BOOTLOADER = caterina
# This definition is optional, and if your keyboard supports multiple bootloaders of
# different sizes, comment this out, and the correct address will be loaded
# automatically (+60). See bootloader.mk for all options.
BOOTLOADER = caterina
# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
@ -72,4 +74,4 @@ UNICODE_ENABLE = YES # Unicode
USB = /dev/ttyACM0
#upload: build
# $(DICHOTEMY_UPLOAD_COMMAND)
# $(DICHOTOMY_UPLOAD_COMMAND)