-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsketch_buttonkeys.ino
146 lines (132 loc) · 5.62 KB
/
sketch_buttonkeys.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <Wire.h>
#include <Keyboard.h>
//Set this to 1 to test using the serial monitor
#define debug 0
//This is the address range of the expander
#define PCA9555_Start 0x20 // address for PCA9555
#define PCA9555_End 0x23
//Stores the previous key state
int prevState[8][2] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}};
//This is the key to send to computer. Might change this to string later so that we can send a string of keystrokes.
//Each expander has two ports of eight bits. I do maths to figure out which pin was activited and then use this
//to determine what to send.
char charMap[8][16] = {{'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'},
{'\0','\0','\0','\0','L','\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','\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','\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'},
{'\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','\0','\0','\0','\0','\0','\0','\0'}};
//This is a table to determine the behavior of the button. M presses the key as long as it is held down just
//like a keyboard. So far we only have M for momentary. Other behaviors will be added later.
char keyType[8][16] = {{'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'},
{'\0','\0','\0','\0','M','\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','\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','\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'},
{'\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','\0','\0','\0','\0','\0','\0','\0'}};
void setup()
{
//We can use the serial monitor to figure out what expander and pin the button is pluggest into in
//debug mode
if (debug) {
Serial.begin(9600);
}
//Each expander as a unique address that it is set to
for (int i=PCA9555_Start; i<=PCA9555_End ;i++)
{
Wire.begin(i);
}
//Arduino Leondardos can act like HID devices and we can send keystrokes
Keyboard.begin();
}
void loop()
{
unsigned char key;
//Read forever. Eventually there will be an hardware interrupt driven version of this where reads only occur when
//there is a pin state change. That will leave us time to do other things instead of just frantically checking for data
key=readdata();
}
unsigned char readdata(void) //main read function
{
for (int i=PCA9555_Start ;i<=PCA9555_End ;i++) //for loop
{
//Each Expander has two ports
for (int p=0;p<2;p++) {
gpio_read(i,p);
}
}
}
unsigned int gpio_read(int address, int port)
{
int data = 0;
Wire.beginTransmission(address);
Wire.write(port);
Wire.endTransmission();
Wire.beginTransmission(address);
//Read one byte from port on expander with address
Wire.requestFrom(address, 1);
if (Wire.available())
{
data = Wire.read( );
}
Wire.endTransmission();
//The data comes across as bits in a byte. We check for a change from the previous state. If there is a change
//we do stuff. We use bitwise logic to figure what bits have been set or unset. Unset is a keydown event. Set is a keyup event.
if (prevState[address - PCA9555_Start][port] != data) {
int changed = prevState[address - PCA9555_Start][port] ^ data;
int bitNum = 0;
bool down = false;
for (int bit=1;bit<=128;bit=bit * 2) {
if (byte(bit & changed) != 0x00) {
//We figure out where in the table this bit maps to to figure out the key and behavior.
//It should be pretty efficient.
int row = address - PCA9555_Start;
int col = (bitNum) + (8 * port);
if (byte(bit & data) == 0x00) {
down = true;
}
else {
down = false;
}
keySend(down, row, col);
}
bitNum++;
}
prevState[address - PCA9555_Start][port] = data;
}
return data;
}
void keySend(int down, int row, int col) {
char key = charMap[row][col];
char type = keyType[row][col];
//If debug is set we just print out data about this bit to the serial monitor so we can create a mapping in the tables
if (debug){
if (down) {
Serial.print("KeyDown:");
} else {
Serial.print("KeyUp:");
}
Serial.print("row:");
Serial.print(row);
Serial.print(":col:");
Serial.print(col);
Serial.print(":char:");
Serial.println(key);
} else {
switch (type) {
//This should behave like a keyboard key. Press a button is pressed until you release. I may have to look into deboucing
//but I haven't had issues yet.
case 'M':
if (down) {
Keyboard.press(key);
} else {
Keyboard.release(key);
}
break;
}
}
}