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