Keyboard Printing with Teensy 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 &lt;string.h&gt;
#include "usb_keyboard.h" // definitions for the /KEY_\w+/ symbols

int key_from_char(char c){
  if (c &gt;= 'a' &amp;&amp; c &lt;= 'z') return c + KEY_A - 'a';
  if (c &gt;= 'A' &amp;&amp; c &lt;= 'Z') return c + KEY_A - 'A';
  if (c &gt;= '1' &amp;&amp; c &lt;= '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 '&amp;': 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 '&lt;': return KEY_COMMA; break;
  case '=': return KEY_EQUAL; break;
  case '&gt;': 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 &gt;= 'A' &amp;&amp; c &lt;= 'Z') ||
      // not sure how useful it is to put chars instead of ints for the rest of these
      c == '!' || c == '"' ||
      (c &gt;= '$' &amp;&amp; c &lt;= '&amp;') ||
      c == '(' || c == ')' ||
      c == ':' || c == '&lt;' ||
      (c &gt;= '&gt;' &amp;&amp; c &lt;= '@') ||
      c == '^' || c == '_' ||
      (c &gt;= '{' &amp;&amp; c &lt;= '~')) return KEY_SHIFT;

  return 0;
}

int8_t usb_keyboard_print(char *s){
  int s_len = strlen(s);
  int i;

  for(i = 0; i &lt; 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!@#$%^&amp;*()_+|~{}:\"&gt;?&lt;-=\\`[];',./");
   ...
}


the character sequence

abcdABCD1234!@\$%^&amp;*()_+|~{}:"&gt;?&lt;-=\`[];',./


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 a Keyboard.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.
Don't subtract absolute values:

    if (c &gt;= 'a' &amp;&amp; c &lt;= 'z') return c - 93;


It makes it hard to understand what you are doing when you subtract integer literals from character codes. I would normally expect some form of value that conveys some meaning. For example lets assume ASCII (You probably want your keyboard thing but I don't know the appropriate macro).

 if (c &gt;= 'a' &amp;&amp; c &lt;= 'z') return c + 3 - 'a';  // For some reason you want 'a' to map to 3
                                                // If we assume ASCII 'a' =&gt; 96 


 if (c &gt;= 'A' &amp;&amp; c &lt;= 'Z') return c + 4 - 'A';  // For some reason you want 'A' to map to 4
                                                // If we assume ASCII 'A' =&gt; 65


Either you have some other requirement that is not ASCII (very possible), you want 'a'/'A' to map to some non zero number or you have a bug. But it is hard to tell with the way you have written your code as the literal values 93 and 61 have no real meaning.