-
Notifications
You must be signed in to change notification settings - Fork 124
/
demo_hook.c
208 lines (172 loc) · 7.35 KB
/
demo_hook.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/* libUIOHook: Cross-platform keyboard and mouse hooking from userland.
* Copyright (C) 2006-2023 Alexander Barker. All Rights Reserved.
* https://github.com/kwhat/libuiohook/
*
* libUIOHook is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libUIOHook is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <uiohook.h>
#include <wchar.h>
bool logger_proc(unsigned int level, const char *format, ...) {
bool status = false;
va_list args;
switch (level) {
case LOG_LEVEL_INFO:
va_start(args, format);
status = vfprintf(stdout, format, args) >= 0;
va_end(args);
break;
case LOG_LEVEL_WARN:
case LOG_LEVEL_ERROR:
va_start(args, format);
status = vfprintf(stderr, format, args) >= 0;
va_end(args);
break;
}
return status;
}
// NOTE: The following callback executes on the same thread that hook_run() is called
// from. This is important because hook_run() attaches to the operating systems
// event dispatcher and may delay event delivery to the target application.
// Furthermore, some operating systems may choose to disable your hook if it
// takes too long to process. If you need to do any extended processing, please
// do so by copying the event to your own queued dispatch thread.
void dispatch_proc(uiohook_event * const event) {
char buffer[256] = { 0 };
size_t length = snprintf(buffer, sizeof(buffer),
"id=%i,when=%" PRIu64 ",mask=0x%X",
event->type, event->time, event->mask);
switch (event->type) {
case EVENT_KEY_PRESSED:
// If the escape key is pressed, naturally terminate the program.
if (event->data.keyboard.keycode == VC_ESCAPE) {
int status = hook_stop();
switch (status) {
case UIOHOOK_SUCCESS:
// Everything is ok.
break;
// System level errors.
case UIOHOOK_ERROR_OUT_OF_MEMORY:
logger_proc(LOG_LEVEL_ERROR, "Failed to allocate memory. (%#X)", status);
break;
case UIOHOOK_ERROR_X_RECORD_GET_CONTEXT:
// NOTE This is the only platform specific error that occurs on hook_stop().
logger_proc(LOG_LEVEL_ERROR, "Failed to get XRecord context. (%#X)", status);
break;
// Default error.
case UIOHOOK_FAILURE:
default:
logger_proc(LOG_LEVEL_ERROR, "An unknown hook error occurred. (%#X)", status);
break;
}
}
case EVENT_KEY_RELEASED:
snprintf(buffer + length, sizeof(buffer) - length,
",keycode=%u,rawcode=0x%X",
event->data.keyboard.keycode, event->data.keyboard.rawcode);
break;
case EVENT_KEY_TYPED:
snprintf(buffer + length, sizeof(buffer) - length,
",keychar=%lc,rawcode=%u",
(wint_t) event->data.keyboard.keychar,
event->data.keyboard.rawcode);
break;
case EVENT_MOUSE_PRESSED:
case EVENT_MOUSE_RELEASED:
case EVENT_MOUSE_CLICKED:
case EVENT_MOUSE_MOVED:
case EVENT_MOUSE_DRAGGED:
snprintf(buffer + length, sizeof(buffer) - length,
",x=%i,y=%i,button=%i,clicks=%i",
event->data.mouse.x, event->data.mouse.y,
event->data.mouse.button, event->data.mouse.clicks);
break;
case EVENT_MOUSE_WHEEL:
snprintf(buffer + length, sizeof(buffer) - length,
",type=%i,amount=%i,rotation=%i",
event->data.wheel.type, event->data.wheel.amount,
event->data.wheel.rotation);
break;
default:
break;
}
fprintf(stdout, "%s\n", buffer);
}
int main() {
// Set the logger callback for library output.
hook_set_logger_proc(&logger_proc);
// Set the event callback for uiohook events.
hook_set_dispatch_proc(&dispatch_proc);
// Start the hook and block.
// NOTE If EVENT_HOOK_ENABLED was delivered, the status will always succeed.
int status = hook_run();
switch (status) {
case UIOHOOK_SUCCESS:
// Everything is ok.
break;
// System level errors.
case UIOHOOK_ERROR_OUT_OF_MEMORY:
logger_proc(LOG_LEVEL_ERROR, "Failed to allocate memory. (%#X)", status);
break;
// X11 specific errors.
case UIOHOOK_ERROR_X_OPEN_DISPLAY:
logger_proc(LOG_LEVEL_ERROR, "Failed to open X11 display. (%#X)", status);
break;
case UIOHOOK_ERROR_X_RECORD_NOT_FOUND:
logger_proc(LOG_LEVEL_ERROR, "Unable to locate XRecord extension. (%#X)", status);
break;
case UIOHOOK_ERROR_X_RECORD_ALLOC_RANGE:
logger_proc(LOG_LEVEL_ERROR, "Unable to allocate XRecord range. (%#X)", status);
break;
case UIOHOOK_ERROR_X_RECORD_CREATE_CONTEXT:
logger_proc(LOG_LEVEL_ERROR, "Unable to allocate XRecord context. (%#X)", status);
break;
case UIOHOOK_ERROR_X_RECORD_ENABLE_CONTEXT:
logger_proc(LOG_LEVEL_ERROR, "Failed to enable XRecord context. (%#X)", status);
break;
// Windows specific errors.
case UIOHOOK_ERROR_SET_WINDOWS_HOOK_EX:
logger_proc(LOG_LEVEL_ERROR, "Failed to register low level windows hook. (%#X)", status);
break;
// Darwin specific errors.
case UIOHOOK_ERROR_AXAPI_DISABLED:
logger_proc(LOG_LEVEL_ERROR, "Failed to enable access for assistive devices. (%#X)", status);
break;
case UIOHOOK_ERROR_CREATE_EVENT_PORT:
logger_proc(LOG_LEVEL_ERROR, "Failed to create apple event port. (%#X)", status);
break;
case UIOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE:
logger_proc(LOG_LEVEL_ERROR, "Failed to create apple run loop source. (%#X)", status);
break;
case UIOHOOK_ERROR_GET_RUNLOOP:
logger_proc(LOG_LEVEL_ERROR, "Failed to acquire apple run loop. (%#X)", status);
break;
case UIOHOOK_ERROR_CREATE_OBSERVER:
logger_proc(LOG_LEVEL_ERROR, "Failed to create apple run loop observer. (%#X)", status);
break;
// Default error.
case UIOHOOK_FAILURE:
default:
logger_proc(LOG_LEVEL_ERROR, "An unknown hook error occurred. (%#X)", status);
break;
}
return status;
}