2021-02-27 21:27:34 +00:00
|
|
|
|
#include <Wire.h>
|
|
|
|
|
|
|
|
|
|
#define TRACKBALL_ADDR 0x0A
|
|
|
|
|
#define TRACKBALL_REG_LEFT 0x04
|
|
|
|
|
|
|
|
|
|
const byte PIN_A = 33;
|
|
|
|
|
const byte PIN_B = 32;
|
|
|
|
|
const byte PIN_C = 31;
|
|
|
|
|
const byte PIN_D = 24;
|
|
|
|
|
const byte PIN_E = 25;
|
|
|
|
|
const byte PIN_F = 26;
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
const byte PIN_MOUSE_UPPER_LEFT = 27;
|
|
|
|
|
const byte PIN_MOUSE_UPPER_RIGHT = 30;
|
|
|
|
|
const byte PIN_MOUSE_LOWER_LEFT = 28;
|
|
|
|
|
const byte PIN_MOUSE_LOWER_RIGHT = 29;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
|
|
|
|
const byte PIN_LED1 = 6;
|
|
|
|
|
const byte PIN_LED2 = 1;
|
|
|
|
|
const byte PIN_LED3 = 3;
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// unused here, but the trackball is wired to i2c bus 0 with these pins
|
|
|
|
|
// const byte PIN_TRACKBALL_SDA = 18;
|
|
|
|
|
// const byte PIN_TRACKBALL_SCL = 19;
|
|
|
|
|
|
|
|
|
|
// custom masks for forcing modifiers for keypresses
|
|
|
|
|
// teensy's inbuilt ones (eg. SHIFT_MASK) conflict with arrow keys etc.
|
|
|
|
|
#define MASK_SHIFT 0x100
|
|
|
|
|
#define MASK_ALTGR 0x200
|
|
|
|
|
#define MASK_CTRL 0x800
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
2021-02-28 17:51:43 +00:00
|
|
|
|
enum Button { A, B, C, D, E, F, MouseUL, MouseUR, MouseDL, MouseDR };
|
2021-02-27 21:27:34 +00:00
|
|
|
|
const int button_pins[10] = {
|
|
|
|
|
PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F,
|
2021-03-03 17:39:28 +00:00
|
|
|
|
PIN_MOUSE_UPPER_LEFT, PIN_MOUSE_UPPER_RIGHT,
|
|
|
|
|
PIN_MOUSE_LOWER_LEFT, PIN_MOUSE_LOWER_RIGHT
|
2021-02-27 21:27:34 +00:00
|
|
|
|
};
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// how many update cycles a button has to stay pressed before
|
|
|
|
|
// it counts as being pressed
|
2021-03-02 18:37:31 +00:00
|
|
|
|
const int debounce_time = 50;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// different actions the keyboard can take
|
2021-02-28 17:51:43 +00:00
|
|
|
|
// - press (and release) a key
|
|
|
|
|
// - toggle a modifier
|
2021-03-02 18:37:31 +00:00
|
|
|
|
enum ActionType { PressKey, ToggleModifier };
|
2021-02-28 17:51:43 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
KEYBOARD KEYS (ON THEIR OWN)
|
|
|
|
|
*************************************************/
|
|
|
|
|
const int keys[6] = { KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F };
|
|
|
|
|
const int keys_symbol[6] = {
|
2021-03-02 18:37:31 +00:00
|
|
|
|
KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6
|
|
|
|
|
};
|
2021-03-03 17:39:28 +00:00
|
|
|
|
const int keys_function[6] = {
|
2021-03-03 16:57:54 +00:00
|
|
|
|
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6
|
|
|
|
|
};
|
2021-02-28 19:17:48 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
CHORDS AND KEYS THAT CAN BE CHORDED INTO
|
|
|
|
|
*************************************************/
|
2021-02-27 21:27:34 +00:00
|
|
|
|
/*
|
2021-03-03 17:39:28 +00:00
|
|
|
|
defined as a 6-bit number with the physical buttons corresponding to
|
|
|
|
|
each of the bits (A = 1, B = 2, C = 4, D = 8, E = 16, F = 32)
|
|
|
|
|
|
|
|
|
|
backspace, space (keep those two first since they overlap with the rest)
|
2021-02-27 21:27:34 +00:00
|
|
|
|
g, k, o, s, w, native
|
|
|
|
|
*/
|
2021-02-28 17:51:43 +00:00
|
|
|
|
const byte chords[8] = { 7, 56, 24, 48, 3, 6, 40, 5 };
|
|
|
|
|
// buttons that can be combined with a chord for a keypress
|
|
|
|
|
const byte chord_buttons[24] = {
|
|
|
|
|
Button::D, Button::E, Button::F,
|
|
|
|
|
Button::A, Button::B, Button::C,
|
|
|
|
|
Button::A, Button::B, Button::C,
|
|
|
|
|
Button::A, Button::B, Button::C,
|
|
|
|
|
Button::D, Button::E, Button::F,
|
|
|
|
|
Button::D, Button::E, Button::F,
|
|
|
|
|
Button::A, Button::B, Button::C,
|
|
|
|
|
Button::D, Button::E, Button::F,
|
|
|
|
|
};
|
|
|
|
|
// keypresses for chords in sets of 4
|
|
|
|
|
// index 0 is the chord on its own, 1-3 correspond to chord_buttons
|
|
|
|
|
const int chord_targets[32] = {
|
2021-03-03 16:08:51 +00:00
|
|
|
|
KEY_BACKSPACE, KEY_LEFT + MASK_CTRL, KEY_LEFT, KEY_HOME,
|
|
|
|
|
KEY_SPACE, KEY_RIGHT + MASK_CTRL, KEY_RIGHT, KEY_END,
|
2021-03-02 18:37:31 +00:00
|
|
|
|
KEY_G, KEY_H, KEY_I, KEY_J,
|
|
|
|
|
KEY_K, KEY_L, KEY_M, KEY_N,
|
|
|
|
|
KEY_O, KEY_P, KEY_Q, KEY_R,
|
|
|
|
|
KEY_S, KEY_T, KEY_U, KEY_V,
|
|
|
|
|
KEY_W, KEY_X, KEY_Y, KEY_Z,
|
2021-02-28 19:17:48 +00:00
|
|
|
|
0, 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
const int chord_targets_symbol[32] = {
|
2021-03-03 16:08:51 +00:00
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0,
|
2021-03-02 18:37:31 +00:00
|
|
|
|
KEY_0, KEY_7, KEY_8, KEY_9,
|
2021-03-03 17:39:28 +00:00
|
|
|
|
KEY_BACKSLASH, KEY_QUOTE + MASK_SHIFT, // # @
|
|
|
|
|
KEY_5 + MASK_ALTGR, KEY_7 + MASK_SHIFT, // ½ &
|
|
|
|
|
KEY_EQUAL + MASK_SHIFT, KEY_5 + MASK_SHIFT, // + %
|
|
|
|
|
KEY_EQUAL, KEY_6 + MASK_SHIFT, // = ^
|
|
|
|
|
KEY_8 + MASK_SHIFT, KEY_4 + MASK_SHIFT, // * $
|
|
|
|
|
KEY_4 + MASK_ALTGR, KEY_3 + MASK_SHIFT, // € £
|
|
|
|
|
KEY_9 + MASK_SHIFT, KEY_LEFT_BRACE, // ( [
|
|
|
|
|
KEY_COMMA + MASK_SHIFT, KEY_LEFT_BRACE + MASK_SHIFT, // < {
|
|
|
|
|
KEY_0 + MASK_SHIFT, KEY_RIGHT_BRACE, // ) ]
|
|
|
|
|
KEY_PERIOD + MASK_SHIFT, KEY_RIGHT_BRACE + MASK_SHIFT, // > }
|
2021-02-28 17:51:43 +00:00
|
|
|
|
};
|
2021-03-03 16:57:54 +00:00
|
|
|
|
const int chord_targets_function[32] = {
|
|
|
|
|
KEY_MEDIA_PLAY_PAUSE, 0, KEY_MEDIA_PREV_TRACK, 0,
|
|
|
|
|
KEY_MEDIA_MUTE, 0, KEY_MEDIA_NEXT_TRACK, 0,
|
|
|
|
|
KEY_F7, KEY_F8, KEY_F9, KEY_F10,
|
|
|
|
|
KEY_F11, KEY_F12, 0, 0,
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0
|
|
|
|
|
};
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
SPECIAL KEY COMBINATIONS
|
|
|
|
|
*************************************************/
|
2021-02-27 21:27:34 +00:00
|
|
|
|
/*
|
|
|
|
|
dash, backslash, slash, apostrophe, comma, exclamation point, question mark,
|
|
|
|
|
period, up, down, page up, page down, shift, symbol shift, switch keyset,
|
2021-03-03 16:57:54 +00:00
|
|
|
|
escape, control, alt, delete, function, gui, tab, enter
|
2021-02-27 21:27:34 +00:00
|
|
|
|
*/
|
2021-03-03 16:57:54 +00:00
|
|
|
|
const byte specials[23] = {
|
2021-02-27 21:27:34 +00:00
|
|
|
|
17, 51, 30, 10, 20, 12, 33, 34, 9, 36, 27,
|
2021-03-03 16:57:54 +00:00
|
|
|
|
54, 18, 45, 63, 31, 47, 55, 62, 29, 43, 61, 59
|
2021-02-27 21:27:34 +00:00
|
|
|
|
};
|
2021-03-03 16:57:54 +00:00
|
|
|
|
enum Modifier { Shift, SymbolShift, Keyset, Control, Alt, Gui, Function };
|
|
|
|
|
const int special_action_targets[23] = {
|
2021-03-03 17:39:28 +00:00
|
|
|
|
KEY_MINUS, KEY_MINUS + MASK_ALTGR, // - \.
|
|
|
|
|
KEY_SLASH, KEY_QUOTE, // / '
|
|
|
|
|
KEY_COMMA, KEY_1 + MASK_SHIFT, // , !
|
|
|
|
|
KEY_SLASH + MASK_SHIFT, KEY_PERIOD, // ! ?
|
2021-03-02 18:37:31 +00:00
|
|
|
|
KEY_UP, KEY_DOWN, KEY_PAGE_UP, KEY_PAGE_DOWN,
|
|
|
|
|
Modifier::Shift, Modifier::SymbolShift, Modifier::Keyset,
|
2021-03-03 16:57:54 +00:00
|
|
|
|
KEY_ESC, Modifier::Control, Modifier::Alt, KEY_DELETE,
|
|
|
|
|
Modifier::Function, Modifier::Gui, KEY_TAB, KEY_ENTER
|
2021-02-28 15:34:38 +00:00
|
|
|
|
};
|
2021-03-03 16:57:54 +00:00
|
|
|
|
const int special_action_targets_symbol[23] = {
|
2021-03-03 17:39:28 +00:00
|
|
|
|
KEY_MINUS + MASK_SHIFT, KEY_TILDE, // _ `
|
|
|
|
|
KEY_SEMICOLON + MASK_ALTGR, KEY_2 + MASK_SHIFT, // ´ "
|
|
|
|
|
KEY_SEMICOLON, KEY_TILDE + MASK_ALTGR, // ; |
|
|
|
|
|
KEY_BACKSLASH + MASK_SHIFT, KEY_SEMICOLON + MASK_SHIFT, // ~ :
|
2021-02-28 19:17:48 +00:00
|
|
|
|
0, 0, 0, 0,
|
2021-03-02 18:37:31 +00:00
|
|
|
|
0, 0, 0,
|
2021-03-03 16:57:54 +00:00
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
const int special_action_targets_function[23] = {
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0,
|
|
|
|
|
KEY_MEDIA_VOLUME_INC, KEY_MEDIA_VOLUME_DEC, 0, 0,
|
|
|
|
|
0, 0, 0,
|
|
|
|
|
0, 0, 0, KEY_PRINTSCREEN,
|
|
|
|
|
0, 0, 0, 0
|
2021-02-28 19:17:48 +00:00
|
|
|
|
};
|
2021-03-03 16:57:54 +00:00
|
|
|
|
const byte special_action_target_types[23] = {
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0
|
2021-02-28 17:51:43 +00:00
|
|
|
|
};
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// bitwise variables, see line 63
|
2021-02-27 21:27:34 +00:00
|
|
|
|
byte key_pressed = 0;
|
|
|
|
|
byte key_pressed_total = 0;
|
2021-02-28 17:51:43 +00:00
|
|
|
|
bool chord_used = false;
|
|
|
|
|
bool chorded_pressed = false;
|
2021-02-26 21:13:24 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// modifiers that can be toggled
|
|
|
|
|
// these get unset after each keypress (save for the locks)
|
2021-02-28 19:17:48 +00:00
|
|
|
|
bool mod_shift = false;
|
|
|
|
|
bool mod_shift_lock = false;
|
|
|
|
|
bool mod_symbol = false;
|
|
|
|
|
bool mod_symbol_lock = false;
|
|
|
|
|
bool mod_control = false;
|
|
|
|
|
bool mod_alt = false;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
bool mod_altgr = false;
|
2021-03-03 15:58:45 +00:00
|
|
|
|
bool mod_gui = false;
|
2021-03-03 16:57:54 +00:00
|
|
|
|
bool mod_function = false;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
|
|
|
|
|
IntervalTimer trackball_timer;
|
|
|
|
|
volatile bool trackball_update = false;
|
|
|
|
|
|
|
|
|
|
byte mouse_up = 0;
|
|
|
|
|
byte mouse_down = 0;
|
|
|
|
|
byte mouse_left = 0;
|
|
|
|
|
byte mouse_right = 0;
|
|
|
|
|
bool mouse_button = false;
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
we do a rudimentary form of mouse acceleration by adjusting movement speed
|
|
|
|
|
based on the distance moved during the last [num_mouse_samples] updates
|
|
|
|
|
*/
|
2021-03-02 20:47:32 +00:00
|
|
|
|
const int num_mouse_samples = 10;
|
|
|
|
|
int current_mouse_sample = 0;
|
|
|
|
|
int mouse_movement_sample = 0;
|
|
|
|
|
float mouse_acceleration = 0.0f;
|
|
|
|
|
const float mouse_accel_factor = 0.7f;
|
|
|
|
|
|
|
|
|
|
const int mouse_scroll_sensitivity = 6;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
int mouse_scroll_dist = 0;
|
|
|
|
|
bool mouse_middle_pressed = false;
|
|
|
|
|
bool mouse_scrolled = false;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
|
2021-02-26 20:54:27 +00:00
|
|
|
|
void setup() {
|
2021-02-27 21:27:34 +00:00
|
|
|
|
pinMode(PIN_A, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_B, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_C, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_D, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_E, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_F, INPUT_PULLUP);
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
pinMode(PIN_MOUSE_UPPER_LEFT, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_MOUSE_UPPER_RIGHT, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_MOUSE_LOWER_LEFT, INPUT_PULLUP);
|
|
|
|
|
pinMode(PIN_MOUSE_LOWER_RIGHT, INPUT_PULLUP);
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
|
|
|
|
pinMode(PIN_LED1, OUTPUT);
|
|
|
|
|
pinMode(PIN_LED2, OUTPUT);
|
|
|
|
|
pinMode(PIN_LED3, OUTPUT);
|
|
|
|
|
|
2021-03-02 20:47:32 +00:00
|
|
|
|
// poll trackball at 10kHz
|
|
|
|
|
trackball_timer.begin(trackball_isr, 100);
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
|
|
|
|
Wire.begin();
|
2021-02-26 20:54:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void loop() {
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*******************
|
|
|
|
|
BUTTONS
|
|
|
|
|
*******************/
|
2021-02-27 21:27:34 +00:00
|
|
|
|
for (byte b = 0; b < 10; b++) {
|
|
|
|
|
// button is pressed
|
|
|
|
|
if (!digitalRead(button_pins[b])) {
|
|
|
|
|
// increment button timer if it's not full
|
|
|
|
|
if (button_timers[b] < debounce_time)
|
2021-03-02 18:37:31 +00:00
|
|
|
|
button_timers[b]++;
|
|
|
|
|
else {
|
|
|
|
|
// update pressed gkos keys
|
|
|
|
|
if (b < 6) {
|
|
|
|
|
key_pressed |= 1 << b;
|
|
|
|
|
key_pressed_total |= 1 << b;
|
|
|
|
|
}
|
|
|
|
|
// update pressed mouse keys
|
|
|
|
|
else {
|
|
|
|
|
switch (b) {
|
|
|
|
|
case Button::MouseUL:
|
|
|
|
|
Mouse.press(MOUSE_LEFT);
|
|
|
|
|
break;
|
|
|
|
|
case Button::MouseUR:
|
|
|
|
|
Mouse.press(MOUSE_RIGHT);
|
|
|
|
|
break;
|
|
|
|
|
case Button::MouseDL:
|
|
|
|
|
case Button::MouseDR:
|
|
|
|
|
mouse_middle_pressed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// button is released
|
|
|
|
|
else {
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// if the button was debounced, it counts as a press
|
2021-02-27 21:27:34 +00:00
|
|
|
|
if (button_timers[b] >= debounce_time) {
|
2021-03-02 18:37:31 +00:00
|
|
|
|
// gkos key released
|
2021-02-27 21:27:34 +00:00
|
|
|
|
if (b < 6) {
|
|
|
|
|
key_pressed &= ~(1 << b);
|
2021-03-02 18:37:31 +00:00
|
|
|
|
key_released(b);
|
2021-02-28 19:17:48 +00:00
|
|
|
|
update_leds();
|
2021-02-27 21:27:34 +00:00
|
|
|
|
if (key_pressed == 0) {
|
|
|
|
|
key_pressed_total = 0;
|
|
|
|
|
// clear flags
|
2021-02-28 17:51:43 +00:00
|
|
|
|
chord_used = false;
|
|
|
|
|
chorded_pressed = false;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
// mouse button released
|
|
|
|
|
else {
|
|
|
|
|
switch (b) {
|
|
|
|
|
case Button::MouseUL:
|
|
|
|
|
Mouse.release(MOUSE_LEFT);
|
|
|
|
|
break;
|
|
|
|
|
case Button::MouseUR:
|
|
|
|
|
Mouse.release(MOUSE_RIGHT);
|
|
|
|
|
break;
|
|
|
|
|
case Button::MouseDL:
|
|
|
|
|
case Button::MouseDR:
|
|
|
|
|
if (!mouse_scrolled)
|
|
|
|
|
Mouse.click(MOUSE_MIDDLE);
|
|
|
|
|
mouse_middle_pressed = mouse_scrolled = false;
|
2021-03-02 20:47:32 +00:00
|
|
|
|
mouse_scroll_dist = 0;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
|
|
|
|
button_timers[b] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*******************
|
|
|
|
|
TRACKBALL
|
|
|
|
|
*******************/
|
2021-03-02 18:37:31 +00:00
|
|
|
|
noInterrupts();
|
|
|
|
|
if (trackball_update) {
|
|
|
|
|
Wire.beginTransmission(TRACKBALL_ADDR);
|
|
|
|
|
Wire.write(TRACKBALL_REG_LEFT);
|
|
|
|
|
Wire.endTransmission();
|
|
|
|
|
|
|
|
|
|
Wire.requestFrom(TRACKBALL_ADDR, 5);
|
|
|
|
|
mouse_left = Wire.read();
|
|
|
|
|
mouse_right = Wire.read();
|
|
|
|
|
mouse_up = Wire.read();
|
|
|
|
|
mouse_down = Wire.read();
|
|
|
|
|
mouse_button = Wire.read();
|
|
|
|
|
|
|
|
|
|
int mouse_x = mouse_right - mouse_left;
|
|
|
|
|
int mouse_y = mouse_down - mouse_up;
|
2021-03-02 20:47:32 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// calculate mouse acceleration every [num_mouse_samples] updates
|
2021-03-02 20:47:32 +00:00
|
|
|
|
mouse_movement_sample += abs(mouse_x) + abs(mouse_y);
|
|
|
|
|
current_mouse_sample++;
|
|
|
|
|
if (current_mouse_sample > num_mouse_samples) {
|
|
|
|
|
current_mouse_sample = 0;
|
|
|
|
|
mouse_acceleration = 1.0f + mouse_movement_sample * mouse_accel_factor;
|
|
|
|
|
mouse_movement_sample = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// scroll with the middle mouse button
|
2021-03-02 18:37:31 +00:00
|
|
|
|
if (mouse_middle_pressed) {
|
|
|
|
|
mouse_scroll_dist += mouse_y;
|
|
|
|
|
if (abs(mouse_scroll_dist) > mouse_scroll_sensitivity) {
|
|
|
|
|
Mouse.scroll(mouse_scroll_dist % mouse_scroll_sensitivity);
|
|
|
|
|
mouse_scroll_dist %= mouse_scroll_sensitivity;
|
|
|
|
|
mouse_scrolled = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-03-02 20:47:32 +00:00
|
|
|
|
Mouse.move(mouse_x * mouse_acceleration, mouse_y * mouse_acceleration);
|
2021-03-02 18:37:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trackball_update = false;
|
|
|
|
|
}
|
|
|
|
|
interrupts();
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-02 18:37:31 +00:00
|
|
|
|
void key_released(byte key) {
|
2021-02-28 19:17:48 +00:00
|
|
|
|
int target = 0;
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
SPECIAL KEY COMBINATIONS
|
|
|
|
|
*************************************************/
|
2021-02-27 21:27:34 +00:00
|
|
|
|
bool is_special = false;
|
|
|
|
|
byte special = 0;
|
2021-03-03 17:39:28 +00:00
|
|
|
|
for (byte b = 0; b < 23; b++) {
|
2021-02-27 21:27:34 +00:00
|
|
|
|
if (key_pressed_total == specials[b]) {
|
|
|
|
|
is_special = true;
|
|
|
|
|
special = b;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-28 17:51:43 +00:00
|
|
|
|
if (is_special && !chord_used) {
|
2021-02-27 21:27:34 +00:00
|
|
|
|
// only register a special keypress when all keys have been released
|
|
|
|
|
if (key_pressed != 0)
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
|
|
|
|
|
target = special_action_targets[special];
|
2021-03-03 16:57:54 +00:00
|
|
|
|
if ((mod_shift || mod_shift_lock || mod_symbol || mod_symbol_lock) &&
|
|
|
|
|
special_action_targets_symbol[special] != 0)
|
|
|
|
|
target = special_action_targets_symbol[special];
|
|
|
|
|
if (mod_function &&
|
|
|
|
|
special_action_targets_function[special] != 0)
|
|
|
|
|
target = special_action_targets_function[special];
|
2021-02-27 21:27:34 +00:00
|
|
|
|
|
2021-02-28 17:51:43 +00:00
|
|
|
|
switch (special_action_target_types[special]) {
|
|
|
|
|
case ActionType::PressKey:
|
2021-03-02 18:37:31 +00:00
|
|
|
|
press_key(target);
|
|
|
|
|
return;
|
2021-02-28 17:51:43 +00:00
|
|
|
|
case ActionType::ToggleModifier:
|
2021-02-28 19:17:48 +00:00
|
|
|
|
switch (target) {
|
|
|
|
|
case Modifier::Shift:
|
|
|
|
|
mod_symbol = mod_symbol_lock = false;
|
|
|
|
|
if (mod_shift_lock) {
|
|
|
|
|
mod_shift_lock = false;
|
|
|
|
|
} else if (mod_shift) {
|
|
|
|
|
mod_shift = false;
|
|
|
|
|
mod_shift_lock = true;
|
|
|
|
|
} else {
|
|
|
|
|
mod_shift = true;
|
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
case Modifier::SymbolShift:
|
|
|
|
|
mod_shift = mod_shift_lock = mod_symbol_lock = false;
|
|
|
|
|
mod_symbol = !mod_symbol;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
case Modifier::Keyset:
|
|
|
|
|
mod_shift = mod_shift_lock = mod_symbol = false;
|
|
|
|
|
mod_symbol_lock = !mod_symbol_lock;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
case Modifier::Control:
|
|
|
|
|
mod_control = !mod_control;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
case Modifier::Alt:
|
|
|
|
|
mod_alt = !mod_alt;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-03-03 15:58:45 +00:00
|
|
|
|
case Modifier::Gui:
|
|
|
|
|
mod_gui = !mod_gui;
|
|
|
|
|
return;
|
2021-03-03 16:57:54 +00:00
|
|
|
|
case Modifier::Function:
|
|
|
|
|
mod_function = !mod_function;
|
|
|
|
|
return;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
}
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
CHORDS AND KEYS THAT CAN BE CHORDED INTO
|
|
|
|
|
*************************************************/
|
2021-02-28 17:51:43 +00:00
|
|
|
|
bool is_chord = false;
|
|
|
|
|
byte chord = 0;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
for (byte b = 0; b < 8; b++) {
|
2021-02-28 17:51:43 +00:00
|
|
|
|
if ((key_pressed_total & chords[b]) == chords[b]) {
|
|
|
|
|
is_chord = true;
|
|
|
|
|
chord = b;
|
|
|
|
|
chord_used = true;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-28 17:51:43 +00:00
|
|
|
|
if (is_chord) {
|
|
|
|
|
// chord on its own
|
|
|
|
|
if (!chorded_pressed && key_pressed == 0 &&
|
|
|
|
|
key_pressed_total == chords[chord]) {
|
2021-02-28 19:17:48 +00:00
|
|
|
|
target = chord_targets[chord * 4];
|
2021-03-03 16:57:54 +00:00
|
|
|
|
if ((mod_symbol || mod_symbol_lock) &&
|
|
|
|
|
chord_targets_symbol[chord * 4] != 0)
|
|
|
|
|
target = chord_targets_symbol[chord * 4];
|
|
|
|
|
if (mod_function &&
|
|
|
|
|
chord_targets_function[chord * 4] != 0)
|
|
|
|
|
target = chord_targets_function[chord * 4];
|
2021-02-28 19:17:48 +00:00
|
|
|
|
|
2021-03-02 18:37:31 +00:00
|
|
|
|
press_key(target);
|
|
|
|
|
return;
|
2021-02-28 17:51:43 +00:00
|
|
|
|
}
|
|
|
|
|
// keys that can be chorded with
|
|
|
|
|
for (byte b = 0; b < 3; b++) {
|
|
|
|
|
if (key == chord_buttons[chord * 3 + b]) {
|
2021-02-28 19:17:48 +00:00
|
|
|
|
target = chord_targets[chord * 4 + 1 + b];
|
2021-03-03 16:57:54 +00:00
|
|
|
|
if ((mod_symbol || mod_symbol_lock) &&
|
|
|
|
|
chord_targets_symbol[chord * 4 + 1 + b] != 0)
|
|
|
|
|
target = chord_targets_symbol[chord * 4 + 1 + b];
|
|
|
|
|
if (mod_function &&
|
|
|
|
|
chord_targets_function[chord * 4 + 1 + b] != 0)
|
|
|
|
|
target = chord_targets_function[chord * 4 + 1 + b];
|
2021-02-28 19:17:48 +00:00
|
|
|
|
|
2021-02-28 17:51:43 +00:00
|
|
|
|
// erase key from total so you can hold the chord down for
|
|
|
|
|
// multiple chorded keypresses
|
|
|
|
|
key_pressed_total &= ~(1 << key);
|
|
|
|
|
chorded_pressed = true;
|
2021-03-02 18:37:31 +00:00
|
|
|
|
press_key(target);
|
|
|
|
|
return;
|
2021-02-28 17:51:43 +00:00
|
|
|
|
}
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
2021-02-27 21:27:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
KEYBOARD KEYS (ON THEIR OWN)
|
|
|
|
|
*************************************************/
|
|
|
|
|
if (mod_function && keys_function[key] != 0)
|
|
|
|
|
press_key(keys_function[key]);
|
2021-03-03 16:57:54 +00:00
|
|
|
|
else if (mod_symbol || mod_symbol_lock)
|
2021-03-03 17:39:28 +00:00
|
|
|
|
press_key(keys_symbol[key]);
|
2021-02-28 19:17:48 +00:00
|
|
|
|
else
|
2021-03-03 17:39:28 +00:00
|
|
|
|
press_key(keys[key]);
|
2021-03-02 18:37:31 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void press_key(int key) {
|
|
|
|
|
// check if modifiers need to be forced
|
|
|
|
|
if (key & MASK_SHIFT) {
|
|
|
|
|
mod_shift = true;
|
|
|
|
|
key &= ~(MASK_SHIFT);
|
|
|
|
|
}
|
|
|
|
|
if (key & MASK_ALTGR) {
|
|
|
|
|
mod_altgr = true;
|
|
|
|
|
key &= ~(MASK_ALTGR);
|
|
|
|
|
}
|
2021-03-03 16:08:51 +00:00
|
|
|
|
if (key & MASK_CTRL) {
|
|
|
|
|
mod_control = true;
|
|
|
|
|
key &= ~(MASK_CTRL);
|
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
|
2021-03-03 17:39:28 +00:00
|
|
|
|
// press modifiers
|
2021-03-02 18:37:31 +00:00
|
|
|
|
if (mod_shift || mod_shift_lock)
|
|
|
|
|
Keyboard.press(KEY_LEFT_SHIFT);
|
|
|
|
|
if (mod_control)
|
|
|
|
|
Keyboard.press(KEY_LEFT_CTRL);
|
|
|
|
|
if (mod_alt)
|
|
|
|
|
Keyboard.press(KEY_LEFT_ALT);
|
|
|
|
|
if (mod_altgr)
|
|
|
|
|
Keyboard.press(KEY_RIGHT_ALT);
|
2021-03-03 15:58:45 +00:00
|
|
|
|
if (mod_gui)
|
|
|
|
|
Keyboard.press(KEY_LEFT_GUI);
|
2021-03-02 18:37:31 +00:00
|
|
|
|
|
|
|
|
|
// keypress
|
|
|
|
|
Keyboard.press(key);
|
|
|
|
|
Keyboard.release(key);
|
|
|
|
|
|
|
|
|
|
// release modifiers
|
|
|
|
|
if (mod_shift || mod_shift_lock)
|
|
|
|
|
Keyboard.release(KEY_LEFT_SHIFT);
|
|
|
|
|
if (mod_control)
|
|
|
|
|
Keyboard.release(KEY_LEFT_CTRL);
|
|
|
|
|
if (mod_alt)
|
|
|
|
|
Keyboard.release(KEY_LEFT_ALT);
|
|
|
|
|
if (mod_altgr)
|
|
|
|
|
Keyboard.release(KEY_RIGHT_ALT);
|
2021-03-03 15:58:45 +00:00
|
|
|
|
if (mod_gui)
|
|
|
|
|
Keyboard.release(KEY_LEFT_GUI);
|
2021-03-02 18:37:31 +00:00
|
|
|
|
|
|
|
|
|
// clear temporary modifiers
|
2021-03-03 16:57:54 +00:00
|
|
|
|
mod_shift = mod_symbol = mod_control = mod_alt = mod_altgr =
|
|
|
|
|
mod_gui = mod_function = false;
|
2021-02-28 19:17:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void update_leds() {
|
|
|
|
|
digitalWrite(PIN_LED1, mod_shift || mod_shift_lock);
|
|
|
|
|
digitalWrite(PIN_LED2, mod_symbol || mod_symbol_lock);
|
2021-03-03 16:57:54 +00:00
|
|
|
|
digitalWrite(PIN_LED3, mod_control || mod_alt || mod_gui || mod_function);
|
2021-02-26 20:54:27 +00:00
|
|
|
|
}
|
2021-03-02 18:37:31 +00:00
|
|
|
|
|
|
|
|
|
int sign(int num) {
|
|
|
|
|
if (num >= 0) return 1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void trackball_isr() {
|
|
|
|
|
trackball_update = true;
|
|
|
|
|
}
|