2017-02-20 18:55:16 +00:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include "teensy-keyboard.h"
|
|
|
|
#include <Keypad.h>
|
2020-07-04 11:41:32 +00:00
|
|
|
#include "teensy-println.h"
|
2017-02-20 18:55:16 +00:00
|
|
|
|
2021-01-11 15:53:03 +00:00
|
|
|
#include "globals.h"
|
|
|
|
#include "teensy-mouse.h"
|
|
|
|
|
2017-02-20 18:55:16 +00:00
|
|
|
const byte ROWS = 5;
|
|
|
|
const byte COLS = 13;
|
|
|
|
|
|
|
|
char keys[ROWS][COLS] = {
|
2018-02-07 15:20:26 +00:00
|
|
|
{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', PK_DEL },
|
|
|
|
{ PK_ESC, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']' },
|
|
|
|
{ PK_CTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', PK_RET },
|
2021-01-20 03:28:14 +00:00
|
|
|
{ PK_LSHFT, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', PK_RSHFT, PK_NONE },
|
|
|
|
{ PK_LOCK, '`', PK_TAB, '\\', PK_LA, ' ', PK_RA, PK_LARR, PK_RARR, PK_DARR, PK_UARR, PK_NONE, PK_NONE }
|
2017-02-20 18:55:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
uint8_t rowsPins[ROWS] = { 33, 34, 35, 36, 37 };
|
2020-07-15 14:19:57 +00:00
|
|
|
uint8_t colsPins[COLS] = { 41, 40, 3, 4, 24, 25, 39, 23, 28, 29, 30, 31, 32 }; // 0, 1, 26, 27 are moving to ... 41, 40, 39, 23?
|
2017-02-20 18:55:16 +00:00
|
|
|
Keypad keypad(makeKeymap(keys), rowsPins, colsPins, ROWS, COLS);
|
2021-01-20 01:14:49 +00:00
|
|
|
|
|
|
|
struct _tkb_event {
|
|
|
|
uint8_t keycode;
|
|
|
|
bool pressedIfTrue;
|
|
|
|
struct _tkb_event *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAXKBEVENTS 10
|
|
|
|
struct _tkb_event keyboardEvents[MAXKBEVENTS];
|
|
|
|
uint8_t kbEventCount = 0;
|
|
|
|
uint8_t kbEventHead = 0;
|
|
|
|
uint8_t kbEventPtr = 0;
|
|
|
|
|
2021-01-20 01:42:15 +00:00
|
|
|
bool TeensyKeyboard::addEvent(uint8_t kc, bool pressed)
|
2021-01-20 01:14:49 +00:00
|
|
|
{
|
|
|
|
if (kbEventCount >= MAXKBEVENTS)
|
|
|
|
return false;
|
|
|
|
|
2021-01-20 01:42:15 +00:00
|
|
|
if (pressed && kbEventCount+numPressed >= MAXKBEVENTS) {
|
|
|
|
// save space in the event queue for any keyup events that may come
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:14:49 +00:00
|
|
|
keyboardEvents[kbEventPtr].keycode = kc;
|
|
|
|
keyboardEvents[kbEventPtr++].pressedIfTrue = pressed;
|
|
|
|
if (kbEventPtr >= MAXKBEVENTS) kbEventPtr = 0;
|
|
|
|
kbEventCount++;
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:42:15 +00:00
|
|
|
bool TeensyKeyboard::popEvent(uint8_t *kc, bool *pressed)
|
2021-01-20 01:14:49 +00:00
|
|
|
{
|
|
|
|
if (kbEventCount) {
|
|
|
|
*kc = keyboardEvents[kbEventHead].keycode;
|
|
|
|
*pressed = keyboardEvents[kbEventHead++].pressedIfTrue;
|
|
|
|
if (kbEventHead >= MAXKBEVENTS) kbEventHead = 0;
|
|
|
|
kbEventCount--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-02-20 18:55:16 +00:00
|
|
|
|
|
|
|
static uint8_t shiftedNumber[] = { '<', // ,
|
|
|
|
'_', // -
|
|
|
|
'>', // .
|
|
|
|
'?', // /
|
|
|
|
')', // 0
|
|
|
|
'!', // 1
|
|
|
|
'@', // 2
|
|
|
|
'#', // 3
|
|
|
|
'$', // 4
|
|
|
|
'%', // 5
|
|
|
|
'^', // 6
|
|
|
|
'&', // 7
|
|
|
|
'*', // 8
|
|
|
|
'(', // 9
|
|
|
|
0, // (: is not a key)
|
|
|
|
':' // ;
|
|
|
|
};
|
|
|
|
|
|
|
|
TeensyKeyboard::TeensyKeyboard(VMKeyboard *k) : PhysicalKeyboard(k)
|
|
|
|
{
|
2021-01-20 12:41:24 +00:00
|
|
|
// Need to set the rows to be pull-ups early, so the pullups have
|
|
|
|
// time to settle -- otherwise we get a phantom set of keypresses
|
|
|
|
// on startup for all the keys in the first column
|
|
|
|
for (byte i=0; i<ROWS; i++) {
|
|
|
|
pinMode(rowsPins[i], INPUT_PULLUP);
|
|
|
|
}
|
2021-01-21 01:54:39 +00:00
|
|
|
keypad.setDebounceTime(5);
|
2021-01-20 03:28:14 +00:00
|
|
|
|
2017-02-20 18:55:16 +00:00
|
|
|
leftShiftPressed = false;
|
|
|
|
rightShiftPressed = false;
|
|
|
|
ctrlPressed = false;
|
|
|
|
capsLock = true;
|
|
|
|
leftApplePressed = false;
|
|
|
|
rightApplePressed = false;
|
|
|
|
|
|
|
|
numPressed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TeensyKeyboard::~TeensyKeyboard()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-01-07 17:24:07 +00:00
|
|
|
// apply modifiers to keycode and return result
|
|
|
|
uint8_t TeensyKeyboard::modifyKeycode(uint8_t key)
|
2017-02-20 18:55:16 +00:00
|
|
|
{
|
2018-02-07 15:20:26 +00:00
|
|
|
if (key == ' ' || key == PK_DEL || key == PK_ESC || key == PK_RET || key == PK_TAB) {
|
2022-01-07 17:24:07 +00:00
|
|
|
return key;
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (key >= 'a' &&
|
|
|
|
key <= 'z') {
|
|
|
|
if (ctrlPressed) {
|
2022-01-07 17:24:07 +00:00
|
|
|
return key - 'a' + 1;
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
if (leftShiftPressed || rightShiftPressed || capsLock) {
|
2022-01-07 17:24:07 +00:00
|
|
|
return key - 'a' + 'A';
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
2022-01-07 17:24:07 +00:00
|
|
|
return key;
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: can we control-shift?
|
|
|
|
if (key >= ',' && key <= ';') {
|
|
|
|
if (leftShiftPressed || rightShiftPressed) {
|
2022-01-07 17:24:07 +00:00
|
|
|
return shiftedNumber[key - ','];
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
2022-01-07 17:24:07 +00:00
|
|
|
return key;
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (leftShiftPressed || rightShiftPressed) {
|
|
|
|
uint8_t ret = 0;
|
|
|
|
switch (key) {
|
|
|
|
case '=':
|
|
|
|
ret = '+';
|
|
|
|
break;
|
|
|
|
case '[':
|
|
|
|
ret = '{';
|
|
|
|
break;
|
|
|
|
case ']':
|
|
|
|
ret = '}';
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
ret = '|';
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
ret = '"';
|
|
|
|
break;
|
|
|
|
case '`':
|
|
|
|
ret = '~';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ret) {
|
2022-01-07 17:24:07 +00:00
|
|
|
return ret;
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-07 17:24:07 +00:00
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TeensyKeyboard::pressedKey(uint8_t key)
|
|
|
|
{
|
|
|
|
numPressed++;
|
|
|
|
if (key & 0x80) {
|
|
|
|
// it's a modifier key.
|
|
|
|
switch (key) {
|
|
|
|
case PK_CTRL:
|
|
|
|
ctrlPressed = 1;
|
|
|
|
break;
|
|
|
|
case PK_LSHFT:
|
|
|
|
leftShiftPressed = 1;
|
|
|
|
break;
|
|
|
|
case PK_RSHFT:
|
|
|
|
rightShiftPressed = 1;
|
|
|
|
break;
|
|
|
|
case PK_LOCK:
|
|
|
|
capsLock = !capsLock;
|
|
|
|
break;
|
|
|
|
case PK_LA:
|
|
|
|
leftApplePressed = 1;
|
|
|
|
break;
|
|
|
|
case PK_RA:
|
|
|
|
((TeensyMouse *)g_mouse)->mouseButtonEvent(true);
|
|
|
|
rightApplePressed = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
addEvent(key, true);
|
|
|
|
return;
|
|
|
|
}
|
2017-02-20 18:55:16 +00:00
|
|
|
|
2022-01-07 17:24:07 +00:00
|
|
|
addEvent(modifyKeycode(key), true);
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TeensyKeyboard::releasedKey(uint8_t key)
|
|
|
|
{
|
|
|
|
numPressed--;
|
|
|
|
if (key & 0x80) {
|
|
|
|
// it's a modifier key.
|
|
|
|
switch (key) {
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_CTRL:
|
2017-02-20 18:55:16 +00:00
|
|
|
ctrlPressed = 0;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_LSHFT:
|
2017-02-20 18:55:16 +00:00
|
|
|
leftShiftPressed = 0;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_RSHFT:
|
2017-02-20 18:55:16 +00:00
|
|
|
rightShiftPressed = 0;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_LA:
|
2021-01-11 15:53:03 +00:00
|
|
|
((TeensyMouse *)g_mouse)->mouseButtonEvent(false);
|
2017-02-20 18:55:16 +00:00
|
|
|
leftApplePressed = 0;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_RA:
|
2017-02-20 18:55:16 +00:00
|
|
|
rightApplePressed = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-01-07 17:24:07 +00:00
|
|
|
addEvent(modifyKeycode(key), false);
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool TeensyKeyboard::kbhit()
|
|
|
|
{
|
|
|
|
if (keypad.getKeys()) {
|
|
|
|
for (int i=0; i<LIST_MAX; i++) {
|
2021-01-20 03:28:14 +00:00
|
|
|
if ( keypad.key[i].stateChanged && keypad.key[i].kchar != PK_NONE ) {
|
2017-02-20 18:55:16 +00:00
|
|
|
switch (keypad.key[i].kstate) {
|
|
|
|
case PRESSED:
|
|
|
|
pressedKey(keypad.key[i].kchar);
|
|
|
|
break;
|
|
|
|
case RELEASED:
|
|
|
|
releasedKey(keypad.key[i].kchar);
|
|
|
|
break;
|
|
|
|
case HOLD:
|
|
|
|
case IDLE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:14:49 +00:00
|
|
|
return kbEventCount;
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int8_t TeensyKeyboard::read()
|
|
|
|
{
|
2021-01-20 01:14:49 +00:00
|
|
|
if (kbEventCount) {
|
|
|
|
uint8_t kc;
|
|
|
|
bool pressed;
|
|
|
|
if (popEvent(&kc, &pressed)) {
|
|
|
|
if (pressed) {
|
|
|
|
return kc;
|
|
|
|
}
|
|
|
|
}
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:14:49 +00:00
|
|
|
// This is the interface to the physical keyboard, as used by the VM.
|
2017-02-20 18:55:16 +00:00
|
|
|
void TeensyKeyboard::maintainKeyboard()
|
|
|
|
{
|
2021-01-20 01:14:49 +00:00
|
|
|
kbhit();
|
|
|
|
|
|
|
|
if (kbEventCount) {
|
|
|
|
uint8_t kc;
|
|
|
|
bool pressed;
|
|
|
|
if (popEvent(&kc, &pressed)) {
|
|
|
|
if (pressed) {
|
|
|
|
vmkeyboard->keyDepressed(kc);
|
|
|
|
} else {
|
|
|
|
vmkeyboard->keyReleased(kc);
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|