Compare commits

...

2 Commits

Author SHA1 Message Date
mintey 2ab8d0a68a some simple mouse acceleration 2021-03-02 22:47:32 +02:00
mintey ec0f7eda73 modifier keys and mousegit diff --cached 2021-03-02 20:37:31 +02:00
1 changed files with 221 additions and 103 deletions

View File

@ -3,6 +3,10 @@
#define TRACKBALL_ADDR 0x0A #define TRACKBALL_ADDR 0x0A
#define TRACKBALL_REG_LEFT 0x04 #define TRACKBALL_REG_LEFT 0x04
// using my own masks here since the inbuilt ones conflict with arrow keys etc.
#define MASK_SHIFT 0x100
#define MASK_ALTGR 0x200
const byte PIN_A = 33; const byte PIN_A = 33;
const byte PIN_B = 32; const byte PIN_B = 32;
const byte PIN_C = 31; const byte PIN_C = 31;
@ -21,25 +25,24 @@ const byte PIN_LED3 = 3;
const byte PIN_BALL_SDA = 18; const byte PIN_BALL_SDA = 18;
const byte PIN_BALL_SCL = 19; const byte PIN_BALL_SCL = 19;
const byte PIN_BALL_INT = 11;
enum Button { A, B, C, D, E, F, MouseUL, MouseUR, MouseDL, MouseDR }; enum Button { A, B, C, D, E, F, MouseUL, MouseUR, MouseDL, MouseDR };
const int button_pins[10] = { const int button_pins[10] = {
PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F, PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F,
PIN_MOUSE_UL, PIN_MOUSE_UR, PIN_MOUSE_DL, PIN_MOUSE_DR PIN_MOUSE_UL, PIN_MOUSE_UR, PIN_MOUSE_DL, PIN_MOUSE_DR
}; };
const int debounce_time = 400; const int debounce_time = 50;
int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int button_timers[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// different actions that the keyboard can take // different actions that the keyboard can take
// - print a single character
// - press (and release) a key // - press (and release) a key
// - toggle a modifier // - toggle a modifier
enum ActionType { PrintCharacter, PressKey, ToggleModifier }; enum ActionType { PressKey, ToggleModifier };
const char button_characters[6] = { 'a', 'b', 'c', 'd', 'e', 'f' }; const int button_characters[6] = { KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F };
const char button_characters_shifted[6] = { 'A', 'B', 'C', 'D', 'E', 'F' }; const int button_characters_symbol[6] = {
const char button_characters_symbol[6] = { '1', '2', '3', '4', '5', '6' }; KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6
};
/* /*
backspace, space (keep those two first since they overlap with the rest ) backspace, space (keep those two first since they overlap with the rest )
@ -62,44 +65,27 @@ const byte chord_buttons[24] = {
const int chord_targets[32] = { const int chord_targets[32] = {
KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME, KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME,
KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END, KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END,
'g', 'h', 'i', 'j', KEY_G, KEY_H, KEY_I, KEY_J,
'k', 'l', 'm', 'n', KEY_K, KEY_L, KEY_M, KEY_N,
'o', 'p', 'q', 'r', KEY_O, KEY_P, KEY_Q, KEY_R,
's', 't', 'u', 'v', KEY_S, KEY_T, KEY_U, KEY_V,
'w', 'x', 'y', 'z', KEY_W, KEY_X, KEY_Y, KEY_Z,
0, 0, 0, 0 0, 0, 0, 0
}; };
const int chord_targets_shifted[32] = {
KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME,
KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END,
'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z',
0, 0, 0, 0
};
// TODO: check that all the symbols work
// TODO: match symbols to keypresses in the keyboard layout
const int chord_targets_symbol[32] = { const int chord_targets_symbol[32] = {
KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME, KEY_BACKSPACE, KEY_LEFT, KEY_LEFT, KEY_HOME,
KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END, KEY_SPACE, KEY_RIGHT, KEY_RIGHT, KEY_END,
'0', '7', '8', '9', KEY_0, KEY_7, KEY_8, KEY_9,
'#', '@', '½', '&', // # @ ½ &
'+', '%', '=', '^', 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,
const byte chord_target_types[32] = { // ( [ < {
1, 1, 1, 1, KEY_9 + MASK_SHIFT, KEY_LEFT_BRACE, KEY_COMMA + MASK_SHIFT, KEY_LEFT_BRACE + MASK_SHIFT,
1, 1, 1, 1, // ) ] > }
0, 0, 0, 0, KEY_0 + MASK_SHIFT, KEY_RIGHT_BRACE, KEY_PERIOD + MASK_SHIFT, KEY_RIGHT_BRACE + MASK_SHIFT,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
}; };
/* /*
@ -107,25 +93,34 @@ dash, backslash, slash, apostrophe, comma, exclamation point, question mark,
period, up, down, page up, page down, shift, symbol shift, switch keyset, period, up, down, page up, page down, shift, symbol shift, switch keyset,
escape, control, alt, delete, insert, tab, enter escape, control, alt, delete, insert, tab, enter
*/ */
// TODO: add the middle specials for function keys instead of the weird symbols
const byte specials[22] = { const byte specials[22] = {
17, 51, 30, 10, 20, 12, 33, 34, 9, 36, 27, 17, 51, 30, 10, 20, 12, 33, 34, 9, 36, 27,
54, 18, 45, 63, 31, 47, 55, 62, 43, 61, 59 54, 18, 45, 63, 31, 47, 55, 62, 43, 61, 59
}; };
enum Modifier { Shift, SymbolShift, Keyset, Control, Alt }; enum Modifier { Shift, SymbolShift, Keyset, Control, Alt };
const int special_action_targets[22] = { const int special_action_targets[22] = {
'-', '\\', '/', '\'', ',', '!', '?', '/', KEY_UP, KEY_DOWN, KEY_PAGE_UP, // - \ / '
KEY_PAGE_DOWN, Modifier::Shift, Modifier::SymbolShift, Modifier::Keyset, KEY_MINUS, KEY_MINUS + MASK_ALTGR, KEY_SLASH, KEY_QUOTE,
// , ! ? .
KEY_COMMA, KEY_1 + MASK_SHIFT, KEY_SLASH + MASK_SHIFT, KEY_PERIOD,
KEY_UP, KEY_DOWN, KEY_PAGE_UP, KEY_PAGE_DOWN,
Modifier::Shift, Modifier::SymbolShift, Modifier::Keyset,
KEY_ESC, Modifier::Control, Modifier::Alt, KEY_DELETE, KEY_INSERT, KEY_ESC, Modifier::Control, Modifier::Alt, KEY_DELETE, KEY_INSERT,
KEY_TAB, KEY_ENTER KEY_TAB, KEY_ENTER
}; };
const int special_action_targets_symbol[22] = { const int special_action_targets_symbol[22] = {
'_', '\`', 0, '\"', ';', '|', '~', ':', 0, 0, 0, // _ ` ´ "
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,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0 0, 0
}; };
const byte special_action_target_types[22] = { const byte special_action_target_types[22] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0
}; };
byte key_pressed = 0; byte key_pressed = 0;
@ -137,9 +132,29 @@ bool mod_shift = false;
bool mod_shift_lock = false; bool mod_shift_lock = false;
bool mod_symbol = false; bool mod_symbol = false;
bool mod_symbol_lock = false; bool mod_symbol_lock = false;
// TODO: control and alt modifiers
bool mod_control = false; bool mod_control = false;
bool mod_alt = false; bool mod_alt = false;
bool mod_altgr = false;
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;
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;
int mouse_scroll_dist = 0;
bool mouse_middle_pressed = false;
bool mouse_scrolled = false;
void setup() { void setup() {
pinMode(PIN_A, INPUT_PULLUP); pinMode(PIN_A, INPUT_PULLUP);
@ -158,35 +173,54 @@ void setup() {
pinMode(PIN_LED2, OUTPUT); pinMode(PIN_LED2, OUTPUT);
pinMode(PIN_LED3, OUTPUT); pinMode(PIN_LED3, OUTPUT);
Serial.begin(115200); // poll trackball at 10kHz
Serial.println("helo"); trackball_timer.begin(trackball_isr, 100);
Wire.begin(); Wire.begin();
} }
void loop() { void loop() {
/*
BUTTONS
*/
for (byte b = 0; b < 10; b++) { for (byte b = 0; b < 10; b++) {
// button is pressed // button is pressed
if (!digitalRead(button_pins[b])) { if (!digitalRead(button_pins[b])) {
// increment button timer if it's not full // increment button timer if it's not full
if (button_timers[b] < debounce_time) if (button_timers[b] < debounce_time)
button_timers[b]++; button_timers[b]++;
// update pressed gkos keys else {
else if (b < 6) { // update pressed gkos keys
key_pressed |= 1 << b; if (b < 6) {
key_pressed_total |= 1 << b; 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;
}
}
} }
} }
// button is released // button is released
else { else {
// if the button had been debounced, it counts as a keypress // if the button had been debounced, it counts as a press
if (button_timers[b] >= debounce_time) { if (button_timers[b] >= debounce_time) {
// gkos key released
if (b < 6) { if (b < 6) {
key_pressed &= ~(1 << b); key_pressed &= ~(1 << b);
// gkos key was released, check if it completed a chord // check if it completed a chord
// clear temporary modifiers if a keypress was completed key_released(b);
if (key_released(b))
mod_shift = mod_symbol = mod_control = mod_alt = false;
update_leds(); update_leds();
if (key_pressed == 0) { if (key_pressed == 0) {
key_pressed_total = 0; key_pressed_total = 0;
@ -195,14 +229,74 @@ void loop() {
chorded_pressed = false; chorded_pressed = false;
} }
} }
// 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;
mouse_scroll_dist = 0;
break;
}
}
} }
button_timers[b] = 0; button_timers[b] = 0;
} }
} }
/*
TRACKBALL
*/
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;
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;
}
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 {
Mouse.move(mouse_x * mouse_acceleration, mouse_y * mouse_acceleration);
}
trackball_update = false;
}
interrupts();
} }
// returns true if a keypress was completed // returns true if a keypress was completed
bool key_released(byte key) { void key_released(byte key) {
int target = 0; int target = 0;
/* /*
@ -221,7 +315,7 @@ bool key_released(byte key) {
if (is_special && !chord_used) { if (is_special && !chord_used) {
// only register a special keypress when all keys have been released // only register a special keypress when all keys have been released
if (key_pressed != 0) if (key_pressed != 0)
return false; return;
target = special_action_targets[special]; target = special_action_targets[special];
if (mod_shift || mod_shift_lock || mod_symbol || mod_symbol_lock) { if (mod_shift || mod_shift_lock || mod_symbol || mod_symbol_lock) {
@ -230,13 +324,9 @@ bool key_released(byte key) {
} }
switch (special_action_target_types[special]) { switch (special_action_target_types[special]) {
case ActionType::PrintCharacter:
Keyboard.print((char)target);
return true;
case ActionType::PressKey: case ActionType::PressKey:
Keyboard.press(target); press_key(target);
Keyboard.release(target); return;
return true;
case ActionType::ToggleModifier: case ActionType::ToggleModifier:
switch (target) { switch (target) {
case Modifier::Shift: case Modifier::Shift:
@ -249,24 +339,24 @@ bool key_released(byte key) {
} else { } else {
mod_shift = true; mod_shift = true;
} }
return false; return;
case Modifier::SymbolShift: case Modifier::SymbolShift:
mod_shift = mod_shift_lock = mod_symbol_lock = false; mod_shift = mod_shift_lock = mod_symbol_lock = false;
mod_symbol = !mod_symbol; mod_symbol = !mod_symbol;
return false; return;
case Modifier::Keyset: case Modifier::Keyset:
mod_shift = mod_shift_lock = mod_symbol = false; mod_shift = mod_shift_lock = mod_symbol = false;
mod_symbol_lock = !mod_symbol_lock; mod_symbol_lock = !mod_symbol_lock;
return false; return;
case Modifier::Control: case Modifier::Control:
mod_control = !mod_control; mod_control = !mod_control;
return false; return;
case Modifier::Alt: case Modifier::Alt:
mod_alt = !mod_alt; mod_alt = !mod_alt;
return false; return;
} }
} }
return false; return;
} }
/* /*
@ -288,59 +378,78 @@ bool key_released(byte key) {
if (!chorded_pressed && key_pressed == 0 && if (!chorded_pressed && key_pressed == 0 &&
key_pressed_total == chords[chord]) { key_pressed_total == chords[chord]) {
target = chord_targets[chord * 4]; target = chord_targets[chord * 4];
if (mod_shift || mod_shift_lock) if (mod_symbol || mod_symbol_lock)
target = chord_targets_shifted[chord * 4];
else if (mod_symbol || mod_symbol_lock)
target = chord_targets_symbol[chord * 4]; target = chord_targets_symbol[chord * 4];
switch (chord_target_types[chord * 4]) { press_key(target);
case ActionType::PrintCharacter: return;
Keyboard.print((char)target);
return true;
case ActionType::PressKey:
Keyboard.press(target);
Keyboard.release(target);
return true;
}
return false;
} }
// keys that can be chorded with // keys that can be chorded with
for (byte b = 0; b < 3; b++) { for (byte b = 0; b < 3; b++) {
if (key == chord_buttons[chord * 3 + b]) { if (key == chord_buttons[chord * 3 + b]) {
target = chord_targets[chord * 4 + 1 + b]; target = chord_targets[chord * 4 + 1 + b];
if (mod_shift || mod_shift_lock) if (mod_symbol || mod_symbol_lock)
target = chord_targets_shifted[chord * 4 + 1 + b];
else if (mod_symbol || mod_symbol_lock)
target = chord_targets_symbol[chord * 4 + 1 + b]; target = chord_targets_symbol[chord * 4 + 1 + b];
// erase key from total so you can hold the chord down for // erase key from total so you can hold the chord down for
// multiple chorded keypresses // multiple chorded keypresses
key_pressed_total &= ~(1 << key); key_pressed_total &= ~(1 << key);
chorded_pressed = true; chorded_pressed = true;
switch (chord_target_types[chord * 4 + 1 + b]) { press_key(target);
case ActionType::PrintCharacter: return;
Keyboard.print((char)target);
return true;
case ActionType::PressKey:
Keyboard.press(target);
Keyboard.release(target);
return true;
}
} }
} }
return false; return;
} }
/* /*
REGULAR KEYS REGULAR KEYS
*/ */
if (mod_shift || mod_shift_lock) // keypress
Keyboard.print(button_characters_shifted[key]); if (mod_symbol || mod_symbol_lock)
else if (mod_symbol || mod_symbol_lock) press_key(button_characters_symbol[key]);
Keyboard.print(button_characters_symbol[key]);
else else
Keyboard.print(button_characters[key]); press_key(button_characters[key]);
return true; 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);
}
// modifiers
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);
// 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);
// clear temporary modifiers
mod_shift = mod_symbol = mod_control = mod_alt = mod_altgr = false;
} }
void update_leds() { void update_leds() {
@ -348,3 +457,12 @@ void update_leds() {
digitalWrite(PIN_LED2, mod_symbol || mod_symbol_lock); digitalWrite(PIN_LED2, mod_symbol || mod_symbol_lock);
digitalWrite(PIN_LED3, mod_control || mod_alt); digitalWrite(PIN_LED3, mod_control || mod_alt);
} }
int sign(int num) {
if (num >= 0) return 1;
return -1;
}
void trackball_isr() {
trackball_update = true;
}