added a Makefile to use it as a C library. no python dependencies. added 2 example...
[rofl0r-libxauto.git] / src / xaut.c
blobca939c2bfa89e51ea0324a662c16182414777da2
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.h"
21 #include <stdarg.h>
23 // --- Published subroutines, functions and structures
25 void cleanup() {
26 if (defaults->display == NULL) {
27 fprintf(stderr, "cleanup: Display is null, no need to release it\n");
28 } else {
29 XFlush(defaults->display);
30 XCloseDisplay(defaults->display);
31 defaults->display = NULL;
33 free(defaults);
34 free(ascii_codes);
35 defaults = NULL;
36 ascii_codes = NULL;
39 void verbose(BOOL verbose) {
40 if (_check_init()) {
41 if(verbose) {
42 defaults->log_level |= LOG_LEVEL_VERBOSE;
43 } else {
44 defaults->log_level &= (! LOG_LEVEL_VERBOSE);
49 void extra_verbose(BOOL extra_verbose) {
50 if (_check_init()) {
51 if(extra_verbose) {
52 defaults->log_level |= LOG_LEVEL_EXTRA_VERBOSE;
53 } else {
54 defaults->log_level &= (! LOG_LEVEL_EXTRA_VERBOSE);
59 void logit(int level, char *msg, ...) {
60 if(defaults->log_level >= level) {
61 va_list args;
62 va_start(args, msg);
63 vfprintf(stderr, msg, args);
64 va_end(args);
68 // --- Unpublished
70 void _add_code(unsigned short code, BOOL shifted) {
71 ascii_codes[code].ascii = (char) code;
72 ascii_codes[code].code = XKeysymToKeycode(defaults->display, code);
73 ascii_codes[code].shifted = shifted;
76 BOOL _check_init() {
77 if (!defaults || !defaults->dsp_width) {
78 _initialize();
80 if (!ascii_codes) {
81 _init_ascii();
83 if (defaults->dsp_width) {
84 return TRUE;
85 } else {
86 fprintf(stderr, "Cannot properly initialize defaults - exiting\n");
87 return FALSE;
91 #ifdef EN_US
92 BOOL _init_ascii() {
93 ascii_codes = malloc(128 * sizeof(xautpy_ascii_t));
94 if (ascii_codes == NULL) {
95 fprintf(stderr, "init: Unable to allocate space for ascii codes");
96 return FALSE;
98 memset(ascii_codes, 0, 128 * sizeof(xautpy_ascii_t));
100 // These are easy - regular letters are ( lower case == uppercase | 32 )
101 unsigned short i;
102 for (i = 'A'; i <= 'Z'; i++) {
103 _add_code(i, TRUE); //Upper
104 _add_code((i | 32), FALSE); //Lower
107 // Numbers
108 for (i = '0'; i <= '9'; i++) {
109 _add_code(i, FALSE);
112 // These are arbitrary keys that will just work. They would be too
113 // weird to try to enter in a loop, seeing as how consecutive ascii
114 // codes sometimes require shift, and sometimes do not.
115 // This is just me running my fingers across my QWERTY US keyboard.
116 _add_code(' ', FALSE); //Space
117 _add_code('\t', FALSE); //Tab
118 _add_code('`', FALSE);
119 _add_code('~', TRUE);
120 _add_code('!', TRUE);
121 _add_code('@', TRUE);
122 _add_code('#', TRUE);
123 _add_code('$', TRUE);
124 _add_code('%', TRUE);
125 _add_code('^', TRUE);
126 _add_code('&', TRUE);
127 _add_code('*', TRUE);
128 _add_code('(', TRUE);
129 _add_code(')', TRUE);
130 _add_code('-', FALSE);
131 _add_code('_', TRUE);
132 _add_code('=', FALSE);
133 _add_code('+', TRUE);
134 _add_code('[', FALSE);
135 _add_code('{', TRUE);
136 _add_code(']', FALSE);
137 _add_code('}', TRUE);
138 _add_code('\\', FALSE);
139 _add_code('|', TRUE);
140 _add_code(';', FALSE);
141 _add_code(':', TRUE);
142 _add_code('\'', FALSE);
143 _add_code('"', TRUE);
144 _add_code(',', FALSE);
145 _add_code('<', TRUE); //Strangely, this doesn't appear to work. "+," does though.
146 _add_code('.', FALSE);
147 _add_code('>', TRUE);
148 _add_code('/', FALSE);
149 _add_code('?', TRUE);
151 SHIFT_L = XKeysymToKeycode(defaults->display, XStringToKeysym("Shift_L"));
152 CONTROL_L = XKeysymToKeycode(defaults->display,
153 XStringToKeysym("Control_L"));
154 ALT_L = XKeysymToKeycode(defaults->display, XStringToKeysym("Alt_L"));
155 META_L = XKeysymToKeycode(defaults->display, XStringToKeysym("Super_L"));
157 #ifdef LESS_THAN_FIX
158 //Note that we leave the ascii code and shift alone, so in
159 //essence we are sending +, or shift + comma.
160 ascii_codes['<'].code = ascii_codes[','].code; //Corrects the "<" problem
161 #endif // LESS_THAN_FIX
162 return TRUE;
164 #else
165 BOOL _init_ascii() {
166 fprintf( stderr, "init: No init_ascii function enabled" );
167 return FALSE;
169 #endif //EN_US
171 void _initialize() {
172 if (defaults && defaults->display) {
173 return;
175 if (!init_defaults()) {
176 fprintf(stderr, "Failure initialize defaults\n");
177 return;
179 if (!_init_ascii()) {
180 fprintf(stderr, "Failure to initialize ascii keys\n");
181 return;
185 BOOL init_defaults() {
186 Display *display = XOpenDisplay(NULL);
187 if (display == NULL) {
188 fprintf(stderr, "init: Unable to get default display\n");
189 return FALSE;
191 defaults = malloc(sizeof(xautpy_defaults_t));
192 if (defaults == NULL) {
193 fprintf(stderr, "init: Unable to allocate space for defaults");
194 return FALSE;
196 memset(defaults, 0, sizeof(xautpy_defaults_t));
197 defaults->display = display;
198 int defScreen = XDefaultScreen(defaults->display);
199 defaults->dsp_width = XDisplayWidth(defaults->display, defScreen);
200 defaults->dsp_height = XDisplayHeight(defaults->display, defScreen);
201 defaults->mouse_move_delay = 10;
202 defaults->mouse_down_delay = 10;
203 defaults->mouse_click_delay = 10;
204 defaults->key_down_delay = 10;
205 defaults->key_click_delay = 5;
206 defaults->log_level = LOG_LEVEL_NONE;
207 defaults->interpret_meta_symbols = TRUE;
208 return TRUE;
211 BOOL _is_supported_feature(char *feature) {
212 Atom type = 0;
213 long item_count = 0L;
214 int size = 0;
215 Atom *results = NULL;
216 long i = 0;
218 Atom request = XInternAtom(defaults->display, "_NET_SUPPORTED", FALSE);
219 Atom feature_atom = XInternAtom(defaults->display, feature, FALSE);
220 Window root = RootWindow(defaults->display, 0);
222 results = (Atom *) _window_property(
223 root, request, &item_count, &type, &size);
224 BOOL ret = FALSE;
225 for (i = 0L; i < item_count; i++) {
226 if (results[i] == feature_atom)
227 ret = TRUE;
229 XFree(results);
230 return ret;
233 char* _stringmid(const char *str, size_t first, size_t last) {
234 if (str == NULL) {
235 return NULL;
237 size_t len = strlen(str);
238 if (len == 0 || len < first || last < first) {
239 return NULL;
241 if (len < last) {
242 last = len;
244 size_t count = last - first + 1;
245 char *ret = malloc((count + 1) * sizeof(char));
246 if (ret == NULL) {
247 fprintf(stderr, "Unable to create string of %d characters\n",
248 (count + 1));
249 return NULL;
251 memset(ret, '\0', (count + 1) * sizeof(char));
252 ret = strncpy(ret, str + first, count);
253 return ret;
256 void _normalize_coords(int *x, int *y) {
257 if (!_check_init()) {
258 return;
260 if (*x < 0) {
261 *x = 0;
262 } else if (*x > defaults->dsp_width) {
263 x = &defaults->dsp_width;
265 if (*y < 0) {
266 *y = 0;
267 } else if (*y > defaults->dsp_height) {
268 y = &defaults->dsp_height;
270 logit(LOG_LEVEL_VERBOSE, "Final mouse location %d X %d\n", *x, *y);
273 BOOL _normalize_wincoords(int *x, int *y, unsigned long win) {
274 if (!_check_init()) {
275 return FALSE;
277 XWindowAttributes *attribs = calloc(1, sizeof(XWindowAttributes));
278 if(attribs == NULL) {
279 fprintf(stderr, "Unable to allocate space for XWindowAttributes");
280 return FALSE;
282 XSetErrorHandler(_invalid_window_error_handler);
283 int status = XGetWindowAttributes(defaults->display, win, attribs);
284 XSetErrorHandler(NULL);
285 BOOL ret;
286 if (status) {
287 int winx = window_x(win);
288 int winy = window_y(win);
289 *x = winx + *x;
290 *y = winy + *y;
291 logit(LOG_LEVEL_VERBOSE, "Window at %d X %d\n", winx, winy);
292 logit(LOG_LEVEL_VERBOSE, "Relative location %d X %d\n", *x, *y);
293 ret = TRUE;
294 } else {
295 fprintf(stderr, "Window handle %lu appears to be invalid\n", win);
296 fprintf(stderr, "Not moving the mouse\n");
297 *x = mouse_x(0);
298 *y = mouse_y(0);
299 ret = FALSE;
301 free(attribs);
302 //In case the window is partially off the screen
303 _normalize_coords(x, y);
304 return ret;
307 /* Typically we don't need to do anything other than return
308 * a status of zero. That is sufficient for these functions
310 int _invalid_window_error_handler(Display *dsp, XErrorEvent *err) {
311 return 0;