]> git.gir.st - sendHID.git/blob - main.c
readme: dwc2 gets appended instead of overwriting the whole file
[sendHID.git] / main.c
1 /*
2 description: sends a sequence of keystrokes provided from stdin to the hid
3 device.
4 stops typing at: control characters (including newline), chars not in table, EOF
5 parameters:
6 device file (e.g. /dev/hidg0)
7 keyboard layout (1=en_us, 2=de_at, 3=de_at-nodeadkeys)
8 unicode method: 1=gtk_holddown, 2=gtk_spaceend, 3=windows
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include "scancodes.h"
14
15 #define TEXT_LEN 256 //max length of piped text
16 enum params {//argv-indices:
17 P_EXE, //executable name
18 P_DEV, //device file
19 P_LAY, //layout
20 P_UNI, //unicode method
21 NUM_P //number of parameters
22 };
23 enum uni_m {//unicode methods:
24 SKIP, //ignore any keys not on the layout
25 GTK_HOLD, //hold ctrl and shift while entering hex values
26 GTK_SPACE, //end hex sequence with spacebar
27 WINDOWS //use alt+numpad
28 };
29 enum errors {
30 ERR_SUCCESS, //no error
31 ERR_ARGCOUNT, //wrong number of arguments
32 ERR_SYMBOL, //symbol not in look up table
33 ERR_LAYOUT, //parameter P_LAY does not contain a correct keyboard layout
34 ERR_LAZY //i haven't done this
35 };
36
37 void send_key (FILE* hid_dev, unsigned short key, unsigned short mod);
38 enum errors send_unicode (FILE* hid_dev, unsigned int unicode, enum uni_m method, enum kbdl layout);
39
40 int main (int argc, char** argv) {
41 if (argc != NUM_P) {
42 fprintf (stderr, "Usage: %s <device file> <layout> <unicode>\n", argv[P_EXE]);
43 fprintf (stderr, "Takes string to type from stdin\n");
44 fprintf (stderr, "<device file>:\ton the Raspberry Pi usually /dev/hidg0\n");
45 fprintf (stderr, "<layout>:\n\t%d\t%s\n\t%d\t%s\n\t%d\t%s\n",
46 en_US, "en_US",
47 de_AT, "de_AT (w/ dead keys)",
48 de_ND, "de_AT-nodeadkeys");
49 fprintf (stderr, "<unicode>:\n\t%d\t%s\n\t%d\t%s\n\t%d\t%s\n\t%d\t%s\n",
50 SKIP, "skip over unicode characters",
51 GTK_HOLD, "X11 Holddown: CTRL+SHIFT+[u, hex]",
52 GTK_SPACE, "X11 Space: CTRL+SHIFT+u, hex, SPACE",
53 WINDOWS, "Windows: Alt+[Numpad]");
54 return ERR_ARGCOUNT;
55 }
56 FILE* hid_dev = fopen ("/dev/hidg0", "w");
57 char in_string[TEXT_LEN];
58 fgets(in_string, TEXT_LEN, stdin);
59 for (int i = 0; i < strlen (in_string); i++) {
60 if (in_string[i] < 32) {
61 if (in_string[i] != '\n') fprintf (stderr, "Cannot print control characters!\n(Is there a newline at the end of your string?\n");
62 return ERR_SYMBOL;
63 }
64
65 char tmp[UTF8_MAX_LENGTH] = {in_string[i], in_string[i+1], in_string[i+2], '\0'};
66 //TODO: replace by something less stupid
67 if (in_string[i] < 128) { // not multi byte
68 tmp[1] = '\0';
69 } else { // is multi byte
70 if (in_string[i] < 0xe0) {
71 i++; //skip next thing
72 tmp[2] = 0;
73 } else {
74 i+=2; //WARN: fails on utf8 > 3 byte
75 }
76 }
77
78 struct keysym* s = toscan (tmp);
79 if (s == NULL) {
80 fprintf (stderr, "Key Symbol not found.\n");
81 fclose (hid_dev);
82 return ERR_SYMBOL;
83 }
84 struct layout* l = tolay (s, atoi (argv[P_LAY]));
85 if (l == NULL) {
86 fprintf (stderr, "Unrecognised keyboard layout.\n");
87 fclose (hid_dev);
88 return ERR_LAYOUT;
89 }
90 if (l->key != 0x00) {
91 send_key(hid_dev, l->key, l->mod);
92 send_key(hid_dev, '\0', '\0'); //release all keys
93 if (l->is_dead) {
94 //dead keys need to be pressed twice to show up
95 send_key(hid_dev, l->key, l->mod);
96 send_key(hid_dev, '\0', '\0'); //release all keys
97 }
98 } else {
99 //key does not exist in this layout, use unicode method
100 //fprintf (stderr, "Warning: Key '%s'(0x%x) not in this layout!\n", s->sym, s->unicode);
101 send_unicode (hid_dev, s->unicode, atoi (argv[P_UNI]), atoi(argv[P_LAY]));
102 }
103 }
104 fclose (hid_dev);
105
106 return ERR_SUCCESS;
107 }
108
109 void send_key (FILE* hid_dev, unsigned short key, unsigned short mod) {
110 fprintf (hid_dev, "%c%c%c%c%c%c%c%c", mod, '\0', key, '\0', '\0', '\0', '\0', '\0');
111 }
112
113 enum errors send_unicode (FILE* hid_dev, unsigned int unicode, enum uni_m method, enum kbdl layout) {
114 char buf[10];
115 struct keysym* s;
116 struct layout* l;
117
118 if (unicode == 0x00) {
119 fprintf (stderr, "Symbol not in lookup table!\n");
120 return ERR_SYMBOL;
121 }
122
123 switch (method) {
124 case SKIP:
125 break;
126 case GTK_HOLD:
127 sprintf (buf, "%x", unicode);
128 s = toscan ("u");
129 l = tolay (s, layout);
130 send_key (hid_dev, l->key, MOD_LCTRL | MOD_LSHIFT);
131 for (int i = 0; i < strlen (buf); i++) {
132 s = toscan ((char[2]){buf[i], '\0'});
133 l = tolay (s, layout);
134 send_key (hid_dev, l->key, MOD_LCTRL | MOD_LSHIFT);
135 }
136 send_key (hid_dev, '\0', '\0');
137 break;
138 case GTK_SPACE:
139 sprintf (buf, "%x ", unicode);
140 s = toscan ("u");
141 l = tolay (s, layout);
142 send_key (hid_dev, l->key, MOD_LCTRL | MOD_LSHIFT);
143 for (int i = 0; i < strlen (buf); i++) {
144 s = toscan ((char[2]){buf[i], '\0'});
145 l = tolay (s, layout);
146 send_key (hid_dev, l->key, MOD_NONE);
147 }
148 send_key (hid_dev, '\0', '\0');
149 break;
150 case WINDOWS:
151 fprintf (stderr, "windows method not implemented!\n");
152 return ERR_LAZY;
153 default:
154 fprintf (stderr, "unknown unicode method!\n");
155 return ERR_LAYOUT; //TODO: better error code
156 }
157 return ERR_SUCCESS;
158 }
Imprint / Impressum