Hi! I'm working on a project where I will have button matrix with windows shortcuts assigned to it. I have nearly finished code but I don't know how to add long presses of said shortcuts(for example I want to hold alt tab to choose window and don't be bothered of shortcut relasing before I get what I want). I would really love some fedback and here is my code.
#include <Keyboard.h>
#include <Keypad.h>
const byte ROWS = 4;
const byte COLS = 6;
char keys[ROWS][COLS] = {
{'a', 'b', 'c', 'd', 'e', 'f'},
{'g', 'h', 'i', 'j', 'k', 'l'},
{'m', 'n', 'o', 'p', 'q', 'r'},
{'s', 't', 'u', 'v', 'w', 'x'},
};
byte rowPins[ROWS] = {8, 9, 10, 11};
byte colPins[COLS] = {2, 3, 4, 5, 6, 7};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup() {
Keyboard.begin();
}
void loop() {
char key = keypad.getKey();
if (key) {
switch (key) {
case 'a':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('c');
break;
case 'b':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('x');
break;
case 'c':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('v');
break;
case 'd':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('a');
break;
case 'e':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('z');
break;
case 'f':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('y');
break;
case 'g':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('t');
break;
case 'h':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('d');
break;
case 'i':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(KEY_HOME);
break;
case 'j': //I need it here
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(',');
break;
case 'k': //and here
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press(KEY_TAB);
break;
case 'l':
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press(KEY_ESC);
break;
case 'm':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(KEY_TAB);
break;
case 'n':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('d');
break;
case 'o':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_ARROW);
break;
case 'p':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_RIGHT_ARROW);
break;
case 'q':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_F4);
break;
case 'r':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('e');
break;
case 's':
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press(KEY_F4);
break;
case 't':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('l');
break;
case 'u':
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press(KEY_DELETE);
break;
case 'v':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('r');
break;
case 'w':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('i');
break;
case 'x':
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('a');
break;
}
delay(100);
Keyboard.releaseAll();
}
}
See the Keypad library "MultiKey" example. Use keypad.getKeys() to get a list of currently active keys. For keys that are "PRESSED" you need to note a start time associated with that key. If the state is "HOLD" and the timer has expired, you have a long press. If the key goes "RELEASED" before the timer expires, you have a short press.
The key state will stay at "HOLD" until you release it so when you act on a long press, make sure you mark that key somehow so you know not to act on the long press again. I would set the start time to 0 to indicate that the long press has been handled and the timer is no longer running.
Okay I'll check it out but I have one more question. I want to add more keys to it so I bought two PCF8574T 8pin expanders(I2C). I assume that I need to create separate 4x4 keypad matrixes on them? Also some people are saying that I need pull up resistors on SDA and SCL lines(10k ohm) and some are saying that I don't need them so what should I do?
Yankiel:
I want to add more keys to it so I bought two PCF8574T 8pin expanders(I2C). I assume that I need to create separate 4x4 keypad matrixes on them?
The Keypad library supports up to 16 columns and, by default, up to 10 rows. It does not support port expanders so you will have to find another library for that.
Yankiel:
Also some people are saying that I need pull up resistors on SDA and SCL lines(10k ohm) and some are saying that I don't need them so what should I do?
I think the Wire library uses the internal pull-up resistors. Try without and if it doesn't work, try with.
So I checked MultiKey example and worked out how to implement Keyboard.press for all letters on keypad but I have no idea how to assign each letter with it's corresponding shortcut now 
#include <Keypad.h>
#include <Keyboard.h>
const byte ROWS = 4;
const byte COLS = 6;
char keys[ROWS][COLS] = {
{'a', 'b', 'c', 'd', 'e', 'f'},
{'g', 'h', 'i', 'j', 'k', 'l'},
{'m', 'n', 'o', 'p', 'q', 'r'},
{'s', 't', 'u', 'v', 'w', 'x'},
};
byte rowPins[ROWS] = {8, 9, 10, 11};
byte colPins[COLS] = {2, 3, 4, 5, 6, 7};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
unsigned long loopCount;
unsigned long startTime;
String msg;
void setup() {
Keyboard.begin();
Serial.begin(9600);
loopCount = 0;
startTime = millis();
msg = "";
}
void loop() {
loopCount++;
if ( (millis()-startTime)>500 ) {
startTime = millis();
loopCount = 0;
}
if (keypad.getKeys())
{
for (int i=0; i<LIST_MAX; i++)
{
if ( keypad.key[i].stateChanged )
{
switch (keypad.key[i].kstate) {
case PRESSED:
msg = " PRESSED.";
Keyboard.press(keypad.key[i].kchar);
break;
case HOLD:
Keyboard.press(keypad.key[i].kchar);
break;
case RELEASED:
Keyboard.releaseAll();
break;
case IDLE:
msg = " IDLE.";
}
Serial.print("Key ");
Serial.print(keypad.key[i].kchar);
Serial.println(msg);
}
}
}
}
Yankiel:
So I checked MultiKey example and worked out how to implement Keyboard.press for all letters on keypad but I have no idea how to assign each letter with it's corresponding shortcut now.
Normally you would put it in the "PRESSED" case. Because you want a long press to do something different from a short press, you have to add code like I described in reply #1:
johnwasser:
For keys that are "PRESSED" you need to note a start time associated with that key. If the state is "HOLD" and the timer has expired, you have a long press. If the key goes "RELEASED" before the timer expires, you have a short press.
The key state will stay at "HOLD" until you release it so when you act on a long press, make sure you mark that key somehow so you know not to act on the long press again. I would set the start time to 0 to indicate that the long press has been handled and the timer is no longer running.
I recommend you start with an array of unsigned long timer values you can associate with each key. Luckily for you, each key has a 'kcode' value which is an index into the kchar list.
Oh, and get rid of this line:
if ( keypad.key[i].stateChanged)
You need to check the timer on keys in the "HOLD" state even if no states have changed.
johnwasser:
Normally you would put it in the "PRESSED" case. Because you want a long press to do something different from a short press, you have to add code like I described in reply #1
No i want it to do exactly the same thing but for longer time. Like for example one button is assigned to alt+f4 and other to alt+tab. Normally you just push alt+f4 and release instantly to close window but you can press and release or hold alt+tab to choose between different windows. I have 4x6 matrix so that are 24 different shortcuts. I want them to be assigned to their corresponding buttons and each button will do the same thing on press and hold but momentarily or for time I'm pressing that button respectively.
Oh! That's different. Usually when people talk about a "long press" they want the button to do something DIFFERENT when held down for a specified period.
The length of your key presses was controlled by:
delay(100);
Keyboard.releaseAll();
To keep the keys down until you release the button, send the 'Keyboard.press(keycode)' when the button is PRESSED and send the corresponding 'Keyboard.release(keycode)' when the button is RELEASED. if you want to simplify, you can send .releaseAll() when any key is released. The trick is to NOT send .releaseAll() until the button is RELEASED.