I'm trying to write a piece of code that will mimic ASCII keyboard output. It uses the keyboard library from pjrc, but the application I'm working on requires outputting string sequences rather than individual keys (the C++ interface exposes Keyboard.print
, which does exactly what I want, except that I'm trying to stick to C for learning purposes).
Here's a kick at it;
[snip]
#include <string.h>
#include "usb_keyboard.h" // definitions for the /KEY_\w+/ symbols
int key_from_char(char c){
if (c >= 'a' && c <= 'z') return c + KEY_A - 'a';
if (c >= 'A' && c <= 'Z') return c + KEY_A - 'A';
if (c >= '1' && c <= '9') return c + KEY_A - '1';
if (c == '0') return 39; // 0 is low in ASCII, high in the USB key definition
// there's no easy mapping between the other ASCII characters and
// USB keyboard keys, so these are all manually represented
switch (c) {
case ' ': return KEY_SPACE; break;
case '!': return KEY_1; break;
case '"': return KEY_QUOTE; break;
case '#': return KEY_NUMBER; break;
case '$': return KEY_4; break;
case '%': return KEY_5; break;
case '&': return KEY_7; break;
case '\'': return KEY_QUOTE; break;
case '(': return KEY_9; break;
case ')': return KEY_0; break;
case '*': return KEYPAD_ASTERIX; break;
case '+': return KEYPAD_PLUS; break;
case ',': return KEY_COMMA; break;
case '-': return KEYPAD_MINUS; break;
case '.': return KEY_PERIOD; break;
case '/': return KEYPAD_SLASH; break;
case ':': return KEY_SEMICOLON; break;
case ';': return KEY_SEMICOLON; break;
case '<': return KEY_COMMA; break;
case '=': return KEY_EQUAL; break;
case '>': return KEY_PERIOD; break;
case '?': return KEY_SLASH; break;
case '@': return KEY_2; break;
case '[': return KEY_LEFT_BRACE; break;
case '\\': return KEY_BACKSLASH; break;
case ']': return KEY_RIGHT_BRACE; break;
case '^': return KEY_6; break;
case '_': return KEY_MINUS; break;
case '`': return KEY_TILDE; break;
case '{': return KEY_LEFT_BRACE; break;
case '|': return KEY_BACKSLASH; break;
case '}': return KEY_RIGHT_BRACE; break;
case '~': return KEY_TILDE; break;
default: return 0;
}
}
int modifier_from_char(char c){
if ((c >= 'A' && c <= 'Z') ||
// not sure how useful it is to put chars instead of ints for the rest of these
c == '!' || c == '"' ||
(c >= '$' && c <= '&') ||
c == '(' || c == ')' ||
c == ':' || c == '<' ||
(c >= '>' && c <= '@') ||
c == '^' || c == '_' ||
(c >= '{' && c <= '~')) return KEY_SHIFT;
return 0;
}
int8_t usb_keyboard_print(char *s){
int s_len = strlen(s);
int i;
for(i = 0; i < s_len; i++){
usb_keyboard_press(key_from_char(s[i]), modifier_from_char(s[i]));
}
}
It seems to work, when I do
int main(void) {
...
usb_keyboard_print("abcdABCD1234!@#$%^&*()_+|~{}:\">?<-=\\`[];',./");
...
}
the character sequence
abcdABCD1234!@\$%^&*()_+|~{}:">?<-=\`[];',./
is output as if by keyboard.
All comments welcome, but I also have specific points/questions
- It seems like there should be an easier way to do this. I mention above that the C++ version of the
usb_keyboard
library provides aKeyboard.print
which does essentially the same thing, but I haven't found anything similar for plain C. - Are there any issues I'm missing about USB key codes that would make this code wonk out based on nationality settings? How would you go about internationalizing it?
- This is basically the first C code I've written since getting out of high-school, so please point out style errors and inefficiencies with extreme prejudice.