I have a set of buttons wired to an arduino leonardo that are meant to send either single keystrokes to a computer "a, b, c..." etc, or a key sequence like ctrl+z (to perform an undo command.) Effectively this is a little usb keyboard with pre defined buttons. The way the struct is now, I can only manage to send one keystroke, never a modifier key+letter like I need.
The full code is listed here under "working code": Arduino sending keystrokes via push-buttons. Proper bouncing and manually setting buttons?
It just debounces the buttons and sends back actions (just single letters right now) using the ones defined in the struct. (thanks very much jwpat7)
The part in question is this
struct ButtonStruct buttons[nSwitches] = {
{0, sw0, 'A'},
{0, sw1, 'B'},
{0, sw2, 'C'},
{0, sw3, 'D'},
{0, sw4, 'E'},
{0, sw5, 'F'},
{0, sw6, 'G'},
{0, sw7, 'H'}};
I effectively want to replace the 'A' in {0, sw0, 'A'} to something that sends ctrl+z keystroke/keysequence instead of the letter 'A'.
I've tried KEY_LEFT_CTRL, setting a variable like char ctrlKey = KEY_LEFT_CTRL; and trying {0, sw0, ctrlKey, 'z'}, the "substitution" hex here: http://www.nthelp.com/ascii.htm and a number of other things.
I've read through a lot and I can't seem to find anything relevant. I've been told it's possible to use pointers to create a key-sequence but a -> operand in there just throws errors. I'm new and I realize I might have a core principal wrong, but isn't there some simple syntax to send a ctrl+z command (and then releasing it obviously) using that space? When I put {0, sw0, KEY_LEFT_CTRL, 'z'} it just reports "Lz", using the last letter in KEY_LEFT_CTRL instead of treating it as a modifier. I'm so confused
(Also right now one press = one character and doesn't continually report like holding down a key on a regular keyboard. I'd like to fix that too but I'd settle for just a bloody ctrl+z at this point.)
EDIT: Current Code (compiled!)
enum { sw0=2, sw1=3, sw2=4, sw3=5, sw4=6, sw5=7, sw6=8, sw7=9}; // Switchbutton lines
enum { nSwitches=8, bounceMillis=42}; // # of switches; debounce delay
struct ButtonStruct {
unsigned long int bounceEnd; // Debouncing-flag and end-time
// Switch number, press-action, release-action, and prev reading
byte swiNum, swiActP, charMod, swiActR, swiPrev;
};
struct ButtonStruct buttons[nSwitches] = {
{0, sw0, 'z', KEY_LEFT_CTRL},
{0, sw1, 'B'},
{0, sw2, 'C'},
{0, sw3, 'D'},
{0, sw4, 'E'},
{0, sw5, 'F'},
{0, sw6, 'G'},
{0, sw7, 'H'}};
//--------------------------------------------------------
void setup() {
for (int i=0; i<nSwitches; ++i)
pinMode(buttons[i].swiNum, INPUT_PULLUP);
Keyboard.begin();
}
//--------------------------------------------------------
byte readSwitch (byte swiNum) {
// Following inverts the pin reading (assumes pulldown = pressed)
return 1 - digitalRead(swiNum);
}
//--------------------------------------------------------
void doAction(byte swin, char code, char tosend, char chmodi) {
if (chmodi) { // See if modifier needed
Keyboard.press(chmodi);
Keyboard.press(tosend);
delay(100);
Keyboard.releaseAll();
} else {
Keyboard.write(tosend);
}
}
//--------------------------------------------------------
void doButton(byte bn) {
struct ButtonStruct *b = buttons + bn;
if (b->bounceEnd) { // Was button changing?
// It was changing, see if debounce time is done.
if (b->bounceEnd < millis()) {
b->bounceEnd = 0; // Debounce time is done, so clear flag
// See if the change was real, or a glitch
if (readSwitch(b->swiNum) == b->swiPrev) {
// Current reading is same as trigger reading, so do it
if (b->swiPrev) {
doAction(b->swiNum, 'P', b->swiActP, b->charMod);
}
}
}
} else { // It wasn't changing; but see if it's changing now
if (b->swiPrev != readSwitch(b->swiNum)) {
b->swiPrev = readSwitch(b->swiNum);
b->bounceEnd = millis()+bounceMillis; // Set the Debounce flag
}
}
}
//--------------------------------------------------------
long int seconds, prevSec=0;
void loop() {
for (int i=0; i<nSwitches; ++i)
doButton(i);
}
swiActR
take it out of the struct. In current code,{sw0, 'R', KEY_LEFT_CTRL}
inits bounceEnd equal to sw0, swiNum to R, and swiActP to KEY_LEFT_CTRL. Initializers have to be in the right order, ie have to match the order declared in struct. Values can be left off at the end, to default to 0, but can't be left off the frontchar action, char chmodi
tochar tosend, char chmodi
and delete the two lines with b-> at front. In doButton add b->charMod to the first doAction call. Deleteelse { doAction(b->swiNum, 'R', b->swiActR);
if you don't plan to do an action for button releases, else perhaps fix the code up with a modifier for the release action char. Just make the function calls and function defs match up, only use vars that are in scope, etc