added a Makefile to use it as a C library. no python dependencies. added 2 example...
[rofl0r-libxauto.git] / src / xaut_keyboard.c
blob33aa4309f9d300b2237593f772da38bcab4b4827
1 /***************************************************************************
2 * Copyright (C) 2009 by Chris Parker *
3 * chrsprkr3@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the Python License version 2.5 or later. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
11 ***************************************************************************/
14 $URL$
15 $Author$
16 $Date$
17 $Rev$
20 #include "xaut_keyboard.h"
22 short key_down_delay(short delay) {
23 if (!_check_init()) {
24 return 0;
26 if(delay < 0) {
27 logit(LOG_LEVEL_VERBOSE, "Leaving key down delay at %hu\n",
28 defaults->key_down_delay);
29 return defaults->key_down_delay;
31 logit(LOG_LEVEL_EXTRA_VERBOSE,
32 "Keys used to stay down %hu milliseconds when clicked\n",
33 defaults->key_down_delay);
34 defaults->key_down_delay = delay;
35 logit(LOG_LEVEL_EXTRA_VERBOSE,
36 "Keys now stay down %hu milliseconds when clicked\n",
37 defaults->key_down_delay);
38 return defaults->key_down_delay;
41 short key_click_delay(short delay) {
42 if (!_check_init()) {
43 return 0;
45 if(delay < 0) {
46 logit(LOG_LEVEL_VERBOSE, "Leaving key down delay at %hu\n",
47 defaults->key_click_delay);
48 return defaults->key_click_delay;
50 logit(LOG_LEVEL_EXTRA_VERBOSE,
51 "Keys used to wait %hu milliseconds between clicks\n",
52 defaults->key_click_delay);
54 defaults->key_click_delay = delay;
55 logit(LOG_LEVEL_EXTRA_VERBOSE,
56 "Keys now wait %hu milliseconds between clicks\n",
57 defaults->key_click_delay);
58 return defaults->key_click_delay;
61 BOOL key_click(unsigned int key) {
62 if (!_check_init()) {
63 return FALSE;
65 int success = key_down(key);
66 if (success) {
67 usleep(MILLI_MULTIPLIER * defaults->key_down_delay);
68 success = key_up(key);
70 return success;
73 BOOL key_down(unsigned int key) {
74 if (!_check_init()) {
75 return FALSE;
78 int success = XTestFakeKeyEvent(defaults->display, key, TRUE, CurrentTime);
79 XFlush(defaults->display);
80 if (success) {
81 logit(LOG_LEVEL_EXTRA_VERBOSE, "Pressed %d ", key);
82 } else {
83 fprintf(stderr, "Failure to press %d ", key);
85 return (success != 0);
88 BOOL key_up(unsigned int key) {
89 if (!_check_init()) {
90 return FALSE;
92 int release = XTestFakeKeyEvent(defaults->display, key, FALSE, CurrentTime);
93 BOOL success = (release != 0);
94 XFlush(defaults->display);
95 if (success) {
96 logit(LOG_LEVEL_EXTRA_VERBOSE, "Released %d", key);
97 } else {
98 fprintf(stderr, "Failure to release %d\n", key);
100 return (success != 0);
103 void interpret_meta_symbols(BOOL tf) {
104 //"BOOL" is actually a short - so I'm going
105 //to filter the value sent.
107 char *msg = "I was %sinterpreting meta symbols\n";
108 char *yn = defaults->interpret_meta_symbols ? "" : "not ";
109 logit(LOG_LEVEL_EXTRA_VERBOSE, msg, yn);
111 defaults->interpret_meta_symbols = (tf) ? TRUE : FALSE;
113 char *msg = "Now I will %sinterpret meta symbols\n";
114 char *yn = defaults->interpret_meta_symbols ? "" : "not ";
115 logit(LOG_LEVEL_EXTRA_VERBOSE, msg, yn);
119 void print_keycodes() {
120 if (!_check_init()) {
121 fprintf(stderr, "Unable to print keycodes");
122 return;
124 printf("Code X11 key symbol name string Shift?\n");
125 printf("---- --------------------------------- -------\n");
126 int min, max; //The minumum and maximum codes
127 XDisplayKeycodes(defaults->display, &min, &max);
128 int i;
129 KeySym symL, symU; //Lower and upper symbols
130 char *strL, *strU; //Lower and upper strings
131 char *fmt = "%4d %-33s %-6s\n";
132 for (i = (min - 1); i <= max; i++) {
133 symL = XKeycodeToKeysym(defaults->display, i, FALSE);
134 symU = XKeycodeToKeysym(defaults->display, i, TRUE);
135 if (symL) {
136 strL = XKeysymToString(symL);
138 if (symU) {
139 strU = XKeysymToString(symU);
142 //If both shifted and unshifted have values
143 if (symL && symU) {
144 if (!strcmp(strL, strU)) {
145 //If they're the same
146 printf(fmt, i, strL, "Either");
147 } else {
148 //Otherwise
149 printf(fmt, i, strL, "No");
150 printf(fmt, i, strU, "Yes");
152 } else if (symL) {
153 //Unshifted only (lower case)
154 printf(fmt, i, strL, "No");
155 } else if (symU) {
156 //Shifted only (upper case)
157 printf(fmt, i, strU, "Yes");
162 #ifdef EN_US
163 BOOL type(char *str) {
164 if (!_check_init()) {
165 return FALSE;
167 logit(LOG_LEVEL_VERBOSE, "Sending '%s'\n", str);
168 BOOL success = TRUE;
170 size_t index = 0;
171 int down = 0;
172 int meta[] = { 0, 0, 0, 0 };
173 BOOL shft_pressed = FALSE;
174 BOOL ctl_pressed = FALSE;
175 BOOL alt_pressed = FALSE;
176 BOOL meta_pressed = FALSE;
177 unsigned short key = 0;
178 while (str[index] != '\0') {
179 switch (str[index]) {
180 case ('+'):
181 if(defaults->interpret_meta_symbols) {
182 if (!shft_pressed) {
183 shft_pressed = TRUE;
184 logit(LOG_LEVEL_VERBOSE, "%s", "Shift_L down ");
185 success &= key_down(SHIFT_L);
186 meta[down] = SHIFT_L;
187 down++;
189 break;
191 case ('^'):
192 if(defaults->interpret_meta_symbols) {
193 if (!ctl_pressed) {
194 ctl_pressed = TRUE;
195 logit(LOG_LEVEL_VERBOSE, "%s", "Control_L down ");
196 success &= key_down(CONTROL_L);
197 meta[down] = CONTROL_L;
198 down++;
200 break;
202 case ('!'):
203 if(defaults->interpret_meta_symbols) {
204 if (!alt_pressed) {
205 alt_pressed = TRUE;
206 success &= key_down(ALT_L);
207 logit(LOG_LEVEL_VERBOSE, "%s", "Alt_L down ");
208 meta[down] = ALT_L;
209 down++;
211 break;
213 case ('#'):
214 if(defaults->interpret_meta_symbols) {
215 if (!meta_pressed) {
216 meta_pressed = TRUE;
217 success &= key_down(META_L);
218 logit(LOG_LEVEL_VERBOSE, "%s", "META_L down ");
219 meta[down] = META_L;
220 down++;
222 break;
224 case ('{'):
225 if( defaults->interpret_meta_symbols) {
226 index = _handle_keycode(index, str);
227 if (down > 0) {
228 logit(LOG_LEVEL_VERBOSE, "%s", "Meta keys released ");
230 while (down > 0) {
231 down--;
232 success &= key_up(meta[down]);
233 meta[down] = 0;
235 shft_pressed = FALSE;
236 ctl_pressed = FALSE;
237 alt_pressed = FALSE;
238 logit(LOG_LEVEL_VERBOSE, "%s", "\n");
239 break;
241 default:
242 key = ((unsigned short) (str[index]));
243 if (ascii_codes[key].ascii) {
244 int code = ascii_codes[key].code;
245 if (ascii_codes[key].shifted && !shft_pressed) {
246 shft_pressed = TRUE;
247 logit(LOG_LEVEL_VERBOSE, "Shift_L down ");
248 success &= key_down(SHIFT_L);
249 meta[down] = SHIFT_L;
250 down++;
252 if (str[index] == ' ') {
253 logit(LOG_LEVEL_VERBOSE, "%s", "Typing (space) ");
254 } else if (str[index] == '\t') {
255 logit(LOG_LEVEL_VERBOSE, "%s", "Typing (tab) ");
256 } else {
257 logit(LOG_LEVEL_VERBOSE, "%s", "Typing %c ", str[index]);
259 success &= key_click(code);
260 if (down > 0) {
261 logit(LOG_LEVEL_VERBOSE, "%s", "Meta keys released ");
263 while (down > 0) {
264 down--;
265 success &= key_up(meta[down]);
266 meta[down] = 0;
268 shft_pressed = FALSE;
269 ctl_pressed = FALSE;
270 alt_pressed = FALSE;
271 logit(LOG_LEVEL_VERBOSE, "%s", "\n");
272 XFlush(defaults->display);
274 if (str[index + 1]) {
275 usleep(MILLI_MULTIPLIER * defaults->key_click_delay);
277 } else {
278 fprintf(stderr, "Unable to print %c", str[index]);
280 break;
281 // <- Switch ends
283 index++;
285 return success;
287 #else
288 BOOL type( char *str ) {
289 fprintf( stderr, "No language defined - skipping" );
290 return FALSE;
292 #endif
294 xautpy_meta_t *_extract_metakey(char *input) {
295 size_t i = 1;
296 BOOL space_char_found = FALSE;
297 xautpy_meta_t *meta = malloc(sizeof(xautpy_meta_t));
298 if (meta == NULL) {
299 fprintf(stderr, "Unable to allocate space for metakey");
300 return 0;
302 memset(meta, 0, sizeof(xautpy_meta_t));
303 while (input[i] != '\0') {
304 //First we check to see if there is a space in the string
305 if (input[i] == ' ') {
306 space_char_found = TRUE;
307 break;
309 i++;
311 if (space_char_found) {
312 //Note that i points directly at the space character
313 _extract_metakey_with_count(meta, input, i);
314 } else {
315 meta->name = _stringmid(input, 0, strlen(input));
316 meta->count = 1;
318 if (meta->name) { //Might be empty, since name is allocated
319 meta->keysym = XStringToKeysym(meta->name);
320 if (meta->keysym) {
321 meta->keycode = XKeysymToKeycode(defaults->display, meta->keysym);
322 _extract_metakey_shifted(meta);
325 return meta;
328 void _extract_metakey_shifted(xautpy_meta_t *meta) {
329 //Try no shift key first, since if it doesn't matter
330 // to the code, why worry about it
331 KeySym sym = XKeycodeToKeysym(defaults->display, meta->keycode, FALSE);
332 if (sym == meta->keysym) {
333 meta->shifted = FALSE;
334 } else {
335 sym = XKeycodeToKeysym(defaults->display, meta->keycode, TRUE);
336 if (sym == meta->keysym) {
337 meta->shifted = TRUE;
338 } else {
339 fprintf(stderr, "Something went wrong with keystring %s\n",
340 meta->name);
341 meta->shifted = FALSE;
346 void _extract_metakey_with_count(xautpy_meta_t *meta, char *input,
347 size_t space_index) {
348 //We have to try to extract a string from the left, and
349 // a number from the right.
350 meta->name = _stringmid(input, 0, space_index - 1);
351 char *numStr = _stringmid(input, space_index + 1, strlen(input));
352 int num = atoi(numStr);
353 if (num < 0) {
354 num = 0;
356 meta->count = (unsigned short) num;
357 free(numStr);
360 #ifdef EN_US
361 size_t _handle_keycode(size_t curr, char *str) {
362 size_t index = curr;
363 BOOL closing_brace_found = FALSE;
364 xautpy_meta_t *meta;
365 unsigned short count = 0; //No point in going past 100 characters
366 while (str[index] != '\0' && count < 100) {
367 if (str[index] == '}') {
368 closing_brace_found = TRUE;
369 break;
371 count++;
372 index++;
374 if (closing_brace_found) {
375 //Note: curr points at opening brace {
376 // and index points at closing brace }
377 char *keycode = _stringmid(str, curr + 1, index - 1);
378 meta = _extract_metakey(keycode);
379 free(keycode);
380 } else {
381 fprintf(stderr, "Unable to find closing brace in '%s'\n", str + curr);
382 meta = malloc(sizeof(xautpy_meta_t));
383 if (meta == NULL) {
384 return index;
386 memset(meta, 0, sizeof(xautpy_meta_t));
387 index = curr; //Point index back at opening brace
388 meta->count = 1;
389 meta->keycode = ascii_codes['{'].code;
390 meta->shifted = ascii_codes['{'].shifted;
391 meta->name = _stringmid("{", 0, 1);
393 if (meta && meta->keycode) {
394 unsigned short i;
395 if (meta->shifted) {
396 key_down(SHIFT_L);
397 logit(LOG_LEVEL_VERBOSE, "%s", "Shift_L down ");
399 for (i = 0; i < meta->count; i++) {
400 key_click(meta->keycode);
401 if (meta->keycode == ascii_codes['{'].code) {
402 logit(LOG_LEVEL_VERBOSE, "%s", "Typing { ");
403 } else {
404 logit(LOG_LEVEL_VERBOSE, "Typing metakey %s ", meta->name);
406 if (i + 1 < meta->count) {
407 usleep(MILLI_MULTIPLIER * defaults->key_click_delay);
410 if (meta->shifted) {
411 key_up(SHIFT_L);
412 logit(LOG_LEVEL_VERBOSE, "%s", "Shift_L up ");
415 free(meta->name);
416 free(meta);
417 return index;
419 #else
420 unsigned long _handle_keycode( size_t index, char *str ) {
421 //Skips the remainder if not EN_US
422 while( str[index] != '\0' )
423 index++;
424 return index;
426 #endif