#include <Keypad.h>
#define multi_tap_threshold 1000
#define RESET_MTP '~'
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
int pointer;
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {1,15,2,4}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {16,17,5,18}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup(){
Serial.begin(9600);
}
void loop()
{
int mtKey=0;
byte key=keypad.getKey(); // Get a key press from the keypad
mtKey=multi_tap(key); // Feed the key press to the multi_tap function.
if(!(mtKey&B10000000)) Serial.print(mtKey);
}
int multi_tap(byte key)
{
static boolean upperCase=true;
static byte prevKeyPress=NO_KEY,cyclicPtr=0;
static unsigned long prevKeyMillis=0;
static const char multi_tap_mapping[10][5]={{'0','#','.','?'},{'1','+','-','^','/'},{'A','B','C','2','!'},{'D','E','F','3','%'},{'G','H','I','4','('},{'J','K','L','5',')'},{'M','N','O','6','@'},{'P','Q','R','S','7'},{'T','U','V','8',','},{'W','X','Y','Z','9'}};
if (key==RESET_MTP) // Received reset command. Flush everything and get ready for restart.
{
upperCase=true;
prevKeyPress=NO_KEY;
cyclicPtr=0;
return 0;
}
if (key!=NO_KEY) // A key is pressed at this iteration.
{
if ((key>'9')||(key<'0')) // Function keys
{
if ((key==1)||(key=='#')) // Up for case change
{
upperCase=!upperCase;
return 0;
}
else // Other function keys. These keys produce characters so they need to terminate the last keypress.
{
if (prevKeyPress!=NO_KEY)
{
char temp1=multi_tap_mapping[prevKeyPress-'0'][cyclicPtr];
if ((!upperCase)&&(temp1>='A')&&(temp1<='Z')) temp1+='a'-'A';
cyclicPtr=0;
prevKeyMillis=0;
switch (key)
{
case 2:
// Call symbol list
return 0; // Clear the buffer.
break;
case 3:
prevKeyPress='\b';
break;
case 4:
case '^':
prevKeyPress=' ';
break;
case 5:
prevKeyPress='\n';
break;
case 6:
prevKeyPress=NO_KEY; // Clear the buffer.
break;
}
return(256+(unsigned int)(temp1));
}
else
{
prevKeyPress=NO_KEY;
cyclicPtr=0;
prevKeyMillis=0;
switch (key)
{
case 2:
// Call symbol list
return 0; // Clear the buffer.
break;
case 3:
return (256+(unsigned int)('\b'));
break;
case 4:
return (256+(unsigned int)(' '));
break;
case 5:
return (256+(unsigned int)('\n'));
break;
case 6:
return 0; // Clear the buffer.
break;
}
}
}
}
if (prevKeyPress!=NO_KEY)
{
if (prevKeyPress==key)
{
char temp1;
cyclicPtr++;
if ((multi_tap_mapping[key-'0'][cyclicPtr]==0)||(cyclicPtr==5)) cyclicPtr=0; //Cycle key
prevKeyMillis=millis();
temp1=multi_tap_mapping[key-'0'][cyclicPtr];
if ((!upperCase)&&(temp1>='A')&&(temp1<='Z')) temp1+='a'-'A';
return ((unsigned int)(temp1));
}
else
{
char temp1=multi_tap_mapping[prevKeyPress-'0'][cyclicPtr];
if ((!upperCase)&&(temp1>='A')&&(temp1<='Z')) temp1+='a'-'A';
prevKeyPress=key;
cyclicPtr=0;
prevKeyMillis=millis();
//Print key on cursor+1
return(256+(unsigned int)(temp1));
}
}
else
{
char temp1=multi_tap_mapping[key-'0'][cyclicPtr];
if ((!upperCase)&&(temp1>='A')&&(temp1<='Z')) temp1+='a'-'A';
prevKeyPress=key;
prevKeyMillis=millis();
cyclicPtr=0;
return ((unsigned int)(temp1));
}
}
else // No key is pressed at this iteration.
{
if (prevKeyPress==NO_KEY) return 0; // No key was previously pressed.
else if (millis()-prevKeyMillis<multi_tap_threshold) // Key was pressed previously but within threshold
{
char temp1=multi_tap_mapping[prevKeyPress-'0'][cyclicPtr];
if ((!upperCase)&&(temp1>='A')&&(temp1<='Z')) temp1+='a'-'A';
return((unsigned int)(temp1));
}
else // Key was pressed previously and threshold has passed
{
char temp1=multi_tap_mapping[prevKeyPress-'0'][cyclicPtr];
if ((!upperCase)&&(temp1>='A')&&(temp1<='Z')) temp1+='a'-'A';
prevKeyPress=NO_KEY;
cyclicPtr=0;
return(256+(unsigned int)(temp1));
}
}
return 0;
}