2017-02-20 18:55:16 +00:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include "teensy-keyboard.h"
|
|
|
|
#include <Keypad.h>
|
2017-12-30 20:20:34 +00:00
|
|
|
#include "LRingBuffer.h"
|
2020-07-04 11:41:32 +00:00
|
|
|
#include "teensy-println.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 },
|
|
|
|
{ PK_LSHFT, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', PK_RSHFT, 0 },
|
|
|
|
{ PK_LOCK, '`', PK_TAB, '\\', PK_LA, ' ', PK_RA, PK_LARR, PK_RARR, PK_DARR, PK_UARR, 0, 0 }
|
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);
|
2017-12-30 20:20:34 +00:00
|
|
|
LRingBuffer buffer(10); // 10 keys should be plenty, right?
|
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)
|
|
|
|
{
|
|
|
|
keypad.setDebounceTime(5);
|
|
|
|
|
|
|
|
leftShiftPressed = false;
|
|
|
|
rightShiftPressed = false;
|
|
|
|
ctrlPressed = false;
|
|
|
|
capsLock = true;
|
|
|
|
leftApplePressed = false;
|
|
|
|
rightApplePressed = false;
|
|
|
|
|
|
|
|
numPressed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TeensyKeyboard::~TeensyKeyboard()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void TeensyKeyboard::pressedKey(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 = 1;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_LSHFT:
|
2017-02-20 18:55:16 +00:00
|
|
|
leftShiftPressed = 1;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_RSHFT:
|
2017-02-20 18:55:16 +00:00
|
|
|
rightShiftPressed = 1;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_LOCK:
|
2017-02-20 18:55:16 +00:00
|
|
|
capsLock = !capsLock;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_LA:
|
2017-02-20 18:55:16 +00:00
|
|
|
leftApplePressed = 1;
|
|
|
|
break;
|
2018-02-07 15:20:26 +00:00
|
|
|
case PK_RA:
|
2017-02-20 18:55:16 +00:00
|
|
|
rightApplePressed = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-07 15:20:26 +00:00
|
|
|
if (key == ' ' || key == PK_DEL || key == PK_ESC || key == PK_RET || key == PK_TAB) {
|
2017-02-20 18:55:16 +00:00
|
|
|
buffer.addByte(key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key >= 'a' &&
|
|
|
|
key <= 'z') {
|
|
|
|
if (ctrlPressed) {
|
|
|
|
buffer.addByte(key - 'a' + 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (leftShiftPressed || rightShiftPressed || capsLock) {
|
|
|
|
buffer.addByte(key - 'a' + 'A');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
buffer.addByte(key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: can we control-shift?
|
|
|
|
if (key >= ',' && key <= ';') {
|
|
|
|
if (leftShiftPressed || rightShiftPressed) {
|
|
|
|
buffer.addByte(shiftedNumber[key - ',']);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
buffer.addByte(key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
buffer.addByte(ret);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Everything else falls through.
|
|
|
|
buffer.addByte(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TeensyKeyboard::kbhit()
|
|
|
|
{
|
|
|
|
if (keypad.getKeys()) {
|
|
|
|
for (int i=0; i<LIST_MAX; i++) {
|
|
|
|
if ( keypad.key[i].stateChanged ) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For debugging: also allow USB serial to act as a keyboard
|
2020-07-04 11:41:32 +00:00
|
|
|
if (serialavailable()) {
|
|
|
|
buffer.addByte(serialgetch());
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return buffer.hasData();
|
|
|
|
}
|
|
|
|
|
|
|
|
int8_t TeensyKeyboard::read()
|
|
|
|
{
|
|
|
|
if (buffer.hasData()) {
|
|
|
|
return buffer.consumeByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a non-buffered interface to the physical keyboard, as used
|
|
|
|
// by the VM.
|
|
|
|
void TeensyKeyboard::maintainKeyboard()
|
|
|
|
{
|
|
|
|
if (keypad.getKeys()) {
|
|
|
|
for (int i=0; i<LIST_MAX; i++) {
|
|
|
|
if ( keypad.key[i].stateChanged ) {
|
|
|
|
switch (keypad.key[i].kstate) {
|
|
|
|
case PRESSED:
|
|
|
|
vmkeyboard->keyDepressed(keypad.key[i].kchar);
|
|
|
|
break;
|
|
|
|
case RELEASED:
|
|
|
|
vmkeyboard->keyReleased(keypad.key[i].kchar);
|
|
|
|
break;
|
|
|
|
case HOLD:
|
|
|
|
case IDLE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-26 16:00:41 +00:00
|
|
|
|
|
|
|
// For debugging: also allow USB serial to act as a keyboard
|
2020-07-04 11:41:32 +00:00
|
|
|
if (serialavailable()) {
|
|
|
|
int c = serialgetch();
|
2017-02-26 16:00:41 +00:00
|
|
|
vmkeyboard->keyDepressed(c);
|
|
|
|
vmkeyboard->keyReleased(c);
|
|
|
|
}
|
2017-02-20 18:55:16 +00:00
|
|
|
}
|