diff --git a/cdeps/hook/README.md b/cdeps/hook/README.md deleted file mode 100644 index 6dcd4be..0000000 --- a/cdeps/hook/README.md +++ /dev/null @@ -1,4 +0,0 @@ -The hook directory link from the https://github.com/robotn/gohook/ -hook, you need to follow the relevant agreement and LICENSE. -See the LICENSE file at the top-level directory of this distribution and at -https://github.com/robotn/gohook/blob/master/LICENSE \ No newline at end of file diff --git a/cdeps/hook/darwin/event_c.h b/cdeps/hook/darwin/event_c.h deleted file mode 100644 index c621b71..0000000 --- a/cdeps/hook/darwin/event_c.h +++ /dev/null @@ -1,235 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include -#include -#include -#include "../iohook.h" - -// #include "../logger_c.h" -#include "input.h" - -// TODO Possibly relocate to input helper. -static inline CGEventFlags get_key_event_mask(iohook_event * const event) { - CGEventFlags native_mask = 0x00; - - if (event->mask & (MASK_SHIFT)) { native_mask |= kCGEventFlagMaskShift; } - if (event->mask & (MASK_CTRL)) { native_mask |= kCGEventFlagMaskControl; } - if (event->mask & (MASK_META)) { native_mask |= kCGEventFlagMaskControl; } - if (event->mask & (MASK_ALT)) { native_mask |= kCGEventFlagMaskAlternate; } - - if (event->type == EVENT_KEY_PRESSED || event->type == EVENT_KEY_RELEASED || event->type == EVENT_KEY_TYPED) { - switch (event->data.keyboard.keycode) { - case VC_KP_0: - case VC_KP_1: - case VC_KP_2: - case VC_KP_3: - case VC_KP_4: - case VC_KP_5: - case VC_KP_6: - case VC_KP_7: - case VC_KP_8: - case VC_KP_9: - - case VC_NUM_LOCK: - case VC_KP_ENTER: - case VC_KP_MULTIPLY: - case VC_KP_ADD: - case VC_KP_SEPARATOR: - case VC_KP_SUBTRACT: - case VC_KP_DIVIDE: - case VC_KP_COMMA: - native_mask |= kCGEventFlagMaskNumericPad; - break; - } - } - - return native_mask; -} - -static inline void post_key_event(iohook_event * const event) { - bool is_pressed = event->type == EVENT_KEY_PRESSED; - - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef cg_event = CGEventCreateKeyboardEvent(src, - (CGKeyCode) scancode_to_keycode(event->data.keyboard.keycode), - is_pressed); - - CGEventSetFlags(cg_event, get_key_event_mask(event)); - CGEventPost(kCGHIDEventTap, cg_event); // kCGSessionEventTap also works. - CFRelease(cg_event); - CFRelease(src); -} - -static inline void post_mouse_button_event(iohook_event * const event, bool is_pressed) { - CGMouseButton mouse_button; - CGEventType mouse_type; - if (event->data.mouse.button == MOUSE_BUTTON1) { - if (is_pressed) { - mouse_type = kCGEventLeftMouseDown; - } - else { - mouse_type = kCGEventLeftMouseUp; - } - mouse_button = kCGMouseButtonLeft; - } - else if (event->data.mouse.button == MOUSE_BUTTON2) { - if (is_pressed) { - mouse_type = kCGEventRightMouseDown; - } - else { - mouse_type = kCGEventRightMouseUp; - } - mouse_button = kCGMouseButtonRight; - } - else { - if (is_pressed) { - mouse_type = kCGEventOtherMouseDown; - } - else { - mouse_type = kCGEventOtherMouseUp; - } - mouse_button = event->data.mouse.button - 1; - } - - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef cg_event = CGEventCreateMouseEvent(src, - mouse_type, - CGPointMake( - (CGFloat) event->data.mouse.x, - (CGFloat) event->data.mouse.y - ), - mouse_button - ); - CGEventPost(kCGHIDEventTap, cg_event); // kCGSessionEventTap also works. - CFRelease(cg_event); - CFRelease(src); -} - -static inline void post_mouse_wheel_event(iohook_event * const event) { - // FIXME Should I create a source event with the coords? - // It seems to automagically use the current location of the cursor. - // Two options: Query the mouse, move it to x/y, scroll, then move back - // OR disable x/y for scroll events on Windows & X11. - CGScrollEventUnit scroll_unit; - if (event->data.wheel.type == WHEEL_BLOCK_SCROLL) { - // Scrolling data is line-based. - scroll_unit = kCGScrollEventUnitLine; - } - else { - // Scrolling data is pixel-based. - scroll_unit = kCGScrollEventUnitPixel; - } - - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef cg_event = CGEventCreateScrollWheelEvent(src, - kCGScrollEventUnitLine, - // TODO Currently only support 1 wheel axis. - (CGWheelCount) 1, // 1 for Y-only, 2 for Y-X, 3 for Y-X-Z - event->data.wheel.amount * event->data.wheel.rotation); - - CGEventPost(kCGHIDEventTap, cg_event); // kCGSessionEventTap also works. - CFRelease(cg_event); - CFRelease(src); -} - -static inline void post_mouse_motion_event(iohook_event * const event) { - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef cg_event; - if (event->mask >> 8 == 0x00) { - // No mouse flags. - cg_event = CGEventCreateMouseEvent(src, - kCGEventMouseMoved, - CGPointMake( - (CGFloat) event->data.mouse.x, - (CGFloat) event->data.mouse.y - ), - 0 - ); - } - else if (event->mask & MASK_BUTTON1) { - cg_event = CGEventCreateMouseEvent(src, - kCGEventLeftMouseDragged, - CGPointMake( - (CGFloat) event->data.mouse.x, - (CGFloat) event->data.mouse.y - ), - kCGMouseButtonLeft - ); - } - else if (event->mask & MASK_BUTTON2) { - cg_event = CGEventCreateMouseEvent(src, - kCGEventRightMouseDragged, - CGPointMake( - (CGFloat) event->data.mouse.x, - (CGFloat) event->data.mouse.y - ), - kCGMouseButtonRight - ); - } - else { - cg_event = CGEventCreateMouseEvent(src, - kCGEventOtherMouseDragged, - CGPointMake( - (CGFloat) event->data.mouse.x, - (CGFloat) event->data.mouse.y - ), - (event->mask >> 8) - 1 - ); - } - - // kCGSessionEventTap also works. - CGEventPost(kCGHIDEventTap, cg_event); - CFRelease(cg_event); - CFRelease(src); -} - -IOHOOK_API void hook_post_event(iohook_event * const event) { - switch (event->type) { - case EVENT_KEY_PRESSED: - case EVENT_KEY_RELEASED: - post_key_event(event); - break; - - - case EVENT_MOUSE_PRESSED: - post_mouse_button_event(event, true); - break; - - case EVENT_MOUSE_RELEASED: - post_mouse_button_event(event, false); - break; - - case EVENT_MOUSE_CLICKED: - post_mouse_button_event(event, true); - post_mouse_button_event(event, false); - break; - - case EVENT_MOUSE_WHEEL: - post_mouse_wheel_event(event); - break; - - - case EVENT_MOUSE_MOVED: - case EVENT_MOUSE_DRAGGED: - post_mouse_motion_event(event); - break; - - - case EVENT_KEY_TYPED: - // FIXME Ignoreing EVENT_KEY_TYPED events. - - case EVENT_HOOK_ENABLED: - case EVENT_HOOK_DISABLED: - // Ignore hook enabled / disabled events. - - default: - // Ignore any other garbage. - logger(LOG_LEVEL_WARN, "%s [%u]: Ignoring post event type %#X\n", - __FUNCTION__, __LINE__, event->type); - break; - } -} diff --git a/cdeps/hook/darwin/hook_c.h b/cdeps/hook/darwin/hook_c.h deleted file mode 100644 index cb8b609..0000000 --- a/cdeps/hook/darwin/hook_c.h +++ /dev/null @@ -1,1362 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef USE_WEAK_IMPORT - #include -#endif -#include -#ifdef USE_OBJC - #include - #include -#endif - -#include -#include -#include -#include "../iohook.h" -// #include "../logger_c.h" -#include "input.h" - -typedef struct _hook_info { - CFMachPortRef port; - CFRunLoopSourceRef source; - CFRunLoopObserverRef observer; -} hook_info; - -#ifdef USE_OBJC -static id auto_release_pool; -#endif - -// Event runloop reference. -CFRunLoopRef event_loop; - -// Flag to restart the event tap incase of timeout. -static Boolean restart_tap = false; - -// Modifiers for tracking key masks. -static uint16_t current_modifiers = 0x0000; - -// Required to transport messages between the main runloop and our thread for -// Unicode lookups. -#define KEY_BUFFER_SIZE 4 -typedef struct { - CGEventRef event; - UniChar buffer[KEY_BUFFER_SIZE]; - UniCharCount length; -} TISMessage; -TISMessage *tis_message; - -#ifdef USE_WEAK_IMPORT -// Required to dynamically check for AXIsProcessTrustedWithOptions availability. -extern void dispatch_get_main_queue() __attribute__((weak_import)); -extern void dispatch_sync_f(dispatch_queue_t queue, void *context, void (*function)(void *)) __attribute__((weak_import)); -#else -#if __MAC_OS_X_VERSION_MAX_ALLOWED <= 1050 -typedef void* dispatch_queue_t; -#endif -static dispatch_queue_t (*dispatch_get_main_queue_f)(); -static void (*dispatch_sync_f_f)(dispatch_queue_t, void *, void (*function)(void *)); -#endif - -#if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION) -static CFRunLoopSourceRef src_msg_port; -static CFRunLoopObserverRef observer; - -static pthread_cond_t msg_port_cond = PTHREAD_COND_INITIALIZER; -static pthread_mutex_t msg_port_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -// Click count globals. -static unsigned short click_count = 0; -static CGEventTimestamp click_time = 0; -static unsigned short int click_button = MOUSE_NOBUTTON; -static bool mouse_dragged = false; - -// Structure for the current Unix epoch in milliseconds. -static struct timeval system_time; - -// Virtual event pointer. -static iohook_event event; - -// Event dispatch callback. -static dispatcher_t dispatcher = NULL; - -IOHOOK_API void hook_set_dispatch_proc(dispatcher_t dispatch_proc) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Setting new dispatch callback to %#p.\n", - __FUNCTION__, __LINE__, dispatch_proc); - - dispatcher = dispatch_proc; -} - -// Send out an event if a dispatcher was set. -static inline void dispatch_event(iohook_event *const event) { - if (dispatcher != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Dispatching event type %u.\n", - __FUNCTION__, __LINE__, event->type); - - dispatcher(event); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: No dispatch callback set!\n", - __FUNCTION__, __LINE__); - } -} - - -// Set the native modifier mask for future events. -static inline void set_modifier_mask(uint16_t mask) { - current_modifiers |= mask; -} - -// Unset the native modifier mask for future events. -static inline void unset_modifier_mask(uint16_t mask) { - current_modifiers ^= mask; -} - -// Get the current native modifier mask state. -static inline uint16_t get_modifiers() { - return current_modifiers; -} - -// Initialize the modifier mask to the current modifiers. -static void initialize_modifiers() { - current_modifiers = 0x0000; - - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_Shift)) { - set_modifier_mask(MASK_SHIFT_L); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_RightShift)) { - set_modifier_mask(MASK_SHIFT_R); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_Control)) { - set_modifier_mask(MASK_CTRL_L); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_RightControl)) { - set_modifier_mask(MASK_CTRL_R); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_Option)) { - set_modifier_mask(MASK_ALT_L); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_RightOption)) { - set_modifier_mask(MASK_ALT_R); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_Command)) { - set_modifier_mask(MASK_META_L); - } - if (CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, kVK_RightCommand)) { - set_modifier_mask(MASK_META_R); - } - - if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kVK_LBUTTON)) { - set_modifier_mask(MASK_BUTTON1); - } - if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kVK_RBUTTON)) { - set_modifier_mask(MASK_BUTTON2); - } - if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kVK_MBUTTON)) { - set_modifier_mask(MASK_BUTTON3); - } - if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kVK_XBUTTON1)) { - set_modifier_mask(MASK_BUTTON4); - } - if (CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kVK_XBUTTON2)) { - set_modifier_mask(MASK_BUTTON5); - } - - if (CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState) & kCGEventFlagMaskAlphaShift) { - set_modifier_mask(MASK_CAPS_LOCK); - } - // Best I can tell, OS X does not support Num or Scroll lock. - unset_modifier_mask(MASK_NUM_LOCK); - unset_modifier_mask(MASK_SCROLL_LOCK); -} - - -// Wrap keycode_to_unicode with some null checks. -static void keycode_to_lookup(void *info) { - TISMessage *data = (TISMessage *) info; - - if (data != NULL && data->event != NULL) { - // Preform Unicode lookup. - data->length = keycode_to_unicode(data->event, data->buffer, KEY_BUFFER_SIZE); - } -} - -#if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION) -void message_port_status_proc(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { - switch (activity) { - case kCFRunLoopExit: - // Acquire a lock on the msg_port and signal that anyone waiting - // should continue. - pthread_mutex_lock(&msg_port_mutex); - pthread_cond_broadcast(&msg_port_cond); - pthread_mutex_unlock(&msg_port_mutex); - break; - - default: - logger(LOG_LEVEL_WARN, "%s [%u]: Unhandled RunLoop activity! (%#X)\n", - __FUNCTION__, __LINE__, (unsigned int) activity); - break; - } -} - -// Runloop to execute KeyCodeToString on the "Main" runloop due to an -// undocumented thread safety requirement. -static void message_port_proc(void *info) { - // Lock the msg_port mutex as we enter the main runloop. - pthread_mutex_lock(&msg_port_mutex); - - keycode_to_lookup(info); - - // Unlock the msg_port mutex to signal to the hook_thread that we have - // finished on the main runloop. - pthread_cond_broadcast(&msg_port_cond); - pthread_mutex_unlock(&msg_port_mutex); -} - -static int start_message_port_runloop() { - int status = IOHOOK_FAILURE; - - if (tis_message != NULL) { - // Create a runloop observer for the main runloop. - observer = CFRunLoopObserverCreate( - kCFAllocatorDefault, - kCFRunLoopExit, //kCFRunLoopEntry | kCFRunLoopExit, //kCFRunLoopAllActivities, - true, - 0, - message_port_status_proc, - NULL - ); - - if (observer != NULL) { - pthread_mutex_lock(&msg_port_mutex); - - CFRunLoopSourceContext context = { - .version = 0, - .info = tis_message, - .retain = NULL, - .release = NULL, - .copyDescription = NULL, - .equal = NULL, - .hash = NULL, - .schedule = NULL, - .cancel = NULL, - .perform = message_port_proc - }; - - CFRunLoopRef main_loop = CFRunLoopGetMain(); - - src_msg_port = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); - if (src_msg_port != NULL) { - CFRunLoopAddSource(main_loop, src_msg_port, kCFRunLoopDefaultMode); - CFRunLoopAddObserver(main_loop, observer, kCFRunLoopDefaultMode); - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Successful.\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_SUCCESS; - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopSourceCreate failure!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE; - } - - pthread_mutex_unlock(&msg_port_mutex); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopObserverCreate failure!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_CREATE_OBSERVER; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: No available TIS Message pointer.\n", - __FUNCTION__, __LINE__); - } - - return status; -} - -static void stop_message_port_runloop() { - CFRunLoopRef main_loop = CFRunLoopGetMain(); - - if (CFRunLoopContainsObserver(main_loop, observer, kCFRunLoopDefaultMode)) { - CFRunLoopRemoveObserver(main_loop, observer, kCFRunLoopDefaultMode); - CFRunLoopObserverInvalidate(observer); - } - - if (CFRunLoopContainsSource(main_loop, src_msg_port, kCFRunLoopDefaultMode)) { - CFRunLoopRemoveSource(main_loop, src_msg_port, kCFRunLoopDefaultMode); - CFRelease(src_msg_port); - } - - observer = NULL; - src_msg_port = NULL; - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Successful.\n", - __FUNCTION__, __LINE__); -} -#endif - -static void hook_status_proc(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { - uint64_t timestamp = mach_absolute_time(); - - switch (activity) { - case kCFRunLoopEntry: - // Populate the hook start event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_HOOK_ENABLED; - event.mask = 0x00; - - // Fire the hook start event. - dispatch_event(&event); - break; - - case kCFRunLoopExit: - // Populate the hook stop event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_HOOK_DISABLED; - event.mask = 0x00; - - // Fire the hook stop event. - dispatch_event(&event); - break; - - default: - logger(LOG_LEVEL_WARN, "%s [%u]: Unhandled RunLoop activity! (%#X)\n", - __FUNCTION__, __LINE__, (unsigned int) activity); - break; - } -} - -static inline void process_key_pressed(uint64_t timestamp, CGEventRef event_ref) { - UInt64 keycode = CGEventGetIntegerValueField(event_ref, kCGKeyboardEventKeycode); - - // Populate key pressed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_KEY_PRESSED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = keycode_to_scancode(keycode); - event.data.keyboard.rawcode = keycode; - event.data.keyboard.keychar = CHAR_UNDEFINED; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X pressed. (%#X)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, event.data.keyboard.rawcode); - - // Fire key pressed event. - dispatch_event(&event); - - // If the pressed event was not consumed... - if (event.reserved ^ 0x01) { - tis_message->event = event_ref; - tis_message->length = 0; - bool is_runloop_main = CFEqual(event_loop, CFRunLoopGetMain()); - - #ifdef USE_WEAK_IMPORT - if (dispatch_sync_f != NULL && dispatch_get_main_queue != NULL && !is_runloop_main) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Using dispatch_sync_f for key typed events.\n", __FUNCTION__, __LINE__); - dispatch_sync_f(dispatch_get_main_queue(), tis_message, &keycode_to_lookup); - } - #else - if (dispatch_sync_f_f != NULL && dispatch_get_main_queue_f != NULL && !is_runloop_main) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Using *dispatch_sync_f_f for key typed events.\n", __FUNCTION__, __LINE__); - (*dispatch_sync_f_f)((*dispatch_get_main_queue_f)(), tis_message, &keycode_to_lookup); - } - #endif - #if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION) - else if (!is_runloop_main) { - // Lock for code dealing with the main runloop. - pthread_mutex_lock(&msg_port_mutex); - - // Check to see if the main runloop is still running. - // TOOD I would rather this be a check on hook_enable(), - // but it makes the usage complicated by requiring a separate - // thread for the main runloop and hook registration. - CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain()); - if (mode != NULL) { - CFRelease(mode); - - // Lookup the Unicode representation for this event. - //CFRunLoopSourceContext context = { .version = 0 }; - //CFRunLoopSourceGetContext(src_msg_port, &context); - - // Get the run loop context info pointer. - //TISMessage *info = (TISMessage *) context.info; - - // Set the event pointer. - //info->event = event_ref; - - // Signal the custom source and wakeup the main runloop. - CFRunLoopSourceSignal(src_msg_port); - CFRunLoopWakeUp(CFRunLoopGetMain()); - - // Wait for a lock while the main runloop processes they key typed event. - pthread_cond_wait(&msg_port_cond, &msg_port_mutex); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: Failed to signal RunLoop main!\n", - __FUNCTION__, __LINE__); - } - - // Unlock for code dealing with the main runloop. - pthread_mutex_unlock(&msg_port_mutex); - } - #endif - else { - keycode_to_lookup(tis_message); - } - unsigned int i; - for (i= 0; i < tis_message->length; i++) { - // Populate key typed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_KEY_TYPED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = VC_UNDEFINED; - event.data.keyboard.rawcode = keycode; - event.data.keyboard.keychar = tis_message->buffer[i]; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X typed. (%lc)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, - (wint_t) event.data.keyboard.keychar); - - // Populate key typed event. - dispatch_event(&event); - } - } -} - -static inline void process_key_released(uint64_t timestamp, CGEventRef event_ref) { - UInt64 keycode = CGEventGetIntegerValueField(event_ref, kCGKeyboardEventKeycode); - - // Populate key released event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_KEY_RELEASED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = keycode_to_scancode(keycode); - event.data.keyboard.rawcode = keycode; - event.data.keyboard.keychar = CHAR_UNDEFINED; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X released. (%#X)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, event.data.keyboard.rawcode); - - // Fire key released event. - dispatch_event(&event); -} - -static inline void process_modifier_changed(uint64_t timestamp, CGEventRef event_ref) { - CGEventFlags event_mask = CGEventGetFlags(event_ref); - UInt64 keycode = CGEventGetIntegerValueField(event_ref, kCGKeyboardEventKeycode); - - logger(LOG_LEVEL_INFO, "%s [%u]: Modifiers Changed for key %#X. (%#X)\n", - __FUNCTION__, __LINE__, (unsigned long) keycode, (unsigned int) event_mask); - - /* Because Apple treats modifier keys differently than normal key - * events, any changes to the modifier keys will require a key state - * change to be fired manually. - * - * NOTE Left and right keyboard masks like NX_NEXTLSHIFTKEYMASK exist and - * appear to be in use on Darwin, however they are removed by comment or - * preprocessor with a note that reads "device-dependent (really?)." To - * ensure compatability, we will do this the verbose way. - * - * NOTE The masks for scroll and number lock are set in the key event. - */ - if (keycode == kVK_Shift) { - if (event_mask & kCGEventFlagMaskShift) { - // Process as a key pressed event. - set_modifier_mask(MASK_SHIFT_L); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_SHIFT_L); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_Control) { - if (event_mask & kCGEventFlagMaskControl) { - // Process as a key pressed event. - set_modifier_mask(MASK_CTRL_L); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_CTRL_L); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_Command) { - if (event_mask & kCGEventFlagMaskCommand) { - // Process as a key pressed event. - set_modifier_mask(MASK_META_L); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_META_L); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_Option) { - if (event_mask & kCGEventFlagMaskAlternate) { - // Process as a key pressed event. - set_modifier_mask(MASK_ALT_L); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_ALT_L); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_RightShift) { - if (event_mask & kCGEventFlagMaskShift) { - // Process as a key pressed event. - set_modifier_mask(MASK_SHIFT_R); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_SHIFT_R); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_RightControl) { - if (event_mask & kCGEventFlagMaskControl) { - // Process as a key pressed event. - set_modifier_mask(MASK_CTRL_R); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_CTRL_R); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_RightCommand) { - if (event_mask & kCGEventFlagMaskCommand) { - // Process as a key pressed event. - set_modifier_mask(MASK_META_R); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_META_R); - process_key_released(timestamp, event_ref); - } - } - else if (keycode == kVK_RightOption) { - if (event_mask & kCGEventFlagMaskAlternate) { - // Process as a key pressed event. - set_modifier_mask(MASK_ALT_R); - process_key_pressed(timestamp, event_ref); - } - else { - // Process as a key released event. - unset_modifier_mask(MASK_ALT_R); - process_key_released(timestamp, event_ref); - } - } - /* FIXME This should produce a modifier mask for the caps lock key! - else if (keycode == kVK_CapsLock) { - // Process as a key pressed event. - process_key_pressed(timestamp, event_ref); - - // Set the caps-lock flag for release. - caps_down = true; - } - */ -} - -/* These events are totally undocumented for the CGEvent type, but are required to grab media and caps-lock keys. - */ -static inline void process_system_key(uint64_t timestamp, CGEventRef event_ref) { - if( CGEventGetType(event_ref) == NX_SYSDEFINED) { - #ifdef USE_OBJC - // Contributed by Iván Munsuri Ibáñez - id event_data = objc_msgSend((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), event_ref); - int subtype = (int) objc_msgSend(event_data, sel_registerName("subtype")); - #else - CFDataRef data = CGEventCreateData(kCFAllocatorDefault, event_ref); - //CFIndex len = CFDataGetLength(data); - UInt8 *buffer = malloc(12); - // CFDataRef cf_data = CFDataCreate(NULL, [nsData bytes], [nsData length]); - CFDataGetBytes(data, CFRangeMake(108, 12), buffer); - UInt32 subtype = CFSwapInt32BigToHost(*((UInt32 *) buffer)); - #endif - if (subtype == 8) { - #ifdef USE_OBJC - // int data = (int) objc_msgSend(event_data, sel_registerName("data1")); - uint16_t data = (uint16_t) objc_msgSend(event_data, sel_registerName("data1")) - #endif - - // int - uint16_t key_code = ((uint16_t)data & 0xFFFF0000) >> 16; - uint16_t key_flags = ((uint16_t)data & 0xFFFF); - //int key_state = (key_flags & 0xFF00) >> 8; - bool key_down = (key_flags & 0x1) > 0; - - if (key_code == NX_KEYTYPE_CAPS_LOCK) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_CapsLock, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - else if (key_code == NX_KEYTYPE_SOUND_UP) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_VolumeUp, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - else if (key_code == NX_KEYTYPE_SOUND_DOWN) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_VolumeDown, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - else if (key_code == NX_KEYTYPE_MUTE) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_Mute, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - - else if (key_code == NX_KEYTYPE_EJECT) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_NX_Eject, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - else if (key_code == NX_KEYTYPE_PLAY) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_MEDIA_Play, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - else if (key_code == NX_KEYTYPE_FAST) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_MEDIA_Next, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - else if (key_code == NX_KEYTYPE_REWIND) { - // It doesn't appear like we can modify the event coming in, so we will fabricate a new event. - CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef ns_event = CGEventCreateKeyboardEvent(src, kVK_MEDIA_Previous, key_down); - CGEventSetFlags(ns_event, CGEventGetFlags(event_ref)); - - if (key_down) { - process_key_pressed(timestamp, ns_event); - } - else { - process_key_released(timestamp, ns_event); - } - - CFRelease(ns_event); - CFRelease(src); - } - } - - #ifndef USE_OBJC - free(buffer); - CFRelease(data); - #endif - } -} - - -static inline void process_button_pressed(uint64_t timestamp, CGEventRef event_ref, uint16_t button) { - // Track the number of clicks. - if (button == click_button && (long int) (timestamp - click_time) <= hook_get_multi_click_time()) { - if (click_count < USHRT_MAX) { - click_count++; - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: Click count overflow detected!\n", - __FUNCTION__, __LINE__); - } - } - else { - // Reset the click count. - click_count = 1; - - // Set the previous button. - click_button = button; - } - - // Save this events time to calculate the click_count. - click_time = timestamp; - - CGPoint event_point = CGEventGetLocation(event_ref); - - // Populate mouse pressed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_PRESSED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = click_count; - event.data.mouse.x = event_point.x; - event.data.mouse.y = event_point.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u pressed %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse pressed event. - dispatch_event(&event); -} - -static inline void process_button_released(uint64_t timestamp, CGEventRef event_ref, uint16_t button) { - CGPoint event_point = CGEventGetLocation(event_ref); - - // Populate mouse released event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_RELEASED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = click_count; - event.data.mouse.x = event_point.x; - event.data.mouse.y = event_point.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u released %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse released event. - dispatch_event(&event); - - // If the pressed event was not consumed... - if (event.reserved ^ 0x01 && mouse_dragged != true) { - // Populate mouse clicked event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_CLICKED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = click_count; - event.data.mouse.x = event_point.x; - event.data.mouse.y = event_point.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u clicked %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse clicked event. - dispatch_event(&event); - } - - // Reset the number of clicks. - if (button == click_button && (long int) (event.time - click_time) > hook_get_multi_click_time()) { - // Reset the click count. - click_count = 0; - } -} - -static inline void process_mouse_moved(uint64_t timestamp, CGEventRef event_ref) { - // Reset the click count. - if (click_count != 0 && (long int) (timestamp - click_time) > hook_get_multi_click_time()) { - click_count = 0; - } - - CGPoint event_point = CGEventGetLocation(event_ref); - - // Populate mouse motion event. - event.time = timestamp; - event.reserved = 0x00; - - if (mouse_dragged) { - event.type = EVENT_MOUSE_DRAGGED; - } - else { - event.type = EVENT_MOUSE_MOVED; - } - event.mask = get_modifiers(); - - event.data.mouse.button = MOUSE_NOBUTTON; - event.data.mouse.clicks = click_count; - event.data.mouse.x = event_point.x; - event.data.mouse.y = event_point.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Mouse %s to %u, %u.\n", - __FUNCTION__, __LINE__, mouse_dragged ? "dragged" : "moved", - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse motion event. - dispatch_event(&event); -} - -static inline void process_mouse_wheel(uint64_t timestamp, CGEventRef event_ref) { - // Reset the click count and previous button. - click_count = 1; - click_button = MOUSE_NOBUTTON; - - // Check to see what axis was rotated, we only care about axis 1 for vertical rotation. - // TODO Implement horizontal scrolling by examining axis 2. - // NOTE kCGScrollWheelEventDeltaAxis3 is currently unused. - if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1) != 0 - || CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis2) != 0) { - CGPoint event_point = CGEventGetLocation(event_ref); - - // Populate mouse wheel event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_WHEEL; - event.mask = get_modifiers(); - - event.data.wheel.clicks = click_count; - event.data.wheel.x = event_point.x; - event.data.wheel.y = event_point.y; - - // TODO Figure out if kCGScrollWheelEventDeltaAxis2 causes mouse events with zero rotation. - if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventIsContinuous) == 0) { - // Scrolling data is line-based. - event.data.wheel.type = WHEEL_BLOCK_SCROLL; - } - else { - // Scrolling data is pixel-based. - event.data.wheel.type = WHEEL_UNIT_SCROLL; - } - - // TODO The result of kCGScrollWheelEventIsContinuous may effect this value. - // Calculate the amount based on the Point Delta / Event Delta. Integer sign should always be homogeneous resulting in a positive result. - // NOTE kCGScrollWheelEventFixedPtDeltaAxis1 a floating point value (+0.1/-0.1) that takes acceleration into account. - // NOTE kCGScrollWheelEventPointDeltaAxis1 will not build on OS X < 10.5 - - if(CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1) != 0) { - event.data.wheel.amount = CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventPointDeltaAxis1) / CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1); - - // Scrolling data uses a fixed-point 16.16 signed integer format (Ex: 1.0 = 0x00010000). - event.data.wheel.rotation = CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1) * -1; - - } - else if(CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis2) != 0) { - event.data.wheel.amount = CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventPointDeltaAxis2) / CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis2); - - // Scrolling data uses a fixed-point 16.16 signed integer format (Ex: 1.0 = 0x00010000). - event.data.wheel.rotation = CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis2) * -1; - } - else { - //Fail Silently if a 3rd axis gets added without changing this section of code. - event.data.wheel.amount = 0; - event.data.wheel.rotation = 0; - } - - - - if (CGEventGetIntegerValueField(event_ref, kCGScrollWheelEventDeltaAxis1) != 0) { - // Wheel Rotated Up or Down. - event.data.wheel.direction = WHEEL_VERTICAL_DIRECTION; - } - else { // data->event.u.u.detail == WheelLeft || data->event.u.u.detail == WheelRight - // Wheel Rotated Left or Right. - event.data.wheel.direction = WHEEL_HORIZONTAL_DIRECTION; - } - - logger(LOG_LEVEL_INFO, "%s [%u]: Mouse wheel type %u, rotated %i units in the %u direction at %u, %u.\n", - __FUNCTION__, __LINE__, event.data.wheel.type, - event.data.wheel.amount * event.data.wheel.rotation, - event.data.wheel.direction, - event.data.wheel.x, event.data.wheel.y); - - // Fire mouse wheel event. - dispatch_event(&event); - } -} - -CGEventRef hook_event_proc(CGEventTapProxy tap_proxy, CGEventType type, CGEventRef event_ref, void *refcon) { - // Get the local system time in UTC. - gettimeofday(&system_time, NULL); - - // Grab the native event timestap for use later.. - uint64_t timestamp = (uint64_t) CGEventGetTimestamp(event_ref); - - // Get the event class. - switch (type) { - case kCGEventKeyDown: - process_key_pressed(timestamp, event_ref); - break; - - case kCGEventKeyUp: - process_key_released(timestamp, event_ref); - break; - - case kCGEventFlagsChanged: - process_modifier_changed(timestamp, event_ref); - break; - - //b - // case NX_SYSDEFINED: - // process_system_key(timestamp, event_ref); - // break; - - case kCGEventLeftMouseDown: - set_modifier_mask(MASK_BUTTON1); - process_button_pressed(timestamp, event_ref, MOUSE_BUTTON1); - break; - - case kCGEventRightMouseDown: - set_modifier_mask(MASK_BUTTON2); - process_button_pressed(timestamp, event_ref, MOUSE_BUTTON2); - break; - - case kCGEventOtherMouseDown: - // Extra mouse buttons. - if (CGEventGetIntegerValueField(event_ref, kCGMouseEventButtonNumber) < UINT16_MAX) { - uint16_t button = (uint16_t) CGEventGetIntegerValueField(event_ref, kCGMouseEventButtonNumber) + 1; - - // Add support for mouse 4 & 5. - if (button == 4) { - set_modifier_mask(MOUSE_BUTTON4); - } - else if (button == 5) { - set_modifier_mask(MOUSE_BUTTON5); - } - - process_button_pressed(timestamp, event_ref, button); - } - break; - - case kCGEventLeftMouseUp: - unset_modifier_mask(MASK_BUTTON1); - process_button_released(timestamp, event_ref, MOUSE_BUTTON1); - break; - - case kCGEventRightMouseUp: - unset_modifier_mask(MASK_BUTTON2); - process_button_released(timestamp, event_ref, MOUSE_BUTTON2); - break; - - case kCGEventOtherMouseUp: - // Extra mouse buttons. - if (CGEventGetIntegerValueField(event_ref, kCGMouseEventButtonNumber) < UINT16_MAX) { - uint16_t button = (uint16_t) CGEventGetIntegerValueField(event_ref, kCGMouseEventButtonNumber) + 1; - - // Add support for mouse 4 & 5. - if (button == 4) { - unset_modifier_mask(MOUSE_BUTTON4); - } - else if (button == 5) { - unset_modifier_mask(MOUSE_BUTTON5); - } - - process_button_pressed(timestamp, event_ref, button); - } - break; - - - case kCGEventLeftMouseDragged: - case kCGEventRightMouseDragged: - case kCGEventOtherMouseDragged: - // FIXME The drag flag is confusing. Use prev x,y to determine click. - // Set the mouse dragged flag. - mouse_dragged = true; - process_mouse_moved(timestamp, event_ref); - break; - - case kCGEventMouseMoved: - // Set the mouse dragged flag. - mouse_dragged = false; - process_mouse_moved(timestamp, event_ref); - break; - - - case kCGEventScrollWheel: - process_mouse_wheel(timestamp, event_ref); - break; - - - #ifdef USE_DEBUG - case kCGEventNull: - logger(LOG_LEVEL_DEBUG, "%s [%u]: Ignoring kCGEventNull.\n", - __FUNCTION__, __LINE__); - break; - #endif - - default: - // Check for an old OS X bug where the tap seems to timeout for no reason. - // See: http://stackoverflow.com/questions/2969110/cgeventtapcreate-breaks-down-mysteriously-with-key-down-events#2971217 - if (type == (CGEventType) kCGEventTapDisabledByTimeout) { - logger(LOG_LEVEL_WARN, "%s [%u]: CGEventTap timeout!\n", - __FUNCTION__, __LINE__); - - // We need to restart the tap! - restart_tap = true; - CFRunLoopStop(CFRunLoopGetCurrent()); - } - else { - // In theory this *should* never execute. - logger(LOG_LEVEL_DEBUG, "%s [%u]: Unhandled Darwin event: %#X.\n", - __FUNCTION__, __LINE__, (unsigned int) type); - } - break; - } - - CGEventRef result_ref = NULL; - if (event.reserved ^ 0x01) { - result_ref = event_ref; - } - else { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Consuming the current event. (%#X) (%#p)\n", - __FUNCTION__, __LINE__, type, event_ref); - } - - return result_ref; -} - -IOHOOK_API int hook_run() { - int status = IOHOOK_SUCCESS; - - do { - // Reset the restart flag... - restart_tap = false; - - // Check for accessibility each time we start the loop. - if (is_accessibility_enabled()) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Accessibility API is enabled.\n", - __FUNCTION__, __LINE__); - - // Initialize starting modifiers. - initialize_modifiers(); - - // Try and allocate memory for hook_info. - hook_info *hook = malloc(sizeof(hook_info)); - if (hook != NULL) { - // Setup the event mask to listen for. - #ifdef USE_DEBUG - CGEventMask event_mask = kCGEventMaskForAllEvents; - #else - CGEventMask event_mask = CGEventMaskBit(kCGEventKeyDown) | - CGEventMaskBit(kCGEventKeyUp) | - CGEventMaskBit(kCGEventFlagsChanged) | - - CGEventMaskBit(kCGEventLeftMouseDown) | - CGEventMaskBit(kCGEventLeftMouseUp) | - CGEventMaskBit(kCGEventLeftMouseDragged) | - - CGEventMaskBit(kCGEventRightMouseDown) | - CGEventMaskBit(kCGEventRightMouseUp) | - CGEventMaskBit(kCGEventRightMouseDragged) | - - CGEventMaskBit(kCGEventOtherMouseDown) | - CGEventMaskBit(kCGEventOtherMouseUp) | - CGEventMaskBit(kCGEventOtherMouseDragged) | - - CGEventMaskBit(kCGEventMouseMoved) | - CGEventMaskBit(kCGEventScrollWheel) | - - // NOTE This event is undocumented and used - // for caps-lock release and multi-media keys. - CGEventMaskBit(NX_SYSDEFINED); - #endif - - // Create the event tap. - hook->port = CGEventTapCreate( - kCGSessionEventTap, // kCGHIDEventTap - kCGHeadInsertEventTap, // kCGTailAppendEventTap - kCGEventTapOptionDefault, // kCGEventTapOptionListenOnly See Bug #22 - event_mask, - hook_event_proc, - NULL); - - if (hook->port != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: CGEventTapCreate Successful.\n", - __FUNCTION__, __LINE__); - - // Create the runloop event source from the event tap. - hook->source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, hook->port, 0); - if (hook->source != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: CFMachPortCreateRunLoopSource successful.\n", - __FUNCTION__, __LINE__); - - event_loop = CFRunLoopGetCurrent(); - if (event_loop != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopGetCurrent successful.\n", - __FUNCTION__, __LINE__); - - // Create run loop observers. - hook->observer = CFRunLoopObserverCreate( - kCFAllocatorDefault, - kCFRunLoopEntry | kCFRunLoopExit, //kCFRunLoopAllActivities, - true, - 0, - hook_status_proc, - NULL); - - if (hook->observer != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: CFRunLoopObserverCreate successful.\n", - __FUNCTION__, __LINE__); - - tis_message = (TISMessage *) calloc(1, sizeof(TISMessage)); - if (tis_message != NULL) { - if (! CFEqual(event_loop, CFRunLoopGetMain())) { - #ifdef USE_WEAK_IMPORT - if (dispatch_sync_f == NULL || dispatch_get_main_queue == NULL) { - #else - *(void **) (&dispatch_sync_f_f) = dlsym(RTLD_DEFAULT, "dispatch_sync_f"); - const char *dlError = dlerror(); - if (dlError != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n", - __FUNCTION__, __LINE__, dlError); - } - - *(void **) (&dispatch_get_main_queue_f) = dlsym(RTLD_DEFAULT, "dispatch_get_main_queue"); - dlError = dlerror(); - if (dlError != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n", - __FUNCTION__, __LINE__, dlError); - } - - if (dispatch_sync_f_f == NULL || dispatch_get_main_queue_f == NULL) { - #endif - logger(LOG_LEVEL_DEBUG, "%s [%u]: Failed to locate dispatch_sync_f() or dispatch_get_main_queue()!\n", - __FUNCTION__, __LINE__); - - #if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION) - logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to runloop signaling.\n", - __FUNCTION__, __LINE__); - - int runloop_status = start_message_port_runloop(); - if (runloop_status != IOHOOK_SUCCESS) { - return runloop_status; - } - #endif - } - } - - // Add the event source and observer to the runloop mode. - CFRunLoopAddSource(event_loop, hook->source, kCFRunLoopDefaultMode); - CFRunLoopAddObserver(event_loop, hook->observer, kCFRunLoopDefaultMode); - - #ifdef USE_OBJC - // Create a garbage collector to handle Cocoa events correctly. - Class NSAutoreleasePool_class = (Class) objc_getClass("NSAutoreleasePool"); - id pool = class_createInstance(NSAutoreleasePool_class, 0); - auto_release_pool = objc_msgSend(pool, sel_registerName("init")); - #endif - - // Start the hook thread runloop. - CFRunLoopRun(); - - - #ifdef USE_OBJC - //objc_msgSend(auto_release_pool, sel_registerName("drain")); - objc_msgSend(auto_release_pool, sel_registerName("release")); - #endif - - // Lock back up until we are done processing the exit. - if (CFRunLoopContainsObserver(event_loop, hook->observer, kCFRunLoopDefaultMode)) { - CFRunLoopRemoveObserver(event_loop, hook->observer, kCFRunLoopDefaultMode); - } - - if (CFRunLoopContainsSource(event_loop, hook->source, kCFRunLoopDefaultMode)) { - CFRunLoopRemoveSource(event_loop, hook->source, kCFRunLoopDefaultMode); - } - - #if ! defined(USE_CARBON_LEGACY) && defined(USE_COREFOUNDATION) - if (! CFEqual(event_loop, CFRunLoopGetMain())) { - #ifdef USE_WEAK_IMPORT - if (dispatch_sync_f == NULL || dispatch_get_main_queue == NULL) { - #else - if (dispatch_sync_f_f == NULL || dispatch_get_main_queue_f == NULL) { - #endif - stop_message_port_runloop(); - } - } - #endif - - // Free the TIS Message. - free(tis_message); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to allocate memory for TIS message structure!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_OUT_OF_MEMORY; - } - - // Invalidate and free hook observer. - CFRunLoopObserverInvalidate(hook->observer); - CFRelease(hook->observer); - } - else { - // We cant do a whole lot of anything if we cant - // create run loop observer. - logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopObserverCreate failure!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_CREATE_OBSERVER; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: CFRunLoopGetCurrent failure!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_GET_RUNLOOP; - } - - // Clean up the event source. - CFRelease(hook->source); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: CFMachPortCreateRunLoopSource failure!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE; - } - - // Stop the CFMachPort from receiving any more messages. - CFMachPortInvalidate(hook->port); - CFRelease(hook->port); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to create event port!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_CREATE_EVENT_PORT; - } - - // Free the hook structure. - free(hook); - } - else { - status = IOHOOK_ERROR_OUT_OF_MEMORY; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Accessibility API is disabled!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_AXAPI_DISABLED; - } - } while (restart_tap); - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Something, something, something, complete.\n", - __FUNCTION__, __LINE__); - - return status; -} - -IOHOOK_API int hook_stop() { - int status = IOHOOK_FAILURE; - - CFStringRef mode = CFRunLoopCopyCurrentMode(event_loop); - if (mode != NULL) { - CFRelease(mode); - - // Make sure the tap doesn't restart. - restart_tap = false; - - // Stop the run loop. - CFRunLoopStop(event_loop); - - status = IOHOOK_SUCCESS; - } - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Status: %#X.\n", - __FUNCTION__, __LINE__, status); - - return status; -} diff --git a/cdeps/hook/darwin/input.h b/cdeps/hook/darwin/input.h deleted file mode 100644 index 23977e5..0000000 --- a/cdeps/hook/darwin/input.h +++ /dev/null @@ -1,103 +0,0 @@ - -#ifndef _included_input_helper -#define _included_input_helper - -#include -#include // For HIToolbox kVK_ keycodes and TIS funcitons. -#ifdef USE_IOKIT - #include -#endif -#include - - -#ifndef USE_IOKIT -// Some of the system key codes that are needed from IOKit. -// #define NX_KEYTYPE_SOUND_UP 0x00 -// #define NX_KEYTYPE_SOUND_DOWN 0x01 -// #define NX_KEYTYPE_MUTE 0x07 - -/* Display controls... -#define NX_KEYTYPE_BRIGHTNESS_UP 0x02 -#define NX_KEYTYPE_BRIGHTNESS_DOWN 0x03 -#define NX_KEYTYPE_CONTRAST_UP 0x0B -#define NX_KEYTYPE_CONTRAST_DOWN 0x0C -#define NX_KEYTYPE_ILLUMINATION_UP 0x15 -#define NX_KEYTYPE_ILLUMINATION_DOWN 0x16 -#define NX_KEYTYPE_ILLUMINATION_TOGGLE 0x17 -*/ - -// #define NX_KEYTYPE_CAPS_LOCK 0x04 -// #define NX_KEYTYPE_HELP 0x05 -// #define NX_POWER_KEY 0x06 - -// #define NX_KEYTYPE_EJECT 0x0E -// #define NX_KEYTYPE_PLAY 0x10 -// #define NX_KEYTYPE_NEXT 0x12 -// #define NX_KEYTYPE_PREVIOUS 0x13 - -/* There is no official fast-forward or rewind scan code support.*/ -// #define NX_KEYTYPE_FAST 0x14 -// #define NX_KEYTYPE_REWIND 0x15 - -#endif - -// These virtual key codes do not appear to be defined anywhere by Apple. -#define kVK_NX_Power 0xE0 | NX_POWER_KEY /* 0xE6 */ -#define kVK_NX_Eject 0xE0 | NX_KEYTYPE_EJECT /* 0xEE */ - -#define kVK_MEDIA_Play 0xE0 | NX_KEYTYPE_PLAY /* 0xF0 */ -#define kVK_MEDIA_Next 0xE0 | NX_KEYTYPE_NEXT /* 0xF1 */ -#define kVK_MEDIA_Previous 0xE0 | NX_KEYTYPE_PREVIOUS /* 0xF2 */ - -#define kVK_RightCommand 0x36 -#define kVK_ContextMenu 0x6E // AKA kMenuPowerGlyph -#define kVK_Undefined 0xFF - -// These button codes do not appear to be defined anywhere by Apple. -#define kVK_LBUTTON kCGMouseButtonLeft -#define kVK_RBUTTON kCGMouseButtonRight -#define kVK_MBUTTON kCGMouseButtonCenter -#define kVK_XBUTTON1 3 -#define kVK_XBUTTON2 4 - -// These button masks do not appear to be defined anywhere by Apple. -#define kCGEventFlagMaskButtonLeft 1 << 0 -#define kCGEventFlagMaskButtonRight 1 << 1 -#define kCGEventFlagMaskButtonCenter 1 << 2 -#define kCGEventFlagMaskXButton1 1 << 3 -#define kCGEventFlagMaskXButton2 1 << 4 - - -/* Check for access to Apples accessibility API. - */ -extern bool is_accessibility_enabled(); - -/* Converts an OSX key code and event mask to the appropriate Unicode character - * representation. - */ -extern UniCharCount keycode_to_unicode(CGEventRef event_ref, UniChar *buffer, UniCharCount size); - -/* Converts an OSX keycode to the appropriate IOHook scancode constant. - */ -extern uint16_t keycode_to_scancode(UInt64 keycode); - -/* Converts a IOHook scancode constant to the appropriate OSX keycode. - */ -extern UInt64 scancode_to_keycode(uint16_t keycode); - - -/* Initialize items required for KeyCodeToKeySym() and KeySymToUnicode() - * functionality. This method is called by OnLibraryLoad() and may need to be - * called in combination with UnloadInputHelper() if the native keyboard layout - * is changed. - */ -extern void load_input_helper(); - -/* De-initialize items required for KeyCodeToKeySym() and KeySymToUnicode() - * functionality. This method is called by OnLibraryUnload() and may need to be - * called in combination with LoadInputHelper() if the native keyboard layout - * is changed. - */ -extern void unload_input_helper(); - -#endif diff --git a/cdeps/hook/darwin/input_c.h b/cdeps/hook/darwin/input_c.h deleted file mode 100644 index 298f67f..0000000 --- a/cdeps/hook/darwin/input_c.h +++ /dev/null @@ -1,542 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef USE_COREFOUNDATION - #include -#endif -#ifndef USE_WEAK_IMPORT - #include -#endif - -#include -#include "input.h" -#include "../iohook.h" -#include "../logger_c.h" - -// Current dead key state. -#if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION) -static UInt32 deadkey_state; -#endif - -// Input source data for the keyboard. -#if defined(USE_CARBON_LEGACY) -static KeyboardLayoutRef prev_keyboard_layout = NULL; -#elif defined(USE_COREFOUNDATION) -static TISInputSourceRef prev_keyboard_layout = NULL; -#endif - -#ifdef USE_WEAK_IMPORT -// Required to dynamically check for AXIsProcessTrustedWithOptions availability. -extern Boolean AXIsProcessTrustedWithOptions(CFDictionaryRef options) __attribute__((weak_import)); -extern CFStringRef kAXTrustedCheckOptionPrompt __attribute__((weak_import)); -#else -static Boolean (*AXIsProcessTrustedWithOptions_t)(CFDictionaryRef); -#endif - -bool is_accessibility_enabled() { - bool is_enabled = false; - - #ifdef USE_WEAK_IMPORT - // Check and make sure assistive devices is enabled. - if (AXIsProcessTrustedWithOptions != NULL) { - // New accessibility API 10.9 and later. - const void * keys[] = { kAXTrustedCheckOptionPrompt }; - const void * values[] = { kCFBooleanTrue }; - - CFDictionaryRef options = CFDictionaryCreate( - kCFAllocatorDefault, - keys, - values, - sizeof(keys) / sizeof(*keys), - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - is_enabled = AXIsProcessTrustedWithOptions(options); - } - #else - // Dynamically load the application services framework for examination. - *(void **) (&AXIsProcessTrustedWithOptions_t) = dlsym(RTLD_DEFAULT, "AXIsProcessTrustedWithOptions"); - const char *dlError = dlerror(); - if (AXIsProcessTrustedWithOptions_t != NULL && dlError == NULL) { - // Check for property CFStringRef kAXTrustedCheckOptionPrompt - void ** kAXTrustedCheckOptionPrompt_t = dlsym(RTLD_DEFAULT, "kAXTrustedCheckOptionPrompt"); - - dlError = dlerror(); - if (kAXTrustedCheckOptionPrompt_t != NULL && dlError == NULL) { - // New accessibility API 10.9 and later. - const void * keys[] = { *kAXTrustedCheckOptionPrompt_t }; - const void * values[] = { kCFBooleanTrue }; - - CFDictionaryRef options = CFDictionaryCreate( - kCFAllocatorDefault, - keys, - values, - sizeof(keys) / sizeof(*keys), - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - is_enabled = (*AXIsProcessTrustedWithOptions_t)(options); - } - } - #endif - else { - #ifndef USE_WEAK_IMPORT - if (dlError != NULL) { - // Could not load the AXIsProcessTrustedWithOptions function! - logger(LOG_LEVEL_DEBUG, "%s [%u]: %s.\n", - __FUNCTION__, __LINE__, dlError); - } - #endif - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Weak import AXIsProcessTrustedWithOptions not found.\n", - __FUNCTION__, __LINE__, dlError); - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Falling back to AXAPIEnabled().\n", - __FUNCTION__, __LINE__, dlError); - - // Old accessibility check 10.8 and older. - is_enabled = AXAPIEnabled(); - } - - return is_enabled; -} - - -UniCharCount keycode_to_unicode(CGEventRef event_ref, UniChar *buffer, UniCharCount size) { - UniCharCount count = 0; - - #if defined(USE_CARBON_LEGACY) - KeyboardLayoutRef curr_keyboard_layout; - void *inputData = NULL; - if (KLGetCurrentKeyboardLayout(&curr_keyboard_layout) == noErr) { - if (KLGetKeyboardLayoutProperty(curr_keyboard_layout, kKLuchrData, (const void **) &inputData) != noErr) { - inputData = NULL; - } - } - #elif defined(USE_COREFOUNDATION) - CFDataRef inputData = NULL; - if (CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain())) { - // NOTE The following block must execute on the main runloop, - // Ex: CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain()) to avoid - // Exception detected while handling key input and TSMProcessRawKeyCode failed - // (-192) errors. - TISInputSourceRef curr_keyboard_layout = TISCopyCurrentKeyboardLayoutInputSource(); - if (curr_keyboard_layout != NULL && CFGetTypeID(curr_keyboard_layout) == TISInputSourceGetTypeID()) { - CFDataRef data = (CFDataRef) TISGetInputSourceProperty(curr_keyboard_layout, kTISPropertyUnicodeKeyLayoutData); - if (data != NULL && CFGetTypeID(data) == CFDataGetTypeID() && CFDataGetLength(data) > 0) { - inputData = (CFDataRef) data; - } - } - - // Check if the keyboard layout has changed to see if the dead key state needs to be discarded. - if (prev_keyboard_layout != NULL && curr_keyboard_layout != NULL && CFEqual(curr_keyboard_layout, prev_keyboard_layout) == false) { - deadkey_state = 0x00; - } - - // Release the previous keyboard layout. - if (prev_keyboard_layout != NULL) { - CFRelease(prev_keyboard_layout); - prev_keyboard_layout = NULL; - } - - // Set the previous keyboard layout to the current layout. - if (curr_keyboard_layout != NULL) { - prev_keyboard_layout = curr_keyboard_layout; - } - } - #endif - - #if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION) - if (inputData != NULL) { - #ifdef USE_CARBON_LEGACY - const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *) inputData; - #else - const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout*) CFDataGetBytePtr(inputData); - #endif - - if (keyboard_layout != NULL) { - //Extract keycode and modifier information. - CGKeyCode keycode = CGEventGetIntegerValueField(event_ref, kCGKeyboardEventKeycode); - CGEventFlags modifiers = CGEventGetFlags(event_ref); - - // Disable all command modifiers for translation. This is required - // so UCKeyTranslate will provide a keysym for the separate event. - static const CGEventFlags cmd_modifiers = kCGEventFlagMaskCommand | - kCGEventFlagMaskControl | kCGEventFlagMaskAlternate; - modifiers &= ~cmd_modifiers; - - // I don't know why but UCKeyTranslate does not process the - // kCGEventFlagMaskAlphaShift (A.K.A. Caps Lock Mask) correctly. - // We need to basically turn off the mask and process the capital - // letters after UCKeyTranslate(). - bool is_caps_lock = modifiers & kCGEventFlagMaskAlphaShift; - modifiers &= ~kCGEventFlagMaskAlphaShift; - - // Run the translation with the saved deadkey_state. - OSStatus status = UCKeyTranslate( - keyboard_layout, - keycode, - kUCKeyActionDown, //kUCKeyActionDisplay, - (modifiers >> 16) & 0xFF, //(modifiers >> 16) & 0xFF, || (modifiers >> 8) & 0xFF, - LMGetKbdType(), - kNilOptions, //kNilOptions, //kUCKeyTranslateNoDeadKeysMask - &deadkey_state, - size, - &count, - buffer); - - if (status == noErr && count > 0) { - if (is_caps_lock) { - // We *had* a caps lock mask so we need to convert to uppercase. - CFMutableStringRef keytxt = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, buffer, count, size, kCFAllocatorNull); - if (keytxt != NULL) { - CFLocaleRef locale = CFLocaleCopyCurrent(); - CFStringUppercase(keytxt, locale); - CFRelease(locale); - CFRelease(keytxt); - } - else { - // There was an problem creating the CFMutableStringRef. - count = 0; - } - } - } - else { - // Make sure the buffer count is zero if an error occurred. - count = 0; - } - } - } - #else - CGEventKeyboardGetUnicodeString(event_ref, size, &count, buffer); - #endif - - // The following codes should not be processed because they are invalid. - if (count == 1) { - switch (buffer[0]) { - case 0x01: // Home - case 0x04: // End - case 0x05: // Help Key - case 0x10: // Function Keys - case 0x0B: // Page Up - case 0x0C: // Page Down - case 0x1F: // Volume Up - count = 0; - } - } - - return count; -} - - -static const uint16_t keycode_scancode_table[][2] = { - /* idx { keycode, scancode }, */ - /* 0 */ { VC_A, kVK_Undefined }, // 0x00 - /* 1 */ { VC_S, kVK_Escape }, // 0x01 - /* 2 */ { VC_D, kVK_ANSI_1 }, // 0x02 - /* 3 */ { VC_F, kVK_ANSI_2 }, // 0x03 - /* 4 */ { VC_H, kVK_ANSI_3 }, // 0x04 - /* 5 */ { VC_G, kVK_ANSI_4 }, // 0x05 - /* 6 */ { VC_Z, kVK_ANSI_5 }, // 0x07 - /* 7 */ { VC_X, kVK_ANSI_6 }, // 0x08 - /* 8 */ { VC_C, kVK_ANSI_7 }, // 0x09 - /* 9 */ { VC_V, kVK_ANSI_8 }, // 0x0A - /* 10 */ { VC_UNDEFINED, kVK_ANSI_9 }, // 0x0B - /* 11 */ { VC_B, kVK_ANSI_0 }, // 0x0C - /* 12 */ { VC_Q, kVK_ANSI_Minus }, // 0x0D - /* 13 */ { VC_W, kVK_ANSI_Equal }, // 0x0E - /* 14 */ { VC_E, kVK_Delete }, // 0x0F - /* 15 */ { VC_R, kVK_Tab }, // 0x10 - /* 16 */ { VC_Y, kVK_ANSI_Q }, // 0x11 - /* 17 */ { VC_T, kVK_ANSI_W }, // 0x12 - /* 18 */ { VC_1, kVK_ANSI_E }, // 0x13 - /* 19 */ { VC_2, kVK_ANSI_R }, // 0x14 - /* 20 */ { VC_3, kVK_ANSI_T }, // 0x15 - /* 21 */ { VC_4, kVK_ANSI_Y }, // 0x16 - /* 22 */ { VC_6, kVK_ANSI_U }, // 0x17 - /* 23 */ { VC_5, kVK_ANSI_I }, // 0x18 - /* 24 */ { VC_EQUALS, kVK_ANSI_O }, // 0x19 - /* 25 */ { VC_9, kVK_ANSI_P }, // 0x19 - /* 26 */ { VC_7, kVK_ANSI_LeftBracket }, // 0x1A - /* 27 */ { VC_MINUS, kVK_ANSI_RightBracket }, // 0x1B - /* 28 */ { VC_8, kVK_Return }, // 0x1C - /* 29 */ { VC_0, kVK_Control }, // 0x1D - /* 30 */ { VC_CLOSE_BRACKET, kVK_ANSI_A }, // 0x1E - /* 31 */ { VC_O, kVK_ANSI_S }, // 0x1F - /* 32 */ { VC_U, kVK_ANSI_D }, // 0x20 - /* 33 */ { VC_OPEN_BRACKET, kVK_ANSI_F }, // 0x21 - /* 34 */ { VC_I, kVK_ANSI_G }, // 0x22 - /* 35 */ { VC_P, kVK_ANSI_H }, // 0x23 - /* 36 */ { VC_ENTER, kVK_ANSI_J }, // 0x24 - /* 37 */ { VC_L, kVK_ANSI_K }, // 0x25 - /* 38 */ { VC_J, kVK_ANSI_L }, // 0x26 - /* 39 */ { VC_QUOTE, kVK_ANSI_Semicolon }, // 0x27 - /* 40 */ { VC_K, kVK_ANSI_Quote }, // 0x28 - /* 41 */ { VC_SEMICOLON, kVK_ANSI_Grave }, // 0x29 - /* 42 */ { VC_BACK_SLASH, kVK_Shift }, // 0x2A - /* 43 */ { VC_COMMA, kVK_ANSI_Backslash }, // 0x2B - /* 44 */ { VC_SLASH, kVK_ANSI_Z }, // 0x2C - /* 45 */ { VC_N, kVK_ANSI_X }, // 0x2D - /* 46 */ { VC_M, kVK_ANSI_C }, // 0x2E - /* 47 */ { VC_PERIOD, kVK_ANSI_V }, // 0x2F - /* 48 */ { VC_TAB, kVK_ANSI_B }, // 0x30 - /* 49 */ { VC_SPACE, kVK_ANSI_N }, // 0x31 - /* 50 */ { VC_BACKQUOTE, kVK_ANSI_M }, // 0x32 - /* 51 */ { VC_BACKSPACE, kVK_ANSI_Comma }, // 0x33 - /* 52 */ { VC_UNDEFINED, kVK_ANSI_Period }, // 0x34 - /* 53 */ { VC_ESCAPE, kVK_ANSI_Slash }, // 0x35 - /* 54 */ { VC_META_R, kVK_RightShift }, // 0x36 - /* 55 */ { VC_META_L, kVK_ANSI_KeypadMultiply }, // 0x37 - /* 56 */ { VC_SHIFT_L, kVK_Option }, // 0x38 - /* 57 */ { VC_CAPS_LOCK, kVK_Space }, // 0x39 - /* 58 */ { VC_ALT_L, kVK_CapsLock }, // 0x3A - /* 59 */ { VC_CONTROL_L, kVK_F1 }, // 0x3B - /* 60 */ { VC_SHIFT_R, kVK_F2 }, // 0x3C - /* 61 */ { VC_ALT_R, kVK_F3 }, // 0x3D - /* 62 */ { VC_CONTROL_R, kVK_F4 }, // 0x3E - /* 63 */ { VC_UNDEFINED, kVK_F5 }, // 0x3F - /* 64 */ { VC_F17, kVK_F6 }, // 0x40 - /* 65 */ { VC_KP_SEPARATOR, kVK_F7 }, // 0x41 - /* 66 */ { VC_UNDEFINED, kVK_F8 }, // 0x42 - /* 67 */ { VC_KP_MULTIPLY, kVK_F9 }, // 0x43 - /* 68 */ { VC_UNDEFINED, kVK_F10 }, // 0x44 - /* 69 */ { VC_KP_ADD, kVK_ANSI_KeypadClear }, // 0x45 - /* 70 */ { VC_UNDEFINED, kVK_Undefined }, // 0x46 - /* 71 */ { VC_NUM_LOCK, kVK_ANSI_Keypad7 }, // 0x47 - /* 72 */ { VC_VOLUME_UP, kVK_ANSI_Keypad8 }, // 0x48 - /* 73 */ { VC_VOLUME_DOWN, kVK_ANSI_Keypad9 }, // 0x49 - /* 74 */ { VC_VOLUME_MUTE, kVK_ANSI_KeypadMinus }, // 0x4A - /* 75 */ { VC_KP_DIVIDE, kVK_ANSI_Keypad4 }, // 0x4B - /* 76 */ { VC_KP_ENTER, kVK_ANSI_Keypad5 }, // 0x4C - /* 77 */ { VC_UNDEFINED, kVK_ANSI_Keypad6 }, // 0x4D - /* 78 */ { VC_KP_SUBTRACT, kVK_ANSI_KeypadPlus }, // 0x4E - /* 79 */ { VC_F18, kVK_ANSI_Keypad1 }, // 0x4F - /* 80 */ { VC_F19, kVK_ANSI_Keypad2 }, // 0x50 - /* 81 */ { VC_KP_EQUALS, kVK_ANSI_Keypad3 }, // 0x51 - /* 82 */ { VC_KP_0, kVK_ANSI_Keypad0 }, // 0x52 - /* 83 */ { VC_KP_1, kVK_ANSI_KeypadDecimal }, // 0x53 - /* 84 */ { VC_KP_2, kVK_Undefined }, // 0x54 - /* 85 */ { VC_KP_3, kVK_Undefined }, // 0x55 - /* 86 */ { VC_KP_4, kVK_Undefined }, // 0x56 - /* 87 */ { VC_KP_5, kVK_F11 }, // 0x57 - /* 88 */ { VC_KP_6, kVK_F12 }, // 0x58 - /* 89 */ { VC_KP_7, kVK_Undefined }, // 0x59 - /* 90 */ { VC_F20, kVK_Undefined }, // 0x5A - /* 91 */ { VC_KP_8, kVK_F13 }, // 0x5B - /* 92 */ { VC_KP_9, kVK_F14 }, // 0x5C - /* 93 */ { VC_YEN, kVK_F15 }, // 0x5D - /* 94 */ { VC_UNDERSCORE, kVK_Undefined }, // 0x5E - /* 95 */ { VC_KP_COMMA, kVK_Undefined }, // 0x5F - /* 96 */ { VC_F5, kVK_Undefined }, // 0x60 - /* 97 */ { VC_F6, kVK_Undefined }, // 0x61 - /* 98 */ { VC_F7, kVK_Undefined }, // 0x62 - /* 99 */ { VC_F3, kVK_F16 }, // 0x63 - /* 100 */ { VC_F8, kVK_F17 }, // 0x64 - /* 101 */ { VC_F9, kVK_F18 }, // 0x65 - /* 102 */ { VC_UNDEFINED, kVK_F19 }, // 0x66 - /* 103 */ { VC_F11, kVK_F20 }, // 0x67 - /* 104 */ { VC_KATAKANA, kVK_Undefined }, // 0x68 - /* 105 */ { VC_F13, kVK_Undefined }, // 0x69 - /* 106 */ { VC_F16, kVK_Undefined }, // 0x6A - /* 107 */ { VC_F14, kVK_Undefined }, // 0x6B - /* 108 */ { VC_UNDEFINED, kVK_Undefined }, // 0x6C FIXME kVK_JIS_Eisu same as Caps Lock ? - /* 109 */ { VC_F10, kVK_Undefined }, // 0x6D - /* 110 */ { VC_UNDEFINED, kVK_Undefined }, // 0x6E - /* 111 */ { VC_F12, kVK_Undefined }, // 0x6F - /* 112 */ { VC_UNDEFINED, kVK_JIS_Kana }, // 0x70 - /* 113 */ { VC_F15, kVK_Undefined }, // 0x71 - /* 114 */ { VC_INSERT, kVK_Undefined }, // 0x72 - /* 115 */ { VC_HOME, kVK_JIS_Underscore }, // 0x73 - /* 116 */ { VC_PAGE_UP, kVK_Undefined }, // 0x74 - /* 117 */ { VC_DELETE, kVK_Undefined }, // 0x75 - /* 118 */ { VC_F4, kVK_Undefined }, // 0x76 - /* 119 */ { VC_END, kVK_Undefined }, // 0x77 - /* 120 */ { VC_F2, kVK_Undefined }, // 0x78 - /* 121 */ { VC_PAGE_DOWN, kVK_Undefined }, // 0x79 - /* 122 */ { VC_F1, kVK_Undefined }, // 0x7A - /* 123 */ { VC_LEFT, kVK_Undefined }, // 0x7B - /* 124 */ { VC_RIGHT, kVK_Undefined }, // 0x7C - /* 125 */ { VC_DOWN, kVK_JIS_Yen }, // 0x7D - /* 126 */ { VC_UP, kVK_JIS_KeypadComma }, // 0x7E - /* 127 */ { VC_UNDEFINED, kVK_Undefined }, // 0x7F - - // No Offset Offset (i & 0x007F) + 128 - - /* 128 */ { VC_UNDEFINED, kVK_Undefined }, // 0x80 - /* 129 */ { VC_UNDEFINED, kVK_Undefined }, // 0x81 - /* 130 */ { VC_UNDEFINED, kVK_Undefined }, // 0x82 - /* 131 */ { VC_UNDEFINED, kVK_Undefined }, // 0x83 - /* 132 */ { VC_UNDEFINED, kVK_Undefined }, // 0x84 - /* 133 */ { VC_UNDEFINED, kVK_Undefined }, // 0x85 - /* 134 */ { VC_UNDEFINED, kVK_Undefined }, // 0x86 - /* 135 */ { VC_UNDEFINED, kVK_Undefined }, // 0x87 - /* 136 */ { VC_UNDEFINED, kVK_Undefined }, // 0x88 - /* 137 */ { VC_UNDEFINED, kVK_Undefined }, // 0x89 - /* 138 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8A - /* 139 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8B - /* 140 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8C - /* 141 */ { VC_UNDEFINED, kVK_ANSI_KeypadEquals }, // 0x8D - /* 142 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8E - /* 143 */ { VC_UNDEFINED, kVK_Undefined }, // 0x8F - /* 144 */ { VC_UNDEFINED, kVK_MEDIA_Previous }, // 0x90 - /* 145 */ { VC_UNDEFINED, kVK_Undefined }, // 0x91 - /* 146 */ { VC_UNDEFINED, kVK_Undefined }, // 0x92 - /* 147 */ { VC_UNDEFINED, kVK_Undefined }, // 0x93 - /* 148 */ { VC_UNDEFINED, kVK_Undefined }, // 0x94 - /* 149 */ { VC_UNDEFINED, kVK_Undefined }, // 0x95 - /* 150 */ { VC_UNDEFINED, kVK_Undefined }, // 0x96 - /* 151 */ { VC_UNDEFINED, kVK_Undefined }, // 0x97 - /* 152 */ { VC_UNDEFINED, kVK_Undefined }, // 0x98 - /* 153 */ { VC_UNDEFINED, kVK_MEDIA_Next }, // 0x99 - /* 154 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9A - /* 155 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9B - /* 156 */ { VC_UNDEFINED, kVK_ANSI_KeypadEnter }, // 0x9C - /* 157 */ { VC_UNDEFINED, kVK_RightControl }, // 0x9D - /* 158 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9E - /* 159 */ { VC_UNDEFINED, kVK_Undefined }, // 0x9F - /* 160 */ { VC_UNDEFINED, kVK_Mute }, // 0xA0 - /* 161 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA1 - /* 162 */ { VC_UNDEFINED, kVK_MEDIA_Play }, // 0xA2 - /* 163 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA3 - /* 164 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA4 - /* 165 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA5 - /* 166 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA6 - /* 167 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA7 - /* 168 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA8 - /* 169 */ { VC_UNDEFINED, kVK_Undefined }, // 0xA9 - /* 170 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAA - /* 171 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAB - /* 172 */ { VC_UNDEFINED, kVK_NX_Eject }, // 0xAC - /* 173 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAD - /* 174 */ { VC_UNDEFINED, kVK_VolumeDown }, // 0xAE - /* 175 */ { VC_UNDEFINED, kVK_Undefined }, // 0xAF - /* 176 */ { VC_UNDEFINED, kVK_VolumeUp }, // 0xB0 - /* 177 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB1 - /* 178 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB2 - /* 179 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB3 - /* 180 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB4 - /* 181 */ { VC_UNDEFINED, kVK_ANSI_KeypadDivide }, // 0xB5 - /* 182 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB6 - /* 183 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB7 - /* 184 */ { VC_UNDEFINED, kVK_RightOption }, // 0xB8 - /* 185 */ { VC_UNDEFINED, kVK_Undefined }, // 0xB9 - /* 186 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBA - /* 187 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBB - /* 188 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBC - /* 189 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBD - /* 190 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBE - /* 191 */ { VC_UNDEFINED, kVK_Undefined }, // 0xBF - /* 192 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC0 - /* 193 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC1 - /* 194 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC2 - /* 195 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC3 - /* 196 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC4 - /* 197 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC5 - /* 198 */ { VC_UNDEFINED, kVK_Undefined }, // 0xC6 - /* 199 */ { VC_UNDEFINED, kVK_Home }, // 0xC7 - /* 200 */ { VC_UNDEFINED, kVK_UpArrow }, // 0xC8 - /* 201 */ { VC_UNDEFINED, kVK_PageUp }, // 0xC9 - /* 202 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCA - /* 203 */ { VC_UNDEFINED, kVK_LeftArrow }, // 0xCB - /* 204 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCC - /* 205 */ { VC_UNDEFINED, kVK_RightArrow }, // 0xCD - /* 206 */ { VC_UNDEFINED, kVK_Undefined }, // 0xCE - /* 207 */ { VC_UNDEFINED, kVK_End }, // 0xCF - /* 208 */ { VC_UNDEFINED, kVK_DownArrow }, // 0xD0 - /* 209 */ { VC_UNDEFINED, kVK_PageDown }, // 0xD1 - /* 210 */ { VC_UNDEFINED, kVK_Help }, // 0xD2 - /* 211 */ { VC_UNDEFINED, kVK_ForwardDelete }, // 0xD3 - /* 212 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD4 - /* 213 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD5 - /* 214 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD6 - /* 215 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD7 - /* 216 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD8 - /* 217 */ { VC_UNDEFINED, kVK_Undefined }, // 0xD9 - /* 218 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDA - /* 219 */ { VC_UNDEFINED, kVK_Command }, // 0xDB - /* 220 */ { VC_UNDEFINED, kVK_RightCommand }, // 0xDC - /* 221 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDD - /* 222 */ { VC_UNDEFINED, kVK_NX_Power }, // 0xDE - /* 223 */ { VC_UNDEFINED, kVK_Undefined }, // 0xDF - /* 224 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE0 - /* 225 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE1 - /* 226 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE2 - /* 227 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE3 - /* 228 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE4 - /* 229 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE5 - /* 230 */ { VC_POWER, kVK_Undefined }, // 0xE6 - /* 231 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE7 - /* 232 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE8 - /* 233 */ { VC_UNDEFINED, kVK_Undefined }, // 0xE9 - /* 234 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEA - /* 235 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEB - /* 236 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEC - /* 237 */ { VC_UNDEFINED, kVK_Undefined }, // 0xED - /* 238 */ { VC_MEDIA_EJECT, kVK_Undefined }, // 0xEE - /* 239 */ { VC_UNDEFINED, kVK_Undefined }, // 0xEF - /* 240 */ { VC_MEDIA_PLAY, kVK_Undefined }, // 0xF0 - /* 241 */ { VC_MEDIA_NEXT, kVK_Undefined }, // 0xF1 - /* 242 */ { VC_MEDIA_PREVIOUS, kVK_Undefined }, // 0xF2 - /* 243 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF3 - /* 244 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF4 - /* 245 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF5 - /* 246 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF6 - /* 247 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF7 - /* 248 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF8 - /* 249 */ { VC_UNDEFINED, kVK_Undefined }, // 0xF9 - /* 250 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFA - /* 251 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFB - /* 252 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFC - /* 253 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFD - /* 254 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFE - /* 255 */ { VC_UNDEFINED, kVK_Undefined }, // 0xFF -}; - -uint16_t keycode_to_scancode(UInt64 keycode) { - uint16_t scancode = VC_UNDEFINED; - - // Bound check 0 <= keycode < 256 - if (keycode < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[0])) { - scancode = keycode_scancode_table[keycode][0]; - } - - return scancode; -} - -UInt64 scancode_to_keycode(uint16_t scancode) { - UInt64 keycode = kVK_Undefined; - - // Bound check 0 <= keycode < 128 - if (scancode < 128) { - keycode = keycode_scancode_table[scancode][1]; - } - else { - // Calculate the upper offset. - unsigned short i = (scancode & 0x007F) | 0x80; - - if (i < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[1])) { - keycode = keycode_scancode_table[i][1]; - } - } - - return keycode; -} - -void load_input_helper() { - #if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION) - // Start with a fresh dead key state. - //curr_deadkey_state = 0; - #endif -} - -void unload_input_helper() { - #if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION) - if (prev_keyboard_layout != NULL) { - // Cleanup tracking of the previous layout. - CFRelease(prev_keyboard_layout); - prev_keyboard_layout = NULL; - } - #endif -} diff --git a/cdeps/hook/darwin/properties_c.h b/cdeps/hook/darwin/properties_c.h deleted file mode 100644 index 0a7679c..0000000 --- a/cdeps/hook/darwin/properties_c.h +++ /dev/null @@ -1,522 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef USE_CARBON_LEGACY - #include -#endif -#ifdef USE_COREFOUNDATION - #include -#endif -#ifdef USE_IOKIT - #include - #include -#endif - -#include -#include "../iohook.h" -#include "input.h" -// #include "../logger_c.h" - -IOHOOK_API screen_data* hook_create_screen_info(unsigned char *count) { - CGError status = kCGErrorFailure; - screen_data* screens = NULL; - - // Initialize count to zero. - *count = 0; - - // Allocate memory to hold each display id. We will just allocate our MAX - // because its only about 1K of memory. - // TODO This can probably be realistically cut to something like 16 or 32.... - // If you have more than 32 monitors, send me a picture and make a donation ;) - CGDirectDisplayID *display_ids = malloc(sizeof(CGDirectDisplayID) * UCHAR_MAX); - if (display_ids != NULL) { - // NOTE Pass UCHAR_MAX to make sure uint32_t doesn't overflow uint8_t. - // TOOD Test/Check whether CGGetOnlineDisplayList is more suitable... - status = CGGetActiveDisplayList(UCHAR_MAX, display_ids, (uint32_t *) count); - - // If there is no error and at least one monitor. - if (status == kCGErrorSuccess && *count > 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: CGGetActiveDisplayList: %li.\n", - __FUNCTION__, __LINE__, *count); - - // Allocate memory for the number of screens found. - screens = malloc(sizeof(screen_data) * (*count)); - if (screens != NULL) { - uint8_t i; - for (i = 0; i < *count; i++) { - //size_t width = CGDisplayPixelsWide(display_ids[i]); - //size_t height = CGDisplayPixelsHigh(display_ids[i]); - CGRect boundsDisp = CGDisplayBounds(display_ids[i]); - if (boundsDisp.size.width > 0 && boundsDisp.size.height > 0) { - screens[i] = (screen_data) { - .number = i + 1, - //TODO: make sure we follow the same convention for the origin - //in all other platform implementations (upper-left) - //TODO: document the approach with examples in order to show different - //cases -> different resolutions (secondary monitors origin might be - //negative) - .x = boundsDisp.origin.x, - .y = boundsDisp.origin.y, - .width = boundsDisp.size.width, - .height = boundsDisp.size.height - }; - } - } - } - } - else { - logger(LOG_LEVEL_INFO, "%s [%u]: multiple_get_screen_info failed: %ld. Fallback.\n", - __FUNCTION__, __LINE__, status); - - size_t width = CGDisplayPixelsWide(CGMainDisplayID()); - size_t height = CGDisplayPixelsHigh(CGMainDisplayID()); - - if (width > 0 && height > 0) { - screens = malloc(sizeof(screen_data)); - - if (screens != NULL) { - *count = 1; - screens[0] = (screen_data) { - .number = 1, - .x = 0, - .y = 0, - .width = width, - .height = height - }; - } - } - } - - // Free the id's after we are done. - free(display_ids); - } - - return screens; -} - -/* - * Apple's documentation is not very good. I was finally able to find this - * information after many hours of googling. Value is the slider value in the - * system preferences. That value * 15 is the rate in MS. 66 / the value is the - * chars per second rate. - * - * Value MS Char/Sec - * - * 1 15 66 * Out of standard range * - * - * 2 30 33 - * 6 90 11 - * 12 180 5.5 - * 30 450 2.2 - * 60 900 1.1 - * 90 1350 0.73 - * 120 1800 0.55 - * - * V = MS / 15 - * V = 66 / CharSec - * - * MS = V * 15 - * MS = (66 / CharSec) * 15 - * - * CharSec = 66 / V - * CharSec = 66 / (MS / 15) - */ - -IOHOOK_API long int hook_get_auto_repeat_rate() { - #if defined USE_IOKIT || defined USE_COREFOUNDATION || defined USE_CARBON_LEGACY - bool successful = false; - SInt64 rate; - #endif - - long int value = -1; - - #ifdef USE_IOKIT - if (!successful) { - io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass)); - if (service) { - kern_return_t kren_ret = kIOReturnError; - io_connect_t connection; - - kren_ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &connection); - if (kren_ret == kIOReturnSuccess) { - IOByteCount size = sizeof(rate); - - kren_ret = IOHIDGetParameter(connection, CFSTR(kIOHIDKeyRepeatKey), (IOByteCount) sizeof(rate), &rate, &size); - if (kren_ret == kIOReturnSuccess) { - /* This is in some undefined unit of time that if we happen - * to multiply by 900 gives us the time in milliseconds. We - * add 0.5 to the result so that when we cast to long we - * actually get a rounded result. Saves the math.h depend. - * - * 33,333,333.0 / 1000.0 / 1000.0 / 1000.0 == 0.033333333 * Fast * - * 100,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 0.1 - * 200,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 0.2 - * 500,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 0.5 - * 1,000,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 1 - * 1,500,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 1.5 - * 2,000,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 2 * Slow * - */ - value = (long) (900.0 * ((double) rate) / 1000.0 / 1000.0 / 1000.0 + 0.5); - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: IOHIDGetParameter: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - } - #endif - - #ifdef USE_COREFOUNDATION - if (!successful) { - CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("KeyRepeat"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (pref_val != NULL && CFGetTypeID(pref_val) == CFNumberGetTypeID()) { - if (CFNumberGetValue((CFNumberRef) pref_val, kCFNumberSInt32Type, &rate)) { - // This is the slider value, we must multiply by 15 to convert to milliseconds. - value = (long) rate * 15; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: CFPreferencesCopyValue: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - #endif - - #ifdef USE_CARBON_LEGACY - if (!successful) { - // Apple documentation states that value is in 'ticks'. I am not sure - // what that means, but it looks a lot like the arbitrary slider value. - rate = LMGetKeyRepThresh(); - if (rate > -1) { - /* This is the slider value, we must multiply by 15 to convert to - * milliseconds. - */ - value = (long) rate * 15; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: LMGetKeyRepThresh: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - #endif - - return value; -} - -IOHOOK_API long int hook_get_auto_repeat_delay() { - #if defined USE_IOKIT || defined USE_COREFOUNDATION || defined USE_CARBON_LEGACY - bool successful = false; - SInt64 delay; - #endif - - long int value = -1; - - #ifdef USE_IOKIT - if (!successful) { - io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass)); - if (service) { - kern_return_t kren_ret = kIOReturnError; - io_connect_t connection; - - kren_ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &connection); - if (kren_ret == kIOReturnSuccess) { - IOByteCount size = sizeof(delay); - - kren_ret = IOHIDGetParameter(connection, CFSTR(kIOHIDInitialKeyRepeatKey), (IOByteCount) sizeof(delay), &delay, &size); - if (kren_ret == kIOReturnSuccess) { - /* This is in some undefined unit of time that if we happen - * to multiply by 900 gives us the time in milliseconds. We - * add 0.5 to the result so that when we cast to long we - * actually get a rounded result. Saves the math.h depend. - * - * 33,333,333.0 / 1000.0 / 1000.0 / 1000.0 == 0.033333333 * Fast * - * 100,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 0.1 - * 200,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 0.2 - * 500,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 0.5 - * 1,000,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 1 - * 1,500,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 1.5 - * 2,000,000,000.0 / 1000.0 / 1000.0 / 1000.0 == 2 * Slow * - */ - value = (long) (900.0 * ((double) delay) / 1000.0 / 1000.0 / 1000.0 + 0.5); - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: IOHIDGetParameter: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - } - #endif - - #ifdef USE_COREFOUNDATION - if (!successful) { - CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("InitialKeyRepeat"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (pref_val != NULL && CFGetTypeID(pref_val) == CFNumberGetTypeID()) { - if (CFNumberGetValue((CFNumberRef) pref_val, kCFNumberSInt32Type, &delay)) { - // This is the slider value, we must multiply by 15 to convert to - // milliseconds. - value = (long) delay * 15; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: CFPreferencesCopyValue: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - #endif - - #ifdef USE_CARBON_LEGACY - if (!successful) { - // Apple documentation states that value is in 'ticks'. I am not sure - // what that means, but it looks a lot like the arbitrary slider value. - delay = LMGetKeyThresh(); - if (delay > -1) { - // This is the slider value, we must multiply by 15 to convert to - // milliseconds. - value = (long) delay * 15; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: LMGetKeyThresh: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - #endif - - return value; -} - -IOHOOK_API long int hook_get_pointer_acceleration_multiplier() { - #if defined USE_IOKIT || defined USE_COREFOUNDATION - bool successful = false; - double multiplier; - #endif - - long int value = -1; - - #ifdef USE_IOKIT - if (!successful) { - io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass)); - - if (service) { - kern_return_t kren_ret = kIOReturnError; - io_connect_t connection; - - kren_ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &connection); - if (kren_ret == kIOReturnSuccess) { - // IOByteCount size = sizeof(multiplier); - - kren_ret = IOHIDGetAccelerationWithKey(connection, CFSTR(kIOHIDMouseAccelerationType), &multiplier); - if (kren_ret == kIOReturnSuccess) { - // Calculate the greatest common factor. - - unsigned long denominator = 1000000, d = denominator; - unsigned long numerator = multiplier * denominator, gcf = numerator; - - while (d != 0) { - unsigned long i = gcf % d; - gcf = d; - d = i; - } - - value = denominator / gcf; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: IOHIDGetAccelerationWithKey: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - } - #endif - - #ifdef USE_COREFOUNDATION - if (!successful) { - CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("com.apple.mouse.scaling"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (pref_val != NULL && CFGetTypeID(pref_val) == CFNumberGetTypeID()) { - if (CFNumberGetValue((CFNumberRef) pref_val, kCFNumberSInt32Type, &multiplier)) { - value = (long) multiplier; - - logger(LOG_LEVEL_INFO, "%s [%u]: CFPreferencesCopyValue: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - #endif - - return value; -} - -IOHOOK_API long int hook_get_pointer_acceleration_threshold() { - #if defined USE_COREFOUNDATION - bool successful = false; - SInt32 threshold; - #endif - - long int value = -1; - - #ifdef USE_COREFOUNDATION - if (!successful) { - CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("mouseDriverMaxSpeed"), CFSTR("com.apple.universalaccess"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (pref_val != NULL && CFGetTypeID(pref_val) == CFNumberGetTypeID()) { - if (CFNumberGetValue((CFNumberRef) pref_val, kCFNumberSInt32Type, &threshold)) { - value = (long) threshold; - - logger(LOG_LEVEL_INFO, "%s [%u]: CFPreferencesCopyValue: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - #endif - - return value; -} - -IOHOOK_API long int hook_get_pointer_sensitivity() { - #ifdef USE_IOKIT - bool successful = false; - double sensitivity; - #endif - - long int value = -1; - - #ifdef USE_IOKIT - if (!successful) { - io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass)); - - if (service) { - kern_return_t kren_ret = kIOReturnError; - io_connect_t connection; - - kren_ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &connection); - if (kren_ret == kIOReturnSuccess) { - // IOByteCount size = sizeof(multiplier); - - kren_ret = IOHIDGetAccelerationWithKey(connection, CFSTR(kIOHIDMouseAccelerationType), &sensitivity); - if (kren_ret == kIOReturnSuccess) { - // Calculate the greatest common factor. - - unsigned long denominator = 1000000, d = denominator; - unsigned long numerator = sensitivity * denominator, gcf = numerator; - - while (d != 0) { - unsigned long i = gcf % d; - gcf = d; - d = i; - } - - value = numerator / gcf; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: IOHIDGetAccelerationWithKey: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - } - #endif - - return value; -} - -IOHOOK_API long int hook_get_multi_click_time() { - #if defined USE_IOKIT || defined USE_COREFOUNDATION || defined USE_CARBON_LEGACY - bool successful = false; - #if defined USE_IOKIT || defined USE_CARBON_LEGACY - // This needs to be defined only if we have USE_IOKIT or USE_CARBON_LEGACY. - SInt64 time; - #endif - #endif - - long int value = -1; - - #ifdef USE_IOKIT - if (!successful) { - io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass)); - if (service) { - kern_return_t kren_ret = kIOReturnError; - io_connect_t connection; - - kren_ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &connection); - if (kren_ret == kIOReturnSuccess) { - IOByteCount size = sizeof(time); - - kren_ret = IOHIDGetParameter(connection, CFSTR(kIOHIDClickTimeKey), (IOByteCount) sizeof(time), &time, &size); - if (kren_ret == kIOReturnSuccess) { - /* This is in some undefined unit of time that if we happen - * to multiply by 900 gives us the time in milliseconds. We - * add 0.5 to the result so that when we cast to long we - * actually get a rounded result. Saves the math.h depend. - */ - value = (long) (900.0 * ((double) time) / 1000.0 / 1000.0 / 1000.0 + 0.5); - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: IOHIDGetParameter: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - } - #endif - - #ifdef USE_COREFOUNDATION - if (!successful) { - Float32 clicktime; - CFTypeRef pref_val = CFPreferencesCopyValue(CFSTR("com.apple.mouse.doubleClickThreshold"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (pref_val != NULL && CFGetTypeID(pref_val) == CFNumberGetTypeID()) { - if (CFNumberGetValue((CFNumberRef) pref_val, kCFNumberFloat32Type, &clicktime)) { - /* This is in some undefined unit of time that if we happen - * to multiply by 900 gives us the time in milliseconds. It is - * completely possible that this value is in seconds and should be - * multiplied by 1000 but because IOKit values are undocumented and - * I have no idea what a Carbon 'tick' is so there really is no way - * to confirm this. - */ - value = (long) (clicktime * 900); - - logger(LOG_LEVEL_INFO, "%s [%u]: CFPreferencesCopyValue: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - } - #endif - - #ifdef USE_CARBON_LEGACY - if (!successful) { - // Apple documentation states that value is in 'ticks'. I am not sure - // what that means, but it looks a lot like the arbitrary slider value. - time = GetDblTime(); - if (time > -1) { - // This is the slider value, we must multiply by 15 to convert to - // milliseconds. - value = (long) time * 15; - successful = true; - - logger(LOG_LEVEL_INFO, "%s [%u]: GetDblTime: %li.\n", - __FUNCTION__, __LINE__, value); - } - } - #endif - - return value; -} - - -// Create a shared object constructor. -__attribute__ ((constructor)) -void on_library_load() { - // Initialize Native Input Functions. - load_input_helper(); -} - -// Create a shared object destructor. -__attribute__ ((destructor)) -void on_library_unload() { - // Disable the event hook. - //hook_stop(); - - // Cleanup native input functions. - unload_input_helper(); -} diff --git a/cdeps/hook/iohook.h b/cdeps/hook/iohook.h deleted file mode 100644 index db0ba8b..0000000 --- a/cdeps/hook/iohook.h +++ /dev/null @@ -1,441 +0,0 @@ - -#ifndef __IOHOOK_H -#define __IOHOOK_H - -// #include "../../base/os.h" -#include -#include -#include - -/* Begin Error Codes */ -#define IOHOOK_SUCCESS 0x00 -#define IOHOOK_FAILURE 0x01 - -// System level errors. -#define IOHOOK_ERROR_OUT_OF_MEMORY 0x02 - -// Unix specific errors. -#define IOHOOK_ERROR_X_OPEN_DISPLAY 0x20 -#define IOHOOK_ERROR_X_RECORD_NOT_FOUND 0x21 -#define IOHOOK_ERROR_X_RECORD_ALLOC_RANGE 0x22 -#define IOHOOK_ERROR_X_RECORD_CREATE_CONTEXT 0x23 -#define IOHOOK_ERROR_X_RECORD_ENABLE_CONTEXT 0x24 -#define IOHOOK_ERROR_X_RECORD_GET_CONTEXT 0x25 - -// Windows specific errors. -#define IOHOOK_ERROR_SET_WINDOWS_HOOK_EX 0x30 -#define IOHOOK_ERROR_GET_MODULE_HANDLE 0x31 - -// Darwin specific errors. -#define IOHOOK_ERROR_AXAPI_DISABLED 0x40 -#define IOHOOK_ERROR_CREATE_EVENT_PORT 0x41 -#define IOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE 0x42 -#define IOHOOK_ERROR_GET_RUNLOOP 0x43 -#define IOHOOK_ERROR_CREATE_OBSERVER 0x44 -/* End Error Codes */ - -/* Begin Log Levels and Function Prototype */ -typedef enum _log_level { - LOG_LEVEL_DEBUG = 1, - LOG_LEVEL_INFO, - LOG_LEVEL_WARN, - LOG_LEVEL_ERROR -} log_level; - -// Logger callback function prototype. -typedef bool (*logger_t)(unsigned int, const char *, ...); -/* End Log Levels and Function Prototype */ - -/* Begin Virtual Event Types and Data Structures */ -typedef enum _event_type { - EVENT_HOOK_ENABLED = 1, - EVENT_HOOK_DISABLED, - EVENT_KEY_TYPED, - EVENT_KEY_PRESSED, - EVENT_KEY_RELEASED, - EVENT_MOUSE_CLICKED, - EVENT_MOUSE_PRESSED, - EVENT_MOUSE_RELEASED, - EVENT_MOUSE_MOVED, - EVENT_MOUSE_DRAGGED, - EVENT_MOUSE_WHEEL -} event_type; - -typedef struct _screen_data { - uint8_t number; - int16_t x; - int16_t y; - uint16_t width; - uint16_t height; -} screen_data; - -typedef struct _keyboard_event_data { - uint16_t keycode; - uint16_t rawcode; - uint16_t keychar; - // char *keychar; -} keyboard_event_data, - key_pressed_event_data, - key_released_event_data, - key_typed_event_data; - -typedef struct _mouse_event_data { - uint16_t button; - uint16_t clicks; - int16_t x; - int16_t y; -} mouse_event_data, - mouse_pressed_event_data, - mouse_released_event_data, - mouse_clicked_event_data; - -typedef struct _mouse_wheel_event_data { - uint16_t clicks; - int16_t x; - int16_t y; - uint8_t type; - uint16_t amount; - int16_t rotation; - uint8_t direction; -} mouse_wheel_event_data; - -typedef struct _iohook_event { - event_type type; - uint64_t time; - uint16_t mask; - uint16_t reserved; - union { - keyboard_event_data keyboard; - mouse_event_data mouse; - mouse_wheel_event_data wheel; - } data; -} iohook_event; - -typedef void (*dispatcher_t)(iohook_event *const); -/* End Virtual Event Types and Data Structures */ - - -/* Begin Virtual Key Codes */ -#define VC_ESCAPE 0x0001 - -// Begin Function Keys -#define VC_F1 0x003B -#define VC_F2 0x003C -#define VC_F3 0x003D -#define VC_F4 0x003E -#define VC_F5 0x003F -#define VC_F6 0x0040 -#define VC_F7 0x0041 -#define VC_F8 0x0042 -#define VC_F9 0x0043 -#define VC_F10 0x0044 -#define VC_F11 0x0057 -#define VC_F12 0x0058 - -#define VC_F13 0x005B -#define VC_F14 0x005C -#define VC_F15 0x005D -#define VC_F16 0x0063 -#define VC_F17 0x0064 -#define VC_F18 0x0065 -#define VC_F19 0x0066 -#define VC_F20 0x0067 -#define VC_F21 0x0068 -#define VC_F22 0x0069 -#define VC_F23 0x006A -#define VC_F24 0x006B -// End Function Keys - - -// Begin Alphanumeric Zone -#define VC_BACKQUOTE 0x0029 - -#define VC_1 0x0002 -#define VC_2 0x0003 -#define VC_3 0x0004 -#define VC_4 0x0005 -#define VC_5 0x0006 -#define VC_6 0x0007 -#define VC_7 0x0008 -#define VC_8 0x0009 -#define VC_9 0x000A -#define VC_0 0x000B - -#define VC_MINUS 0x000C // '-' -#define VC_EQUALS 0x000D // '=' -#define VC_BACKSPACE 0x000E - -#define VC_TAB 0x000F -#define VC_CAPS_LOCK 0x003A - -#define VC_A 0x001E -#define VC_B 0x0030 -#define VC_C 0x002E -#define VC_D 0x0020 -#define VC_E 0x0012 -#define VC_F 0x0021 -#define VC_G 0x0022 -#define VC_H 0x0023 -#define VC_I 0x0017 -#define VC_J 0x0024 -#define VC_K 0x0025 -#define VC_L 0x0026 -#define VC_M 0x0032 -#define VC_N 0x0031 -#define VC_O 0x0018 -#define VC_P 0x0019 -#define VC_Q 0x0010 -#define VC_R 0x0013 -#define VC_S 0x001F -#define VC_T 0x0014 -#define VC_U 0x0016 -#define VC_V 0x002F -#define VC_W 0x0011 -#define VC_X 0x002D -#define VC_Y 0x0015 -#define VC_Z 0x002C - -#define VC_OPEN_BRACKET 0x001A // '[' -#define VC_CLOSE_BRACKET 0x001B // ']' -#define VC_BACK_SLASH 0x002B // '\' - -#define VC_SEMICOLON 0x0027 // ';' -#define VC_QUOTE 0x0028 -#define VC_ENTER 0x001C - -#define VC_COMMA 0x0033 // ',' -#define VC_PERIOD 0x0034 // '.' -#define VC_SLASH 0x0035 // '/' - -#define VC_SPACE 0x0039 -// End Alphanumeric Zone - - -#define VC_PRINTSCREEN 0x0E37 -#define VC_SCROLL_LOCK 0x0046 -#define VC_PAUSE 0x0E45 - - -// Begin Edit Key Zone -#define VC_INSERT 0x0E52 -#define VC_DELETE 0x0E53 -#define VC_HOME 0x0E47 -#define VC_END 0x0E4F -#define VC_PAGE_UP 0x0E49 -#define VC_PAGE_DOWN 0x0E51 -// End Edit Key Zone - - -// Begin Cursor Key Zone -#define VC_UP 0xE048 -#define VC_LEFT 0xE04B -#define VC_CLEAR 0xE04C -#define VC_RIGHT 0xE04D -#define VC_DOWN 0xE050 -// End Cursor Key Zone - - -// Begin Numeric Zone -#define VC_NUM_LOCK 0x0045 -#define VC_KP_DIVIDE 0x0E35 -#define VC_KP_MULTIPLY 0x0037 -#define VC_KP_SUBTRACT 0x004A -#define VC_KP_EQUALS 0x0E0D -#define VC_KP_ADD 0x004E -#define VC_KP_ENTER 0x0E1C -#define VC_KP_SEPARATOR 0x0053 - -#define VC_KP_1 0x004F -#define VC_KP_2 0x0050 -#define VC_KP_3 0x0051 -#define VC_KP_4 0x004B -#define VC_KP_5 0x004C -#define VC_KP_6 0x004D -#define VC_KP_7 0x0047 -#define VC_KP_8 0x0048 -#define VC_KP_9 0x0049 -#define VC_KP_0 0x0052 - -#define VC_KP_END 0xEE00 | VC_KP_1 -#define VC_KP_DOWN 0xEE00 | VC_KP_2 -#define VC_KP_PAGE_DOWN 0xEE00 | VC_KP_3 -#define VC_KP_LEFT 0xEE00 | VC_KP_4 -#define VC_KP_CLEAR 0xEE00 | VC_KP_5 -#define VC_KP_RIGHT 0xEE00 | VC_KP_6 -#define VC_KP_HOME 0xEE00 | VC_KP_7 -#define VC_KP_UP 0xEE00 | VC_KP_8 -#define VC_KP_PAGE_UP 0xEE00 | VC_KP_9 -#define VC_KP_INSERT 0xEE00 | VC_KP_0 -#define VC_KP_DELETE 0xEE00 | VC_KP_SEPARATOR -// End Numeric Zone - - -// Begin Modifier and Control Keys -#define VC_SHIFT_L 0x002A -#define VC_SHIFT_R 0x0036 -#define VC_CONTROL_L 0x001D -#define VC_CONTROL_R 0x0E1D -#define VC_ALT_L 0x0038 // Option or Alt Key -#define VC_ALT_R 0x0E38 // Option or Alt Key -#define VC_META_L 0x0E5B // Windows or Command Key -#define VC_META_R 0x0E5C // Windows or Command Key -#define VC_CONTEXT_MENU 0x0E5D -// End Modifier and Control Keys - - -// Begin Media Control Keys -#define VC_POWER 0xE05E -#define VC_SLEEP 0xE05F -#define VC_WAKE 0xE063 - -#define VC_MEDIA_PLAY 0xE022 -#define VC_MEDIA_STOP 0xE024 -#define VC_MEDIA_PREVIOUS 0xE010 -#define VC_MEDIA_NEXT 0xE019 -#define VC_MEDIA_SELECT 0xE06D -#define VC_MEDIA_EJECT 0xE02C - -#define VC_VOLUME_MUTE 0xE020 -#define VC_VOLUME_UP 0xE030 -#define VC_VOLUME_DOWN 0xE02E - -#define VC_APP_MAIL 0xE06C -#define VC_APP_CALCULATOR 0xE021 -#define VC_APP_MUSIC 0xE03C -#define VC_APP_PICTURES 0xE064 - -#define VC_BROWSER_SEARCH 0xE065 -#define VC_BROWSER_HOME 0xE032 -#define VC_BROWSER_BACK 0xE06A -#define VC_BROWSER_FORWARD 0xE069 -#define VC_BROWSER_STOP 0xE068 -#define VC_BROWSER_REFRESH 0xE067 -#define VC_BROWSER_FAVORITES 0xE066 -// End Media Control Keys - -// Begin Japanese Language Keys -#define VC_KATAKANA 0x0070 -#define VC_UNDERSCORE 0x0073 -#define VC_FURIGANA 0x0077 -#define VC_KANJI 0x0079 -#define VC_HIRAGANA 0x007B -#define VC_YEN 0x007D -#define VC_KP_COMMA 0x007E -// End Japanese Language Keys - -// Begin Sun keyboards -#define VC_SUN_HELP 0xFF75 - -#define VC_SUN_STOP 0xFF78 -#define VC_SUN_PROPS 0xFF76 -#define VC_SUN_FRONT 0xFF77 -#define VC_SUN_OPEN 0xFF74 -#define VC_SUN_FIND 0xFF7E -#define VC_SUN_AGAIN 0xFF79 -#define VC_SUN_UNDO 0xFF7A -#define VC_SUN_COPY 0xFF7C -#define VC_SUN_INSERT 0xFF7D -#define VC_SUN_CUT 0xFF7B -// End Sun keyboards - -#define VC_UNDEFINED 0x0000 // KeyCode Unknown - -#define CHAR_UNDEFINED 0xFFFF // CharCode Unknown -/* End Virtual Key Codes */ - - -/* Begin Virtual Modifier Masks */ -#define MASK_SHIFT_L 1 << 0 -#define MASK_CTRL_L 1 << 1 -#define MASK_META_L 1 << 2 -#define MASK_ALT_L 1 << 3 - -#define MASK_SHIFT_R 1 << 4 -#define MASK_CTRL_R 1 << 5 -#define MASK_META_R 1 << 6 -#define MASK_ALT_R 1 << 7 - -#define MASK_SHIFT MASK_SHIFT_L | MASK_SHIFT_R -#define MASK_CTRL MASK_CTRL_L | MASK_CTRL_R -#define MASK_META MASK_META_L | MASK_META_R -#define MASK_ALT MASK_ALT_L | MASK_ALT_R - -#define MASK_BUTTON1 1 << 8 -#define MASK_BUTTON2 1 << 9 -#define MASK_BUTTON3 1 << 10 -#define MASK_BUTTON4 1 << 11 -#define MASK_BUTTON5 1 << 12 - -#define MASK_NUM_LOCK 1 << 13 -#define MASK_CAPS_LOCK 1 << 14 -#define MASK_SCROLL_LOCK 1 << 15 -/* End Virtual Modifier Masks */ - - -/* Begin Virtual Mouse Buttons */ -#define MOUSE_NOBUTTON 0 // Any Button -#define MOUSE_BUTTON1 1 // Left Button -#define MOUSE_BUTTON2 2 // Right Button -#define MOUSE_BUTTON3 3 // Middle Button -#define MOUSE_BUTTON4 4 // Extra Mouse Button -#define MOUSE_BUTTON5 5 // Extra Mouse Button - -#define WHEEL_UNIT_SCROLL 1 -#define WHEEL_BLOCK_SCROLL 2 - -#define WHEEL_VERTICAL_DIRECTION 3 -#define WHEEL_HORIZONTAL_DIRECTION 4 -/* End Virtual Mouse Buttons */ - - -#ifdef _WIN32 -#define IOHOOK_API __declspec(dllexport) -#else -#define IOHOOK_API -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - // Set the logger callback functions. - IOHOOK_API void hook_set_logger_proc(logger_t logger_proc); - - // Send a virtual event back to the system. - IOHOOK_API void hook_post_event(iohook_event * const event); - - // Set the event callback function. - IOHOOK_API void hook_set_dispatch_proc(dispatcher_t dispatch_proc); - - // Insert the event hook. - IOHOOK_API int hook_run(); - - // Withdraw the event hook. - IOHOOK_API int hook_stop(); - - // Retrieves an array of screen data for each available monitor. - IOHOOK_API screen_data* hook_create_screen_info(unsigned char *count); - - // Retrieves the keyboard auto repeat rate. - IOHOOK_API long int hook_get_auto_repeat_rate(); - - // Retrieves the keyboard auto repeat delay. - IOHOOK_API long int hook_get_auto_repeat_delay(); - - // Retrieves the mouse acceleration multiplier. - IOHOOK_API long int hook_get_pointer_acceleration_multiplier(); - - // Retrieves the mouse acceleration threshold. - IOHOOK_API long int hook_get_pointer_acceleration_threshold(); - - // Retrieves the mouse sensitivity. - IOHOOK_API long int hook_get_pointer_sensitivity(); - - // Retrieves the double/triple click interval. - IOHOOK_API long int hook_get_multi_click_time(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/cdeps/hook/logger.h b/cdeps/hook/logger.h deleted file mode 100644 index 0314e0f..0000000 --- a/cdeps/hook/logger.h +++ /dev/null @@ -1,15 +0,0 @@ - -#ifndef _included_logger -#define _included_logger - -#include "iohook.h" -#include - -#ifndef __FUNCTION__ -#define __FUNCTION__ __func__ -#endif - -// logger(level, message) -extern logger_t logger; - -#endif diff --git a/cdeps/hook/logger_c.h b/cdeps/hook/logger_c.h deleted file mode 100644 index 8752245..0000000 --- a/cdeps/hook/logger_c.h +++ /dev/null @@ -1,53 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include -#include -#include - -#include "iohook.h" -#include "logger.h" - -static bool default_logger(unsigned int level, const char *format, ...) { - bool status = false; - - #ifndef USE_QUIET - va_list args; - switch (level) { - #ifdef USE_DEBUG - case LOG_LEVEL_DEBUG: - #endif - 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; - } - #endif - - return status; -} - -// Current logger function pointer, this should never be null. -// FIXME This should be static and wrapped with a public facing function. -logger_t logger = &default_logger; - - -IOHOOK_API void hookSetlogger(logger_t logger_proc) { - if (logger_proc == NULL) { - logger = &default_logger; - } - else { - logger = logger_proc; - } -} diff --git a/cdeps/hook/windows/event_c.h b/cdeps/hook/windows/event_c.h deleted file mode 100644 index 2eb51f6..0000000 --- a/cdeps/hook/windows/event_c.h +++ /dev/null @@ -1,328 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include "../iohook.h" -#include - -// #include "logger.h" -#include "input.h" - -// Some buggy versions of MinGW and MSys do not include these constants in winuser.h. -#ifndef MAPVK_VK_TO_VSC -#define MAPVK_VK_TO_VSC 0 -#define MAPVK_VSC_TO_VK 1 -#define MAPVK_VK_TO_CHAR 2 -#define MAPVK_VSC_TO_VK_EX 3 -#endif -// Some buggy versions of MinGW and MSys only define this value for Windows -// versions >= 0x0600 (Windows Vista) when it should be 0x0500 (Windows 2000). -#ifndef MAPVK_VK_TO_VSC_EX -#define MAPVK_VK_TO_VSC_EX 4 -#endif - -#ifndef KEYEVENTF_SCANCODE -#define KEYEVENTF_EXTENDEDKEY 0x0001 -#define KEYEVENTF_KEYUP 0x0002 -#define KEYEVENTF_UNICODE 0x0004 -#define KEYEVENTF_SCANCODE 0x0008 -#endif - -#ifndef KEYEVENTF_KEYDOWN -#define KEYEVENTF_KEYDOWN 0x0000 -#endif - -#define MAX_WINDOWS_COORD_VALUE 65535 - -static UINT keymask_lookup[8] = { - VK_LSHIFT, - VK_LCONTROL, - VK_LWIN, - VK_LMENU, - - VK_RSHIFT, - VK_RCONTROL, - VK_RWIN, - VK_RMENU -}; - -IOHOOK_API void hook_post_event(iohook_event * const event) { - //FIXME implement multiple monitor support - uint16_t screen_width = GetSystemMetrics( SM_CXSCREEN ); - uint16_t screen_height = GetSystemMetrics( SM_CYSCREEN ); - - unsigned char events_size = 0, events_max = 28; - INPUT *events = malloc(sizeof(INPUT) * events_max); - - if (event->mask & (MASK_SHIFT | MASK_CTRL | MASK_META | MASK_ALT)) { - unsigned int i; - for (i = 0; i < sizeof(keymask_lookup) / sizeof(UINT); i++) { - if (event->mask & 1 << i) { - events[events_size].type = INPUT_KEYBOARD; - events[events_size].ki.wVk = keymask_lookup[i]; - events[events_size].ki.dwFlags = KEYEVENTF_KEYDOWN; - events[events_size].ki.time = 0; // Use current system time. - events_size++; - } - } - } - - if (event->mask & (MASK_BUTTON1 | MASK_BUTTON2 | MASK_BUTTON3 | MASK_BUTTON4 | MASK_BUTTON5)) { - events[events_size].type = INPUT_MOUSE; - events[events_size].mi.dx = 0; // Relative mouse movement due to - events[events_size].mi.dy = 0; // MOUSEEVENTF_ABSOLUTE not being set. - events[events_size].mi.mouseData = 0x00; - events[events_size].mi.time = 0; // Use current system time. - - if (event->mask & MASK_BUTTON1) { - events[events_size].mi.mouseData |= MOUSEEVENTF_LEFTDOWN; - } - - if (event->mask & MASK_BUTTON2) { - events[events_size].mi.mouseData |= MOUSEEVENTF_RIGHTDOWN; - } - - if (event->mask & MASK_BUTTON3) { - events[events_size].mi.mouseData |= MOUSEEVENTF_MIDDLEDOWN; - } - - if (event->mask & MASK_BUTTON4) { - events[events_size].mi.mouseData = XBUTTON1; - events[events_size].mi.mouseData |= MOUSEEVENTF_XDOWN; - } - - if (event->mask & MASK_BUTTON5) { - events[events_size].mi.mouseData = XBUTTON2; - events[events_size].mi.dwFlags |= MOUSEEVENTF_XDOWN; - } - - events_size++; - } - - - switch (event->type) { - case EVENT_KEY_PRESSED: - events[events_size].ki.wVk = scancode_to_keycode(event->data.keyboard.keycode); - if (events[events_size].ki.wVk != 0x0000) { - events[events_size].type = INPUT_KEYBOARD; - events[events_size].ki.dwFlags = KEYEVENTF_KEYDOWN; // |= KEYEVENTF_SCANCODE; - events[events_size].ki.wScan = 0; // event->data.keyboard.keycode; - events[events_size].ki.time = 0; // GetSystemTime() - events_size++; - } - else { - logger(LOG_LEVEL_INFO, "%s [%u]: Unable to lookup scancode: %li\n", - __FUNCTION__, __LINE__, - event->data.keyboard.keycode); - } - break; - - case EVENT_KEY_RELEASED: - events[events_size].ki.wVk = scancode_to_keycode(event->data.keyboard.keycode); - if (events[events_size].ki.wVk != 0x0000) { - events[events_size].type = INPUT_KEYBOARD; - events[events_size].ki.dwFlags = KEYEVENTF_KEYUP; // |= KEYEVENTF_SCANCODE; - events[events_size].ki.wVk = scancode_to_keycode(event->data.keyboard.keycode); - events[events_size].ki.wScan = 0; // event->data.keyboard.keycode; - events[events_size].ki.time = 0; // GetSystemTime() - events_size++; - } - else { - logger(LOG_LEVEL_INFO, "%s [%u]: Unable to lookup scancode: %li\n", - __FUNCTION__, __LINE__, - event->data.keyboard.keycode); - } - break; - - - case EVENT_MOUSE_PRESSED: - events[events_size].type = INPUT_MOUSE; - events[events_size].mi.dwFlags = MOUSEEVENTF_XDOWN; - - switch (event->data.mouse.button) { - case MOUSE_BUTTON1: - events[events_size].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; - break; - - case MOUSE_BUTTON2: - events[events_size].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; - break; - - case MOUSE_BUTTON3: - events[events_size].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; - break; - - case MOUSE_BUTTON4: - events[events_size].mi.mouseData = XBUTTON1; - break; - - case MOUSE_BUTTON5: - events[events_size].mi.mouseData = XBUTTON2; - break; - - default: - // Extra buttons. - if (event->data.mouse.button > 3) { - events[events_size].mi.mouseData = event->data.mouse.button - 3; - } - } - - events[events_size].mi.dx = event->data.mouse.x * (MAX_WINDOWS_COORD_VALUE / screen_width) + 1; - events[events_size].mi.dy = event->data.mouse.y * (MAX_WINDOWS_COORD_VALUE / screen_height) + 1; - - events[events_size].mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - events[events_size].mi.time = 0; // GetSystemTime() - - events_size++; - break; - - case EVENT_MOUSE_RELEASED: - events[events_size].type = INPUT_MOUSE; - events[events_size].mi.dwFlags = MOUSEEVENTF_XUP; - - switch (event->data.mouse.button) { - case MOUSE_BUTTON1: - events[events_size].mi.dwFlags = MOUSEEVENTF_LEFTUP; - break; - - case MOUSE_BUTTON2: - events[events_size].mi.dwFlags = MOUSEEVENTF_RIGHTUP; - break; - - case MOUSE_BUTTON3: - events[events_size].mi.dwFlags = MOUSEEVENTF_MIDDLEUP; - break; - - case MOUSE_BUTTON4: - events[events_size].mi.mouseData = XBUTTON1; - break; - - case MOUSE_BUTTON5: - events[events_size].mi.mouseData = XBUTTON2; - break; - - default: - // Extra buttons. - if (event->data.mouse.button > 3) { - events[events_size].mi.mouseData = event->data.mouse.button - 3; - } - } - - events[events_size].mi.dx = event->data.mouse.x * (MAX_WINDOWS_COORD_VALUE / screen_width) + 1; - events[events_size].mi.dy = event->data.mouse.y * (MAX_WINDOWS_COORD_VALUE / screen_height) + 1; - - events[events_size].mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - events[events_size].mi.time = 0; // GetSystemTime() - events_size++; - break; - - - case EVENT_MOUSE_WHEEL: - events[events_size].type = INPUT_MOUSE; - events[events_size].mi.dwFlags = MOUSEEVENTF_WHEEL; - - // type, amount and rotation? - events[events_size].mi.mouseData = event->data.wheel.amount * event->data.wheel.rotation * WHEEL_DELTA; - - events[events_size].mi.dx = event->data.wheel.x * (MAX_WINDOWS_COORD_VALUE / screen_width) + 1; - events[events_size].mi.dy = event->data.wheel.y * (MAX_WINDOWS_COORD_VALUE / screen_height) + 1; - - events[events_size].mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - events[events_size].mi.time = 0; // GetSystemTime() - events_size++; - break; - - - case EVENT_MOUSE_DRAGGED: - // The button masks are all applied with the modifier masks. - - case EVENT_MOUSE_MOVED: - events[events_size].type = INPUT_MOUSE; - events[events_size].mi.dwFlags = MOUSEEVENTF_MOVE; - - events[events_size].mi.dx = event->data.mouse.x * (MAX_WINDOWS_COORD_VALUE / screen_width) + 1; - events[events_size].mi.dy = event->data.mouse.y * (MAX_WINDOWS_COORD_VALUE / screen_height) + 1; - - events[events_size].mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - events[events_size].mi.time = 0; // GetSystemTime() - events_size++; - break; - - - case EVENT_MOUSE_CLICKED: - case EVENT_KEY_TYPED: - // Ignore clicked and typed events. - - case EVENT_HOOK_ENABLED: - case EVENT_HOOK_DISABLED: - // Ignore hook enabled / disabled events. - - default: - // Ignore any other garbage. - logger(LOG_LEVEL_WARN, "%s [%u]: Ignoring post event type %#X\n", - __FUNCTION__, __LINE__, event->type); - break; - } - - // Release the previously held modifier keys used to fake the event mask. - if (event->mask & (MASK_SHIFT | MASK_CTRL | MASK_META | MASK_ALT)) { - unsigned int i; - for (i = 0; i < sizeof(keymask_lookup) / sizeof(UINT); i++) { - if (event->mask & 1 << i) { - events[events_size].type = INPUT_KEYBOARD; - events[events_size].ki.wVk = keymask_lookup[i]; - events[events_size].ki.dwFlags = KEYEVENTF_KEYUP; - events[events_size].ki.time = 0; // Use current system time. - events_size++; - } - } - } - - if (event->mask & (MASK_BUTTON1 | MASK_BUTTON2 | MASK_BUTTON3 | MASK_BUTTON4 | MASK_BUTTON5)) { - events[events_size].type = INPUT_MOUSE; - events[events_size].mi.dx = 0; // Relative mouse movement due to - events[events_size].mi.dy = 0; // MOUSEEVENTF_ABSOLUTE not being set. - events[events_size].mi.mouseData = 0x00; - events[events_size].mi.time = 0; // Use current system time. - - // If dwFlags does not contain MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, - // then mouseData should be zero. - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273%28v=vs.85%29.aspx - if (event->mask & MASK_BUTTON1) { - events[events_size].mi.dwFlags |= MOUSEEVENTF_LEFTUP; - } - - if (event->mask & MASK_BUTTON2) { - events[events_size].mi.dwFlags |= MOUSEEVENTF_RIGHTUP; - } - - if (event->mask & MASK_BUTTON3) { - events[events_size].mi.dwFlags |= MOUSEEVENTF_MIDDLEUP; - } - - if (event->mask & MASK_BUTTON4) { - events[events_size].mi.mouseData = XBUTTON1; - events[events_size].mi.dwFlags |= MOUSEEVENTF_XUP; - } - - if (event->mask & MASK_BUTTON5) { - events[events_size].mi.mouseData = XBUTTON2; - events[events_size].mi.dwFlags |= MOUSEEVENTF_XUP; - } - - events_size++; - } - - // Create the key release input - // memcpy(key_events + 1, key_events, sizeof(INPUT)); - // key_events[1].ki.dwFlags |= KEYEVENTF_KEYUP; - - if (! SendInput(events_size, events, sizeof(INPUT)) ) { - logger(LOG_LEVEL_ERROR, "%s [%u]: SendInput() failed! (%#lX)\n", - __FUNCTION__, __LINE__, (unsigned long) GetLastError()); - } - - free(events); -} diff --git a/cdeps/hook/windows/hook_c.h b/cdeps/hook/windows/hook_c.h deleted file mode 100644 index ed15515..0000000 --- a/cdeps/hook/windows/hook_c.h +++ /dev/null @@ -1,747 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include - -#include "../iohook.h" -#include "input.h" -// #include "logger.h" - -// Thread and hook handles. -static DWORD hook_thread_id = 0; -static HHOOK keyboard_event_hhook = NULL, mouse_event_hhook = NULL; -static HWINEVENTHOOK win_event_hhook = NULL; - -// The handle to the DLL module pulled in DllMain on DLL_PROCESS_ATTACH. -extern HINSTANCE hInst; - -// Modifiers for tracking key masks. -static unsigned short int current_modifiers = 0x0000; - -// Click count globals. -static unsigned short click_count = 0; -static DWORD click_time = 0; -static unsigned short int click_button = MOUSE_NOBUTTON; -static POINT last_click; - -// Static event memory. -static iohook_event event; - -// Event dispatch callback. -static dispatcher_t dispatcher = NULL; - -IOHOOK_API void hook_set_dispatch_proc(dispatcher_t dispatch_proc) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Setting new dispatch callback to %#p.\n", - __FUNCTION__, __LINE__, dispatch_proc); - - dispatcher = dispatch_proc; -} - -// Send out an event if a dispatcher was set. -static inline void dispatch_event(iohook_event *const event) { - if (dispatcher != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Dispatching event type %u.\n", - __FUNCTION__, __LINE__, event->type); - - dispatcher(event); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: No dispatch callback set!\n", - __FUNCTION__, __LINE__); - } -} - - -// Set the native modifier mask for future events. -static inline void set_modifier_mask(unsigned short int mask) { - current_modifiers |= mask; -} - -// Unset the native modifier mask for future events. -static inline void unset_modifier_mask(unsigned short int mask) { - current_modifiers ^= mask; -} - -// Get the current native modifier mask state. -static inline unsigned short int get_modifiers() { - return current_modifiers; -} - -// Initialize the modifier mask to the current modifiers. -static void initialize_modifiers() { - current_modifiers = 0x0000; - - // NOTE We are checking the high order bit, so it will be < 0 for a singed short. - if (GetKeyState(VK_LSHIFT) < 0) { set_modifier_mask(MASK_SHIFT_L); } - if (GetKeyState(VK_RSHIFT) < 0) { set_modifier_mask(MASK_SHIFT_R); } - if (GetKeyState(VK_LCONTROL) < 0) { set_modifier_mask(MASK_CTRL_L); } - if (GetKeyState(VK_RCONTROL) < 0) { set_modifier_mask(MASK_CTRL_R); } - if (GetKeyState(VK_LMENU) < 0) { set_modifier_mask(MASK_ALT_L); } - if (GetKeyState(VK_RMENU) < 0) { set_modifier_mask(MASK_ALT_R); } - if (GetKeyState(VK_LWIN) < 0) { set_modifier_mask(MASK_META_L); } - if (GetKeyState(VK_RWIN) < 0) { set_modifier_mask(MASK_META_R); } - - if (GetKeyState(VK_LBUTTON) < 0) { set_modifier_mask(MASK_BUTTON1); } - if (GetKeyState(VK_RBUTTON) < 0) { set_modifier_mask(MASK_BUTTON2); } - if (GetKeyState(VK_MBUTTON) < 0) { set_modifier_mask(MASK_BUTTON3); } - if (GetKeyState(VK_XBUTTON1) < 0) { set_modifier_mask(MASK_BUTTON4); } - if (GetKeyState(VK_XBUTTON2) < 0) { set_modifier_mask(MASK_BUTTON5); } - - if (GetKeyState(VK_NUMLOCK) < 0) { set_modifier_mask(MASK_NUM_LOCK); } - if (GetKeyState(VK_CAPITAL) < 0) { set_modifier_mask(MASK_CAPS_LOCK); } - if (GetKeyState(VK_SCROLL) < 0) { set_modifier_mask(MASK_SCROLL_LOCK); } -} - - -/* Retrieves the mouse wheel scroll type. This function cannot be included as - * part of the input.h due to platform specific calling restrictions. - */ -static unsigned short int get_scroll_wheel_type() { - unsigned short int value; - UINT wheel_type; - - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheel_type, 0); - if (wheel_type == WHEEL_PAGESCROLL) { - value = WHEEL_BLOCK_SCROLL; - } - else { - value = WHEEL_UNIT_SCROLL; - } - - return value; -} - -/* Retrieves the mouse wheel scroll amount. This function cannot be included as - * part of the input.h due to platform specific calling restrictions. - */ -static unsigned short int get_scroll_wheel_amount() { - unsigned short int value; - UINT wheel_amount; - - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheel_amount, 0); - if (wheel_amount == WHEEL_PAGESCROLL) { - value = 1; - } - else { - value = (unsigned short int) wheel_amount; - } - - return value; -} - -void unregister_running_hooks() { - // Stop the event hook and any timer still running. - if (win_event_hhook != NULL) { - UnhookWinEvent(win_event_hhook); - win_event_hhook = NULL; - } - - // Destroy the native hooks. - if (keyboard_event_hhook != NULL) { - UnhookWindowsHookEx(keyboard_event_hhook); - keyboard_event_hhook = NULL; - } - - if (mouse_event_hhook != NULL) { - UnhookWindowsHookEx(mouse_event_hhook); - mouse_event_hhook = NULL; - } -} - -void hook_start_proc() { - // Get the local system time in UNIX epoch form. - uint64_t timestamp = GetMessageTime(); - - // Populate the hook start event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_HOOK_ENABLED; - event.mask = 0x00; - - // Fire the hook start event. - dispatch_event(&event); -} - -void hook_stop_proc() { - // Get the local system time in UNIX epoch form. - uint64_t timestamp = GetMessageTime(); - - // Populate the hook stop event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_HOOK_DISABLED; - event.mask = 0x00; - - // Fire the hook stop event. - dispatch_event(&event); -} - -static void process_key_pressed(KBDLLHOOKSTRUCT *kbhook) { - // Check and setup modifiers. - if (kbhook->vkCode == VK_LSHIFT) { set_modifier_mask(MASK_SHIFT_L); } - else if (kbhook->vkCode == VK_RSHIFT) { set_modifier_mask(MASK_SHIFT_R); } - else if (kbhook->vkCode == VK_LCONTROL) { set_modifier_mask(MASK_CTRL_L); } - else if (kbhook->vkCode == VK_RCONTROL) { set_modifier_mask(MASK_CTRL_R); } - else if (kbhook->vkCode == VK_LMENU) { set_modifier_mask(MASK_ALT_L); } - else if (kbhook->vkCode == VK_RMENU) { set_modifier_mask(MASK_ALT_R); } - else if (kbhook->vkCode == VK_LWIN) { set_modifier_mask(MASK_META_L); } - else if (kbhook->vkCode == VK_RWIN) { set_modifier_mask(MASK_META_R); } - else if (kbhook->vkCode == VK_NUMLOCK) { set_modifier_mask(MASK_NUM_LOCK); } - else if (kbhook->vkCode == VK_CAPITAL) { set_modifier_mask(MASK_CAPS_LOCK); } - else if (kbhook->vkCode == VK_SCROLL) { set_modifier_mask(MASK_SCROLL_LOCK); } - - // Populate key pressed event. - event.time = kbhook->time; - event.reserved = 0x00; - - event.type = EVENT_KEY_PRESSED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = keycode_to_scancode(kbhook->vkCode, kbhook->flags); - event.data.keyboard.rawcode = kbhook->vkCode; - event.data.keyboard.keychar = CHAR_UNDEFINED; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X pressed. (%#X)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, event.data.keyboard.rawcode); - - // Populate key pressed event. - dispatch_event(&event); - - // If the pressed event was not consumed... - if (event.reserved ^ 0x01) { - // Buffer for unicode typed chars. No more than 2 needed. - WCHAR buffer[2]; // = { WCH_NONE }; - - // If the pressed event was not consumed and a unicode char exists... - SIZE_T count = keycode_to_unicode(kbhook->vkCode, buffer, sizeof(buffer)); - unsigned int i; - for (i = 0; i < count; i++) { - // Populate key typed event. - event.time = kbhook->time; - event.reserved = 0x00; - - event.type = EVENT_KEY_TYPED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = VC_UNDEFINED; - event.data.keyboard.rawcode = kbhook->vkCode; - event.data.keyboard.keychar = buffer[i]; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X typed. (%lc)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, (wint_t) event.data.keyboard.keychar); - - // Fire key typed event. - dispatch_event(&event); - } - } -} - -static void process_key_released(KBDLLHOOKSTRUCT *kbhook) { - // Check and setup modifiers. - if (kbhook->vkCode == VK_LSHIFT) { unset_modifier_mask(MASK_SHIFT_L); } - else if (kbhook->vkCode == VK_RSHIFT) { unset_modifier_mask(MASK_SHIFT_R); } - else if (kbhook->vkCode == VK_LCONTROL) { unset_modifier_mask(MASK_CTRL_L); } - else if (kbhook->vkCode == VK_RCONTROL) { unset_modifier_mask(MASK_CTRL_R); } - else if (kbhook->vkCode == VK_LMENU) { unset_modifier_mask(MASK_ALT_L); } - else if (kbhook->vkCode == VK_RMENU) { unset_modifier_mask(MASK_ALT_R); } - else if (kbhook->vkCode == VK_LWIN) { unset_modifier_mask(MASK_META_L); } - else if (kbhook->vkCode == VK_RWIN) { unset_modifier_mask(MASK_META_R); } - else if (kbhook->vkCode == VK_NUMLOCK) { unset_modifier_mask(MASK_NUM_LOCK); } - else if (kbhook->vkCode == VK_CAPITAL) { unset_modifier_mask(MASK_CAPS_LOCK); } - else if (kbhook->vkCode == VK_SCROLL) { unset_modifier_mask(MASK_SCROLL_LOCK); } - - // Populate key pressed event. - event.time = kbhook->time; - event.reserved = 0x00; - - event.type = EVENT_KEY_RELEASED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = keycode_to_scancode(kbhook->vkCode, kbhook->flags); - event.data.keyboard.rawcode = kbhook->vkCode; - event.data.keyboard.keychar = CHAR_UNDEFINED; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X released. (%#X)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, event.data.keyboard.rawcode); - - // Fire key released event. - dispatch_event(&event); -} - -LRESULT CALLBACK keyboard_hook_event_proc(int nCode, WPARAM wParam, LPARAM lParam) { - KBDLLHOOKSTRUCT *kbhook = (KBDLLHOOKSTRUCT *) lParam; - switch (wParam) { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - process_key_pressed(kbhook); - break; - - case WM_KEYUP: - case WM_SYSKEYUP: - process_key_released(kbhook); - break; - - default: - // In theory this *should* never execute. - logger(LOG_LEVEL_DEBUG, "%s [%u]: Unhandled Windows keyboard event: %#X.\n", - __FUNCTION__, __LINE__, (unsigned int) wParam); - break; - } - - LRESULT hook_result = -1; - if (nCode < 0 || event.reserved ^ 0x01) { - hook_result = CallNextHookEx(keyboard_event_hhook, nCode, wParam, lParam); - } - else { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Consuming the current event. (%li)\n", - __FUNCTION__, __LINE__, (long) hook_result); - } - - return hook_result; -} - - -static void process_button_pressed(MSLLHOOKSTRUCT *mshook, uint16_t button) { - uint64_t timestamp = GetMessageTime(); - - // Track the number of clicks, the button must match the previous button. - if (button == click_button && (long int) (timestamp - click_time) <= hook_get_multi_click_time()) { - if (click_count < USHRT_MAX) { - click_count++; - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: Click count overflow detected!\n", - __FUNCTION__, __LINE__); - } - } - else { - // Reset the click count. - click_count = 1; - - // Set the previous button. - click_button = button; - } - - // Save this events time to calculate the click_count. - click_time = timestamp; - - // Store the last click point. - last_click.x = mshook->pt.x; - last_click.y = mshook->pt.y; - - // Populate mouse pressed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_PRESSED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = click_count; - - event.data.mouse.x = mshook->pt.x; - event.data.mouse.y = mshook->pt.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u pressed %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse pressed event. - dispatch_event(&event); -} - -static void process_button_released(MSLLHOOKSTRUCT *mshook, uint16_t button) { - // Populate mouse released event. - event.time = GetMessageTime(); - event.reserved = 0x00; - - event.type = EVENT_MOUSE_RELEASED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = click_count; - - event.data.mouse.x = mshook->pt.x; - event.data.mouse.y = mshook->pt.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u released %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, - event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse released event. - dispatch_event(&event); - - // If the pressed event was not consumed... - if (event.reserved ^ 0x01 && last_click.x == mshook->pt.x && last_click.y == mshook->pt.y) { - // Populate mouse clicked event. - event.time = GetMessageTime(); - event.reserved = 0x00; - - event.type = EVENT_MOUSE_CLICKED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = click_count; - event.data.mouse.x = mshook->pt.x; - event.data.mouse.y = mshook->pt.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u clicked %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse clicked event. - dispatch_event(&event); - } - - // Reset the number of clicks. - if (button == click_button && (long int) (event.time - click_time) > hook_get_multi_click_time()) { - // Reset the click count. - click_count = 0; - } -} - -static void process_mouse_moved(MSLLHOOKSTRUCT *mshook) { - uint64_t timestamp = GetMessageTime(); - - // We received a mouse move event with the mouse actually moving. - // This verifies that the mouse was moved after being depressed. - if (last_click.x != mshook->pt.x || last_click.y != mshook->pt.y) { - // Reset the click count. - if (click_count != 0 && (long) (timestamp - click_time) > hook_get_multi_click_time()) { - click_count = 0; - } - - // Populate mouse move event. - event.time = timestamp; - event.reserved = 0x00; - - event.mask = get_modifiers(); - - // Check the modifier mask range for MASK_BUTTON1 - 5. - bool mouse_dragged = event.mask & (MASK_BUTTON1 | MASK_BUTTON2 | MASK_BUTTON3 | MASK_BUTTON4 | MASK_BUTTON5); - if (mouse_dragged) { - // Create Mouse Dragged event. - event.type = EVENT_MOUSE_DRAGGED; - } - else { - // Create a Mouse Moved event. - event.type = EVENT_MOUSE_MOVED; - } - - event.data.mouse.button = MOUSE_NOBUTTON; - event.data.mouse.clicks = click_count; - event.data.mouse.x = mshook->pt.x; - event.data.mouse.y = mshook->pt.y; - - logger(LOG_LEVEL_INFO, "%s [%u]: Mouse %s to %u, %u.\n", - __FUNCTION__, __LINE__, mouse_dragged ? "dragged" : "moved", - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse move event. - dispatch_event(&event); - } -} - -static void process_mouse_wheel(MSLLHOOKSTRUCT *mshook, uint8_t direction) { - // Track the number of clicks. - // Reset the click count and previous button. - click_count = 1; - click_button = MOUSE_NOBUTTON; - - // Populate mouse wheel event. - event.time = GetMessageTime(); - event.reserved = 0x00; - - event.type = EVENT_MOUSE_WHEEL; - event.mask = get_modifiers(); - - event.data.wheel.clicks = click_count; - event.data.wheel.x = mshook->pt.x; - event.data.wheel.y = mshook->pt.y; - - event.data.wheel.type = get_scroll_wheel_type(); - event.data.wheel.amount = get_scroll_wheel_amount(); - - /* Delta HIWORD(mshook->mouseData) - * A positive value indicates that the wheel was rotated - * forward, away from the user; a negative value indicates that - * the wheel was rotated backward, toward the user. One wheel - * click is defined as WHEEL_DELTA, which is 120. */ - event.data.wheel.rotation = ((int16_t) HIWORD(mshook->mouseData) / WHEEL_DELTA) * -1; - - // Set the direction based on what event was received. - event.data.wheel.direction = direction; - - logger(LOG_LEVEL_INFO, "%s [%u]: Mouse wheel type %u, rotated %i units in the %u direction at %u, %u.\n", - __FUNCTION__, __LINE__, event.data.wheel.type, - event.data.wheel.amount * event.data.wheel.rotation, - event.data.wheel.direction, - event.data.wheel.x, event.data.wheel.y); - - // Fire mouse wheel event. - dispatch_event(&event); -} - -LRESULT CALLBACK mouse_hook_event_proc(int nCode, WPARAM wParam, LPARAM lParam) { - MSLLHOOKSTRUCT *mshook = (MSLLHOOKSTRUCT *) lParam; - switch (wParam) { - case WM_LBUTTONDOWN: - set_modifier_mask(MASK_BUTTON1); - process_button_pressed(mshook, MOUSE_BUTTON1); - break; - - case WM_RBUTTONDOWN: - set_modifier_mask(MASK_BUTTON2); - process_button_pressed(mshook, MOUSE_BUTTON2); - break; - - case WM_MBUTTONDOWN: - set_modifier_mask(MASK_BUTTON3); - process_button_pressed(mshook, MOUSE_BUTTON3); - break; - - case WM_XBUTTONDOWN: - case WM_NCXBUTTONDOWN: - if (HIWORD(mshook->mouseData) == XBUTTON1) { - set_modifier_mask(MASK_BUTTON4); - process_button_pressed(mshook, MOUSE_BUTTON4); - } - else if (HIWORD(mshook->mouseData) == XBUTTON2) { - set_modifier_mask(MASK_BUTTON5); - process_button_pressed(mshook, MOUSE_BUTTON5); - } - else { - // Extra mouse buttons. - uint16_t button = HIWORD(mshook->mouseData); - - // Add support for mouse 4 & 5. - if (button == 4) { - set_modifier_mask(MOUSE_BUTTON4); - } - else if (button == 5) { - set_modifier_mask(MOUSE_BUTTON5); - } - - process_button_pressed(mshook, button); - } - break; - - - case WM_LBUTTONUP: - unset_modifier_mask(MASK_BUTTON1); - process_button_released(mshook, MOUSE_BUTTON1); - break; - - case WM_RBUTTONUP: - unset_modifier_mask(MASK_BUTTON2); - process_button_released(mshook, MOUSE_BUTTON2); - break; - - case WM_MBUTTONUP: - unset_modifier_mask(MASK_BUTTON3); - process_button_released(mshook, MOUSE_BUTTON3); - break; - - case WM_XBUTTONUP: - case WM_NCXBUTTONUP: - if (HIWORD(mshook->mouseData) == XBUTTON1) { - unset_modifier_mask(MASK_BUTTON4); - process_button_released(mshook, MOUSE_BUTTON4); - } - else if (HIWORD(mshook->mouseData) == XBUTTON2) { - unset_modifier_mask(MASK_BUTTON5); - process_button_released(mshook, MOUSE_BUTTON5); - } - else { - // Extra mouse buttons. - uint16_t button = HIWORD(mshook->mouseData); - - // Add support for mouse 4 & 5. - if (button == 4) { - unset_modifier_mask(MOUSE_BUTTON4); - } - else if (button == 5) { - unset_modifier_mask(MOUSE_BUTTON5); - } - - process_button_released(mshook, MOUSE_BUTTON5); - } - break; - - case WM_MOUSEMOVE: - process_mouse_moved(mshook); - break; - - case WM_MOUSEWHEEL: - process_mouse_wheel(mshook, WHEEL_VERTICAL_DIRECTION); - break; - - /* For horizontal scroll wheel support. - * NOTE Windows >= Vista - * case 0x020E: - */ - case WM_MOUSEHWHEEL: - process_mouse_wheel(mshook, WHEEL_HORIZONTAL_DIRECTION); - break; - - default: - // In theory this *should* never execute. - logger(LOG_LEVEL_DEBUG, "%s [%u]: Unhandled Windows mouse event: %#X.\n", - __FUNCTION__, __LINE__, (unsigned int) wParam); - break; - } - - LRESULT hook_result = -1; - if (nCode < 0 || event.reserved ^ 0x01) { - hook_result = CallNextHookEx(mouse_event_hhook, nCode, wParam, lParam); - } - else { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Consuming the current event. (%li)\n", - __FUNCTION__, __LINE__, (long) hook_result); - } - - return hook_result; -} - - -// Callback function that handles events. -void CALLBACK win_hook_event_proc(HWINEVENTHOOK hook, DWORD event, HWND hWnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { - switch (event) { - case EVENT_OBJECT_NAMECHANGE: - logger(LOG_LEVEL_INFO, "%s [%u]: Restarting Windows input hook on window event: %#X.\n", - __FUNCTION__, __LINE__, event); - - // Remove any keyboard or mouse hooks that are still running. - if (keyboard_event_hhook != NULL) { - UnhookWindowsHookEx(keyboard_event_hhook); - } - - if (mouse_event_hhook != NULL) { - UnhookWindowsHookEx(mouse_event_hhook); - } - - // Restart the event hooks. - keyboard_event_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_event_proc, hInst, 0); - mouse_event_hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_hook_event_proc, hInst, 0); - - // Re-initialize modifier masks. - initialize_modifiers(); - - // FIXME We should compare the modifier mask before and after the restart - // to determine if we should synthesize missing events. - - // Check for event hook error. - if (keyboard_event_hhook == NULL || mouse_event_hhook == NULL) { - logger(LOG_LEVEL_ERROR, "%s [%u]: SetWindowsHookEx() failed! (%#lX)\n", - __FUNCTION__, __LINE__, (unsigned long) GetLastError()); - } - break; - - default: - logger(LOG_LEVEL_INFO, "%s [%u]: Unhandled Windows window event: %#X.\n", - __FUNCTION__, __LINE__, event); - } -} - - -IOHOOK_API int hook_run() { - int status = IOHOOK_FAILURE; - - // Set the thread id we want to signal later. - hook_thread_id = GetCurrentThreadId(); - - // Spot check the hInst incase the library was statically linked and DllMain - // did not receive a pointer on load. - if (hInst == NULL) { - logger(LOG_LEVEL_INFO, "%s [%u]: hInst was not set by DllMain().\n", - __FUNCTION__, __LINE__); - - hInst = GetModuleHandle(NULL); - if (hInst != NULL) { - // Initialize native input helper functions. - load_input_helper(); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Could not determine hInst for SetWindowsHookEx()! (%#lX)\n", - __FUNCTION__, __LINE__, (unsigned long) GetLastError()); - - status = IOHOOK_ERROR_GET_MODULE_HANDLE; - } - } - - // Create the native hooks. - keyboard_event_hhook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_event_proc, hInst, 0); - mouse_event_hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_hook_event_proc, hInst, 0); - - // Create a window event hook to listen for capture change. - win_event_hhook = SetWinEventHook( - EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, - NULL, - win_hook_event_proc, - 0, 0, - WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); - - // If we did not encounter a problem, start processing events. - if (keyboard_event_hhook != NULL && mouse_event_hhook != NULL) { - if (win_event_hhook == NULL) { - logger(LOG_LEVEL_WARN, "%s [%u]: SetWinEventHook() failed!\n", - __FUNCTION__, __LINE__); - } - - logger(LOG_LEVEL_DEBUG, "%s [%u]: SetWindowsHookEx() successful.\n", - __FUNCTION__, __LINE__); - - // Check and setup modifiers. - initialize_modifiers(); - - // Set the exit status. - status = IOHOOK_SUCCESS; - - // Windows does not have a hook start event or callback so we need to - // manually fake it. - hook_start_proc(); - - // Block until the thread receives an WM_QUIT request. - MSG message; - while (GetMessage(&message, (HWND) NULL, 0, 0) > 0) { - TranslateMessage(&message); - DispatchMessage(&message); - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: SetWindowsHookEx() failed! (%#lX)\n", - __FUNCTION__, __LINE__, (unsigned long) GetLastError()); - - status = IOHOOK_ERROR_SET_WINDOWS_HOOK_EX; - } - - - // Unregister any hooks that may still be installed. - unregister_running_hooks(); - - // We must explicitly call the cleanup handler because Windows does not - // provide a thread cleanup method like POSIX pthread_cleanup_push/pop. - hook_stop_proc(); - - return status; -} - -IOHOOK_API int hook_stop() { - int status = IOHOOK_FAILURE; - - // Try to exit the thread naturally. - if (PostThreadMessage(hook_thread_id, WM_QUIT, (WPARAM) NULL, (LPARAM) NULL)) { - status = IOHOOK_SUCCESS; - } - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Status: %#X.\n", - __FUNCTION__, __LINE__, status); - - return status; -} diff --git a/cdeps/hook/windows/input.h b/cdeps/hook/windows/input.h deleted file mode 100644 index 6ba9817..0000000 --- a/cdeps/hook/windows/input.h +++ /dev/null @@ -1,104 +0,0 @@ -/*********************************************************************** - Input - ***********************************************************************/ - -#ifndef _included_input_helper -#define _included_input_helper - -#include -#include - -#ifndef LPFN_ISWOW64PROCESS -typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); -#endif - -typedef void* (CALLBACK *KbdLayerDescriptor) (VOID); - -#define CAPLOK 0x01 -#define WCH_NONE 0xF000 -#define WCH_DEAD 0xF001 - -#ifndef WM_MOUSEHWHEEL -#define WM_MOUSEHWHEEL 0x020E -#endif - -typedef struct _VK_TO_WCHARS { - BYTE VirtualKey; - BYTE Attributes; - WCHAR wch[]; -} VK_TO_WCHARS, *PVK_TO_WCHARS; - -typedef struct _LIGATURE { - BYTE VirtualKey; - WORD ModificationNumber; - WCHAR wch[]; -} LIGATURE, *PLIGATURE; - -typedef struct _VK_TO_BIT { - BYTE Vk; - BYTE ModBits; -} VK_TO_BIT, *PVK_TO_BIT; - -typedef struct _MODIFIERS { - PVK_TO_BIT pVkToBit; // __ptr64 - WORD wMaxModBits; - BYTE ModNumber[]; -} MODIFIERS, *PMODIFIERS; - -typedef struct _VSC_VK { - BYTE Vsc; - USHORT Vk; -} VSC_VK, *PVSC_VK; - -typedef struct _VK_TO_WCHAR_TABLE { - PVK_TO_WCHARS pVkToWchars; // __ptr64 - BYTE nModifications; - BYTE cbSize; -} VK_TO_WCHAR_TABLE, *PVK_TO_WCHAR_TABLE; - -typedef struct _DEADKEY { - DWORD dwBoth; - WCHAR wchComposed; - USHORT uFlags; -} DEADKEY, *PDEADKEY; - -typedef struct _VSC_LPWSTR { - BYTE vsc; - WCHAR *pwsz; // __ptr64 -} VSC_LPWSTR, *PVSC_LPWSTR; - -typedef struct tagKbdLayer { - PMODIFIERS pCharModifiers; // __ptr64 - PVK_TO_WCHAR_TABLE pVkToWcharTable; // __ptr64 - PDEADKEY pDeadKey; // __ptr64 - PVSC_LPWSTR pKeyNames; // __ptr64 - PVSC_LPWSTR pKeyNamesExt; // __ptr64 - WCHAR **pKeyNamesDead; // __ptr64 - USHORT *pusVSCtoVK; // __ptr64 - BYTE bMaxVSCtoVK; - PVSC_VK pVSCtoVK_E0; // __ptr64 - PVSC_VK pVSCtoVK_E1; // __ptr64 - DWORD fLocaleFlags; - BYTE nLgMax; - BYTE cbLgEntry; - PLIGATURE pLigature; // __ptr64 - DWORD dwType; - DWORD dwSubType; -} KBDTABLES, *PKBDTABLES; // __ptr64 - - -extern SIZE_T keycode_to_unicode(DWORD keycode, PWCHAR buffer, SIZE_T size); - -//extern DWORD unicode_to_keycode(wchar_t unicode); - -extern unsigned short keycode_to_scancode(DWORD vk_code, DWORD flags); - -extern DWORD scancode_to_keycode(unsigned short scancode); - -// Initialize the locale list and wow64 pointer size. -extern int load_input_helper(); - -// Cleanup the initialized locales. -extern int unload_input_helper(); - -#endif diff --git a/cdeps/hook/windows/input_c.h b/cdeps/hook/windows/input_c.h deleted file mode 100644 index f061b1b..0000000 --- a/cdeps/hook/windows/input_c.h +++ /dev/null @@ -1,832 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include -#include -#include -#include -#include - -#include "../iohook.h" -#include "../logger_c.h" -#include "input.h" - -static const uint16_t keycode_scancode_table[][2] = { - /* idx { vk_code, scancode }, */ - /* 0 */ { VC_UNDEFINED, 0x0000 }, // 0x00 - /* 1 */ { MOUSE_BUTTON1, VK_ESCAPE }, // 0x01 - /* 2 */ { MOUSE_BUTTON2, 0x0031 }, // 0x02 - /* 3 */ { VC_UNDEFINED, 0x0032 }, // 0x03 VK_CANCEL - /* 4 */ { MOUSE_BUTTON3, 0x0033 }, // 0x04 - /* 5 */ { MOUSE_BUTTON4, 0x0034 }, // 0x05 - /* 6 */ { MOUSE_BUTTON5, 0x0035 }, // 0x06 - /* 7 */ { VC_UNDEFINED, 0x0036 }, // 0x07 Undefined - /* 8 */ { VC_BACKSPACE, 0x0037 }, // 0x08 VK_BACK - /* 9 */ { VC_TAB, 0x0038 }, // 0x09 VK_TAB - /* 10 */ { VC_UNDEFINED, 0x0039 }, // 0x0A Reserved - /* 11 */ { VC_UNDEFINED, 0x0030 }, // 0x0B Reserved - /* 12 */ { VC_CLEAR, VK_OEM_MINUS }, // 0x0C VK_CLEAR - /* 13 */ { VC_ENTER, VK_OEM_PLUS }, // 0x0D VK_RETURN - /* 14 */ { VC_UNDEFINED, VK_BACK }, // 0x0E Undefined - /* 15 */ { VC_UNDEFINED, VK_TAB }, // 0x0F Undefined - /* 16 */ { VC_SHIFT_L, 0x0051 }, // 0x10 VK_SHIFT - /* 17 */ { VC_CONTROL_L, 0x0057 }, // 0x11 VK_CONTROL - /* 18 */ { VC_ALT_L, 0x0045 }, // 0x12 VK_MENU ALT key - /* 19 */ { VC_PAUSE, 0x0052 }, // 0x13 VK_PAUSE - /* 20 */ { VC_CAPS_LOCK, 0x0054 }, // 0x14 VK_CAPITAL CAPS LOCK key - /* 21 */ { VC_KATAKANA, 0x0059 }, // 0x15 VK_KANA IME Kana mode - /* 22 */ { VC_UNDEFINED, 0x0055 }, // 0x16 Undefined - /* 23 */ { VC_UNDEFINED, 0x0049 }, // 0x17 VK_JUNJA IME Junja mode - /* 24 */ { VC_UNDEFINED, 0x004F }, // 0x18 VK_FINAL - /* 25 */ { VC_KANJI, 0x0050 }, // 0x19 VK_KANJI / VK_HANJA IME Kanji / Hanja mode - /* 26 */ { VC_UNDEFINED, 0x00DB }, // 0x1A Undefined - /* 27 */ { VC_ESCAPE, 0x00DD }, // 0x1B VK_ESCAPE ESC key - /* 28 */ { VC_UNDEFINED, VK_RETURN }, // 0x1C VK_CONVERT IME convert// 0x1C - /* 29 */ { VC_UNDEFINED, VK_LCONTROL }, // 0x1D VK_NONCONVERT IME nonconvert - /* 30 */ { VC_UNDEFINED, 0x0041 }, // 0x1E VK_ACCEPT IME accept - /* 31 */ { VC_UNDEFINED, 0x0053 }, // 0x1F VK_MODECHANGE IME mode change request - /* 32 */ { VC_SPACE, 0x0044 }, // 0x20 VK_SPACE SPACEBAR - /* 33 */ { VC_PAGE_UP, 0x0046 }, // 0x21 VK_PRIOR PAGE UP key - /* 34 */ { VC_PAGE_DOWN, 0x0047 }, // 0x22 VK_NEXT PAGE DOWN key - /* 35 */ { VC_END, 0x0048 }, // 0x23 VK_END END key - /* 36 */ { VC_HOME, 0x004A }, // 0x24 VK_HOME HOME key - /* 37 */ { VC_LEFT, 0x004B }, // 0x25 VK_LEFT LEFT ARROW key - /* 38 */ { VC_UP, 0x004C }, // 0x26 VK_UP UP ARROW key - /* 39 */ { VC_RIGHT, VK_OEM_1 }, // 0x27 VK_RIGHT RIGHT ARROW key - /* 40 */ { VC_DOWN, VK_OEM_7 }, // 0x28 VK_DOWN DOWN ARROW key - /* 41 */ { VC_UNDEFINED, VK_OEM_3 }, // 0x29 VK_SELECT SELECT key - /* 42 */ { VC_UNDEFINED, VK_LSHIFT }, // 0x2A VK_PRINT PRINT key - /* 43 */ { VC_UNDEFINED, VK_OEM_5 }, // 0x2B VK_EXECUTE EXECUTE key - /* 44 */ { VC_PRINTSCREEN, 0x005A }, // 0x2C VK_SNAPSHOT PRINT SCREEN key - /* 45 */ { VC_INSERT, 0x0058 }, // 0x2D VK_INSERT INS key - /* 46 */ { VC_DELETE, 0x0043 }, // 0x2E VK_DELETE DEL key - /* 47 */ { VC_UNDEFINED, 0x0056 }, // 0x2F VK_HELP HELP key - /* 48 */ { VC_0, 0x0042 }, // 0x30 0 key - /* 49 */ { VC_1, 0x004E }, // 0x31 1 key - /* 50 */ { VC_2, 0x004D }, // 0x32 2 key - /* 51 */ { VC_3, VK_OEM_COMMA }, // 0x33 3 key - /* 52 */ { VC_4, VK_OEM_PERIOD }, // 0x34 4 key - /* 53 */ { VC_5, VK_OEM_2 }, // 0x35 5 key - /* 54 */ { VC_6, VK_RSHIFT }, // 0x36 6 key - /* 55 */ { VC_7, VK_MULTIPLY }, // 0x37 7 key - /* 56 */ { VC_8, VK_LMENU }, // 0x38 8 key - /* 57 */ { VC_9, VK_SPACE }, // 0x39 9 key - /* 58 */ { VC_UNDEFINED, VK_CAPITAL }, // 0x3A Undefined - /* 59 */ { VC_UNDEFINED, VK_F1 }, // 0x3B Undefined - /* 60 */ { VC_UNDEFINED, VK_F2 }, // 0x3C Undefined - /* 61 */ { VC_UNDEFINED, VK_F3 }, // 0x3D Undefined - /* 62 */ { VC_UNDEFINED, VK_F4 }, // 0x3E Undefined - /* 63 */ { VC_UNDEFINED, VK_F5 }, // 0x3F Undefined - /* 64 */ { VC_UNDEFINED, VK_F6 }, // 0x40 Undefined - /* 65 */ { VC_A, VK_F7 }, // 0x41 A key - /* 66 */ { VC_B, VK_F8 }, // 0x42 B key - /* 67 */ { VC_C, VK_F9 }, // 0x43 C key - /* 68 */ { VC_D, VK_F10 }, // 0x44 D key - /* 69 */ { VC_E, VK_NUMLOCK }, // 0x45 E key - /* 70 */ { VC_F, VK_SCROLL }, // 0x46 F key - /* 71 */ { VC_G, VK_NUMPAD7 }, // 0x47 G key - /* 72 */ { VC_H, VK_NUMPAD8 }, // 0x48 H key - /* 73 */ { VC_I, VK_NUMPAD9 }, // 0x49 I key - /* 74 */ { VC_J, VK_SUBTRACT }, // 0x4A J key - /* 75 */ { VC_K, VK_NUMPAD4 }, // 0x4B K key - /* 76 */ { VC_L, VK_NUMPAD5 }, // 0x4C L key - /* 77 */ { VC_M, VK_NUMPAD6 }, // 0x4D M key - /* 78 */ { VC_N, VK_ADD }, // 0x4E N key - /* 79 */ { VC_O, VK_NUMPAD1 }, // 0x4F O key - /* 80 */ { VC_P, VK_NUMPAD2 }, // 0x50 P key - /* 81 */ { VC_Q, VK_NUMPAD3 }, // 0x51 Q key - /* 82 */ { VC_R, VK_NUMPAD0 }, // 0x52 R key - /* 83 */ { VC_S, VK_DECIMAL }, // 0x53 S key - /* 84 */ { VC_T, 0x0000 }, // 0x54 T key - /* 85 */ { VC_U, 0x0000 }, // 0x55 U key - /* 86 */ { VC_V, 0x0000 }, // 0x56 V key - /* 87 */ { VC_W, VK_F11 }, // 0x57 W key - /* 88 */ { VC_X, VK_F12 }, // 0x58 X key - /* 89 */ { VC_Y, 0x0000 }, // 0x59 Y key - /* 90 */ { VC_Z, 0x0000 }, // 0x5A Z key - /* 91 */ { VC_META_L, VK_F13 }, // 0x5B VK_LWIN Left Windows key (Natural keyboard) - /* 92 */ { VC_META_R, VK_F14 }, // 0x5C VK_RWIN Right Windows key (Natural keyboard) - /* 93 */ { VC_CONTEXT_MENU, VK_F15 }, // 0x5D VK_APPS Applications key (Natural keyboard) - /* 94 */ { VC_UNDEFINED, 0x0000 }, // 0x5E Reserved - /* 95 */ { VC_SLEEP, 0x0000 }, // 0x5F VK_SLEEP Computer Sleep key - /* 96 */ { VC_KP_0, 0x0000 }, // 0x60 VK_NUMPAD0 Numeric keypad 0 key - /* 97 */ { VC_KP_1, 0x0000 }, // 0x61 VK_NUMPAD1 Numeric keypad 1 key - /* 98 */ { VC_KP_2, 0x0000 }, // 0x62 VK_NUMPAD2 Numeric keypad 2 key - /* 99 */ { VC_KP_3, VK_F16 }, // 0x63 VK_NUMPAD3 Numeric keypad 3 key - /* 100 */ { VC_KP_4, VK_F17 }, // 0x64 VK_NUMPAD4 Numeric keypad 4 key - /* 101 */ { VC_KP_5, VK_F18 }, // 0x65 VK_NUMPAD5 Numeric keypad 5 key - /* 102 */ { VC_KP_6, VK_F19 }, // 0x66 VK_NUMPAD6 Numeric keypad 6 key - /* 103 */ { VC_KP_7, VK_F20 }, // 0x67 VK_NUMPAD7 Numeric keypad 7 key - /* 104 */ { VC_KP_8, VK_F21 }, // 0x68 VK_NUMPAD8 Numeric keypad 8 key - /* 105 */ { VC_KP_9, VK_F22 }, // 0x69 VK_NUMPAD9 Numeric keypad 9 key - /* 106 */ { VC_KP_MULTIPLY, VK_F23 }, // 0x6A VK_MULTIPLY Multiply key - /* 107 */ { VC_KP_ADD, VK_F24 }, // 0x6B VK_ADD Add key - /* 108 */ { VC_UNDEFINED, 0x0000 }, // 0x6C VK_SEPARATOR Separator key - /* 109 */ { VC_KP_SUBTRACT, 0x0000 }, // 0x6D VK_SUBTRACT Subtract key - /* 110 */ { VC_KP_SEPARATOR, 0x0000 }, // 0x6E VK_DECIMAL Decimal key - /* 111 */ { VC_KP_DIVIDE, 0x0000 }, // 0x6F VK_DIVIDE Divide key - /* 112 */ { VC_F1, VK_KANA }, // 0x70 VK_F1 F1 key - /* 113 */ { VC_F2, 0x0000 }, // 0x71 VK_F2 F2 key - /* 114 */ { VC_F3, 0x0000 }, // 0x72 VK_F3 F3 key - /* 115 */ { VC_F4, 0x0000 }, // 0x73 VK_F4 F4 key - /* 116 */ { VC_F5, 0x0000 }, // 0x74 VK_F5 F5 key - /* 117 */ { VC_F6, 0x0000 }, // 0x75 VK_F6 F6 key - /* 118 */ { VC_F7, 0x0000 }, // 0x76 VK_F7 F7 key - /* 119 */ { VC_F8, 0x0000 }, // 0x77 VK_F8 F8 key - /* 120 */ { VC_F9, 0x0000 }, // 0x78 VK_F9 F9 key - /* 121 */ { VC_F10, VK_KANJI }, // 0x79 VK_F10 F10 key - /* 122 */ { VC_F11, 0x0000 }, // 0x7A VK_F11 F11 key - /* 123 */ { VC_F12, 0x0000 }, // 0x7B VK_F12 F12 key - /* 124 */ { VC_F13, 0x0000 }, // 0x7C VK_F13 F13 key - /* 125 */ { VC_F14, VK_OEM_8 }, // 0x7D VK_F14 F14 key - /* 126 */ { VC_F15, 0x0000 }, // 0x7E VK_F15 F15 key - /* 127 */ { VC_F16, 0x0000 }, // 0x7F VK_F16 F16 key - - // No Offset Offset (i & 0x007F) | 0x80 - - /* 128 */ { VC_F17, 0x0000 }, // 0x80 VK_F17 F17 key - /* 129 */ { VC_F18, 0x0000 }, // 0x81 VK_F18 F18 key - /* 130 */ { VC_F19, 0x0000 }, // 0x82 VK_F19 F19 key - /* 131 */ { VC_F20, 0x0000 }, // 0x83 VK_F20 F20 key - /* 132 */ { VC_F21, 0x0000 }, // 0x84 VK_F21 F21 key - /* 133 */ { VC_F22, 0x0000 }, // 0x85 VK_F22 F22 key - /* 134 */ { VC_F23, 0x0000 }, // 0x86 VK_F23 F23 key - /* 135 */ { VC_F24, 0x0000 }, // 0x87 VK_F24 F24 key - /* 136 */ { VC_UNDEFINED, 0x0000 }, // 0x88 Unassigned - /* 137 */ { VC_UNDEFINED, 0x0000 }, // 0x89 Unassigned - /* 138 */ { VC_UNDEFINED, 0x0000 }, // 0x8A Unassigned - /* 139 */ { VC_UNDEFINED, 0x0000 }, // 0x8B Unassigned - /* 140 */ { VC_UNDEFINED, 0x0000 }, // 0x8C Unassigned - /* 141 */ { VC_UNDEFINED, 0x0000 }, // 0x8D Unassigned - /* 142 */ { VC_UNDEFINED, 0x0000 }, // 0x8E Unassigned - /* 143 */ { VC_UNDEFINED, 0x0000 }, // 0x8F Unassigned - /* 144 */ { VC_NUM_LOCK, VK_MEDIA_PREV_TRACK }, // 0x90 VK_NUMLOCK NUM LOCK key - /* 145 */ { VC_SCROLL_LOCK, 0x0000 }, // 0x91 VK_SCROLL SCROLL LOCK key - /* 146 */ { VC_UNDEFINED, 0x0000 }, // 0x92 OEM specific - /* 147 */ { VC_UNDEFINED, 0x0000 }, // 0x93 OEM specific - /* 148 */ { VC_UNDEFINED, 0x0000 }, // 0x94 OEM specific - /* 149 */ { VC_UNDEFINED, 0x0000 }, // 0x95 OEM specific - /* 150 */ { VC_UNDEFINED, 0x0000 }, // 0x96 OEM specific - /* 151 */ { VC_UNDEFINED, 0x0000 }, // 0x97 Unassigned - /* 152 */ { VC_UNDEFINED, 0x0000 }, // 0x98 Unassigned - /* 153 */ { VC_UNDEFINED, VK_MEDIA_NEXT_TRACK }, // 0x99 Unassigned - /* 154 */ { VC_UNDEFINED, 0x0000 }, // 0x9A Unassigned - /* 155 */ { VC_UNDEFINED, 0x0000 }, // 0x9B Unassigned - /* 156 */ { VC_UNDEFINED, 0x0000 }, // 0x9C Unassigned - /* 157 */ { VC_UNDEFINED, VK_RCONTROL }, // 0x9D Unassigned - /* 158 */ { VC_UNDEFINED, 0x0000 }, // 0x9E Unassigned - /* 159 */ { VC_UNDEFINED, 0x0000 }, // 0x9F Unassigned - /* 160 */ { VC_SHIFT_L, VK_VOLUME_MUTE }, // 0xA0 VK_LSHIFT Left SHIFT key - /* 161 */ { VC_SHIFT_R, VK_LAUNCH_APP2 }, // 0xA1 VK_RSHIFT Right SHIFT key - /* 162 */ { VC_CONTROL_L, VK_MEDIA_PLAY_PAUSE }, // 0xA2 VK_LCONTROL Left CONTROL key - /* 163 */ { VC_CONTROL_R, 0x0000 }, // 0xA3 VK_RCONTROL Right CONTROL key - /* 164 */ { VC_ALT_L, VK_MEDIA_STOP }, // 0xA4 VK_LMENU Left MENU key - /* 165 */ { VC_ALT_R, 0x0000 }, // 0xA5 VK_RMENU Right MENU key - /* 166 */ { VC_BROWSER_BACK, 0x0000 }, // 0xA6 VK_BROWSER_BACK Browser Back key - /* 167 */ { VC_BROWSER_FORWARD, 0x0000 }, // 0xA7 VK_BROWSER_FORWARD Browser Forward key - /* 168 */ { VC_BROWSER_REFRESH, 0x0000 }, // 0xA8 VK_BROWSER_REFRESH Browser Refresh key - /* 169 */ { VC_BROWSER_STOP, 0x0000 }, // 0xA9 VK_BROWSER_STOP Browser Stop key - /* 170 */ { VC_BROWSER_SEARCH, 0x0000 }, // 0xAA VK_BROWSER_SEARCH Browser Search key - /* 171 */ { VC_BROWSER_FAVORITES, 0x0000 }, // 0xAB VK_BROWSER_FAVORITES Browser Favorites key - /* 172 */ { VC_BROWSER_HOME, 0x0000 }, // 0xAC VK_BROWSER_HOME Browser Start and Home key - /* 173 */ { VC_VOLUME_MUTE, 0x0000 }, // 0xAD VK_VOLUME_MUTE Volume Mute key - /* 174 */ { VC_VOLUME_DOWN, VK_VOLUME_DOWN }, // 0xAE VK_VOLUME_DOWN Volume Down key - /* 175 */ { VC_VOLUME_UP, 0x0000 }, // 0xAF VK_VOLUME_UP Volume Up key - /* 176 */ { VC_MEDIA_NEXT, VK_VOLUME_UP }, // 0xB0 VK_MEDIA_NEXT_TRACK Next Track key - /* 177 */ { VC_MEDIA_PREVIOUS, 0x0000 }, // 0xB1 VK_MEDIA_PREV_TRACK Previous Track key - /* 178 */ { VC_MEDIA_STOP, VK_BROWSER_HOME }, // 0xB2 VK_MEDIA_STOP Stop Media key - /* 179 */ { VC_MEDIA_PLAY, 0x0000 }, // 0xB3 VK_MEDIA_PLAY_PAUSE Play/Pause Media key - /* 180 */ { VC_UNDEFINED, 0x0000 }, // 0xB4 VK_LAUNCH_MAIL Start Mail key - /* 181 */ { VC_MEDIA_SELECT, VK_DIVIDE }, // 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key - /* 182 */ { VC_APP_MAIL, 0x0000 }, // 0xB6 VK_LAUNCH_APP1 Start Application 1 key - /* 183 */ { VC_APP_CALCULATOR, VK_SNAPSHOT }, // 0xB7 VK_LAUNCH_APP2 Start Application 2 key - /* 184 */ { VC_UNDEFINED, VK_RMENU }, // 0xB8 Reserved - /* 185 */ { VC_UNDEFINED, 0x0000 }, // 0xB9 Reserved - /* 186 */ { VC_SEMICOLON, 0x0000 }, // 0xBA VK_OEM_1 Varies by keyboard. For the US standard keyboard, the ';:' key - /* 187 */ { VC_EQUALS, 0x0000 }, // 0xBB VK_OEM_PLUS For any country/region, the '+' key - /* 188 */ { VC_COMMA, 0x00E6 }, // 0xBC VK_OEM_COMMA For any country/region, the ',' key - /* 189 */ { VC_MINUS, 0x0000 }, // 0xBD VK_OEM_MINUS For any country/region, the '-' key - /* 190 */ { VC_PERIOD, 0x0000 }, // 0xBE VK_OEM_PERIOD For any country/region, the '.' key - /* 191 */ { VC_SLASH, 0x0000 }, // 0xBF VK_OEM_2 Varies by keyboard. For the US standard keyboard, the '/?' key - /* 192 */ { VC_BACKQUOTE, 0x0000 }, // 0xC0 VK_OEM_3 Varies by keyboard. For the US standard keyboard, the '`~' key - /* 193 */ { VC_UNDEFINED, 0x0000 }, // 0xC1 Reserved - /* 194 */ { VC_UNDEFINED, 0x0000 }, // 0xC2 Reserved - /* 195 */ { VC_UNDEFINED, 0x0000 }, // 0xC3 Reserved - /* 196 */ { VC_UNDEFINED, 0x0000 }, // 0xC4 Reserved - /* 197 */ { VC_UNDEFINED, VK_PAUSE }, // 0xC5 Reserved - /* 198 */ { VC_UNDEFINED, 0x0000 }, // 0xC6 Reserved - /* 199 */ { VC_UNDEFINED, VK_HOME }, // 0xC7 Reserved - /* 200 */ { VC_UNDEFINED, VK_UP }, // 0xC8 Reserved - /* 201 */ { VC_UNDEFINED, VK_PRIOR }, // 0xC9 Reserved - /* 202 */ { VC_UNDEFINED, 0x0000 }, // 0xCA Reserved - /* 203 */ { VC_UNDEFINED, VK_LEFT }, // 0xCB Reserved - /* 204 */ { VC_UNDEFINED, VK_CLEAR }, // 0xCC Reserved - /* 205 */ { VC_UNDEFINED, VK_RIGHT }, // 0xCD Reserved - /* 206 */ { VC_UNDEFINED, 0x0000 }, // 0xCE Reserved - /* 207 */ { VC_UNDEFINED, VK_END }, // 0xCF Reserved - /* 208 */ { VC_UNDEFINED, VK_DOWN }, // 0xD0 Reserved - /* 209 */ { VC_UNDEFINED, VK_NEXT }, // 0xD1 Reserved - /* 210 */ { VC_UNDEFINED, VK_INSERT }, // 0xD2 Reserved - /* 211 */ { VC_UNDEFINED, VK_DELETE }, // 0xD3 Reserved - /* 212 */ { VC_UNDEFINED, 0x0000 }, // 0xD4 Reserved - /* 213 */ { VC_UNDEFINED, 0x0000 }, // 0xD5 Reserved - /* 214 */ { VC_UNDEFINED, 0x0000 }, // 0xD6 Reserved - /* 215 */ { VC_UNDEFINED, 0x0000 }, // 0xD7 Reserved - /* 216 */ { VC_UNDEFINED, 0x0000 }, // 0xD8 Unassigned - /* 217 */ { VC_UNDEFINED, 0x0000 }, // 0xD9 Unassigned - /* 218 */ { VC_UNDEFINED, 0x0000 }, // 0xDA Unassigned - /* 219 */ { VC_OPEN_BRACKET, VK_LWIN }, // 0xDB VK_OEM_4 Varies by keyboard. For the US standard keyboard, the '[{' key - /* 220 */ { VC_BACK_SLASH, VK_RWIN }, // 0xDC VK_OEM_5 Varies by keyboard. For the US standard keyboard, the '\|' key - /* 221 */ { VC_CLOSE_BRACKET, VK_APPS }, // 0xDD VK_OEM_6 Varies by keyboard. For the US standard keyboard, the ']}' key - /* 222 */ { VC_QUOTE, 0x0000 }, // 0xDE VK_OEM_7 Varies by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key - /* 223 */ { VC_YEN, VK_SLEEP }, // 0xDF VK_OEM_8 Varies by keyboard. - /* 224 */ { VC_UNDEFINED, 0x0000 }, // 0xE0 Reserved - /* 225 */ { VC_UNDEFINED, 0x0000 }, // 0xE1 OEM specific - /* 226 */ { VC_UNDEFINED, 0x0000 }, // 0xE2 VK_OEM_102 Either the angle bracket key or the backslash key on the RT 102-key keyboard - /* 227 */ { VC_UNDEFINED, 0x0000 }, // 0xE3 OEM specific - /* 228 */ { VC_UNDEFINED, 0x00E5 }, // 0xE4 VC_APP_PICTURES OEM specific - /* 229 */ { VC_APP_PICTURES, VK_BROWSER_SEARCH }, // 0xE5 VK_PROCESSKEY IME PROCESS key - /* 230 */ { VC_APP_MUSIC, VK_BROWSER_FAVORITES }, // 0xE6 OEM specific - /* 231 */ { VC_UNDEFINED, VK_BROWSER_REFRESH }, // 0xE7 VK_PACKET Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. - /* 232 */ { VC_UNDEFINED, VK_BROWSER_STOP }, // 0xE8 Unassigned - /* 233 */ { VC_UNDEFINED, VK_BROWSER_FORWARD }, // 0xE9 OEM specific - /* 234 */ { VC_UNDEFINED, VK_BROWSER_BACK }, // 0xEA OEM specific - /* 235 */ { VC_UNDEFINED, 0x0000 }, // 0xEB OEM specific - /* 236 */ { VC_UNDEFINED, VK_LAUNCH_APP1 }, // 0xEC OEM specific - /* 237 */ { VC_UNDEFINED, VK_LAUNCH_MEDIA_SELECT }, // 0xED OEM specific - /* 238 */ { VC_UNDEFINED, 0x0000 }, // 0xEE OEM specific - /* 239 */ { VC_UNDEFINED, 0x0000 }, // 0xEF OEM specific - /* 240 */ { VC_UNDEFINED, 0x0000 }, // 0xF0 OEM specific - /* 241 */ { VC_UNDEFINED, 0x0000 }, // 0xF1 OEM specific - /* 242 */ { VC_UNDEFINED, 0x0000 }, // 0xF2 OEM specific - /* 243 */ { VC_UNDEFINED, 0x0000 }, // 0xF3 OEM specific - /* 244 */ { VC_UNDEFINED, 0x0000 }, // 0xF4 OEM specific - /* 245 */ { VC_UNDEFINED, 0x0000 }, // 0xF5 OEM specific - /* 246 */ { VC_UNDEFINED, 0x0000 }, // 0xF6 VK_ATTN Attn key - /* 247 */ { VC_UNDEFINED, 0x0000 }, // 0xF7 VK_CRSEL CrSel key - /* 248 */ { VC_UNDEFINED, 0x0000 }, // 0xF8 VK_EXSEL ExSel key - /* 249 */ { VC_UNDEFINED, 0x0000 }, // 0xF9 VK_EREOF Erase EOF key - /* 250 */ { VC_UNDEFINED, 0x0000 }, // 0xFA VK_PLAY Play key - /* 251 */ { VC_UNDEFINED, 0x0000 }, // 0xFB VK_ZOOM Zoom key - /* 252 */ { VC_UNDEFINED, 0x0000 }, // 0xFC VK_NONAME Reserved - /* 253 */ { VC_UNDEFINED, 0x0000 }, // 0xFD - /* 254 */ { VC_CLEAR, 0x0000 }, // 0xFE VK_OEM_CLEAR Clear key - /* 255 */ { VC_UNDEFINED, 0x0000 } // 0xFE Unassigned -}; - -unsigned short keycode_to_scancode(DWORD vk_code, DWORD flags) { - unsigned short scancode = VC_UNDEFINED; - - // Check the vk_code is in range. - // NOTE vk_code >= 0 is assumed because DWORD is unsigned. - if (vk_code < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[0])) { - scancode = keycode_scancode_table[vk_code][0]; - - if (flags & LLKHF_EXTENDED) { - logger(LOG_LEVEL_WARN, "%s [%u]: EXTD2, vk_code %li\n", - __FUNCTION__, __LINE__, vk_code); - - switch (vk_code) { - case VK_PRIOR: - case VK_NEXT: - case VK_END: - case VK_HOME: - case VK_LEFT: - case VK_UP: - case VK_RIGHT: - case VK_DOWN: - - case VK_INSERT: - case VK_DELETE: - scancode |= 0xEE00; - break; - - case VK_RETURN: - scancode |= 0x0E00; - break; - } - } - else { - // logger(LOG_LEVEL_WARN, "%s [%u]: Test2, vk_code %li\n", - // __FUNCTION__, __LINE__, vk_code); - } - } - - return scancode; -} - -DWORD scancode_to_keycode(unsigned short scancode) { - unsigned short keycode = 0x0000; - - // Check the vk_code is in range. - // NOTE vk_code >= 0 is assumed because the scancode is unsigned. - if (scancode < 128) { - keycode = keycode_scancode_table[scancode][1]; - } - else { - // Calculate the upper offset based on the lower half of the scancode + 128. - unsigned short int i = (scancode & 0x007F) | 0x80; - - if (i < sizeof(keycode_scancode_table) / sizeof(keycode_scancode_table[1])) { - keycode = keycode_scancode_table[i][1]; - } - } - - return keycode; -} - - -/************************************************************************/ - -// Structure and pointers for the keyboard locale cache. -typedef struct _KeyboardLocale { - HKL id; // Locale ID - HINSTANCE library; // Keyboard DLL instance. - PVK_TO_BIT pVkToBit; // Pointers struct arrays. - PVK_TO_WCHAR_TABLE pVkToWcharTable; - PDEADKEY pDeadKey; - struct _KeyboardLocale* next; -} KeyboardLocale; - -static KeyboardLocale* locale_first = NULL; -static KeyboardLocale* locale_current = NULL; -static WCHAR deadChar = WCH_NONE; - -// Amount of pointer padding to apply for Wow64 instances. -static unsigned short int ptr_padding = 0; - -#if defined(_WIN32) && !defined(_WIN64) -// Small function to check and see if we are executing under Wow64. -static BOOL is_wow64() { - BOOL status = FALSE; - - LPFN_ISWOW64PROCESS pIsWow64Process = (LPFN_ISWOW64PROCESS) - GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"); - - if (pIsWow64Process != NULL) { - HANDLE current_proc = GetCurrentProcess(); - - if (!pIsWow64Process(current_proc, &status)) { - status = FALSE; - - logger(LOG_LEVEL_DEBUG, "%s [%u]: pIsWow64Process(%#p, %#p) failed!\n", - __FUNCTION__, __LINE__, current_proc, &status); - } - } - - return status; -} -#endif - -// Locate the DLL that contains the current keyboard layout. -static int get_keyboard_layout_file(char *layoutFile, DWORD bufferSize) { - int status = IOHOOK_FAILURE; - HKEY hKey; - DWORD varType = REG_SZ; - - char kbdName[KL_NAMELENGTH]; - if (GetKeyboardLayoutName(kbdName)) { - char kbdKeyPath[51 + KL_NAMELENGTH]; - snprintf(kbdKeyPath, 51 + KL_NAMELENGTH, "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s", kbdName); - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) kbdKeyPath, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { - if (RegQueryValueEx(hKey, "Layout File", NULL, &varType, (LPBYTE) layoutFile, &bufferSize) == ERROR_SUCCESS) { - RegCloseKey(hKey); - status = IOHOOK_SUCCESS; - } - } - } - - return status; -} - -static int refresh_locale_list() { - int count = 0; - - // Get the number of layouts the user has activated. - int hkl_size = GetKeyboardLayoutList(0, NULL); - if (hkl_size > 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: GetKeyboardLayoutList(0, NULL) found %i layouts.\n", - __FUNCTION__, __LINE__, hkl_size); - - // Get the thread id that currently has focus for our default. - DWORD focus_pid = GetWindowThreadProcessId(GetForegroundWindow(), NULL); - HKL hlk_focus = GetKeyboardLayout(focus_pid); - HKL hlk_default = GetKeyboardLayout(0); - HKL *hkl_list = malloc(sizeof(HKL) * hkl_size); - - int new_size = GetKeyboardLayoutList(hkl_size, hkl_list); - if (new_size > 0) { - if (new_size != hkl_size) { - logger(LOG_LEVEL_WARN, "%s [%u]: Locale size mismatch! " - "Expected %i, received %i!\n", - __FUNCTION__, __LINE__, hkl_size, new_size); - } - else { - logger(LOG_LEVEL_INFO, "%s [%u]: Received %i locales.\n", - __FUNCTION__, __LINE__, new_size); - } - - KeyboardLocale* locale_previous = NULL; - KeyboardLocale* locale_item = locale_first; - - // Go though the linked list and remove KeyboardLocale's that are - // no longer loaded. - while (locale_item != NULL) { - // Check to see if the old HKL is in the new list. - bool is_loaded = false; - int i; - for (i = 0; i < new_size && !is_loaded; i++) { - if (locale_item->id == hkl_list[i]) { - // Flag and jump out of the loop. - hkl_list[i] = NULL; - is_loaded = true; - } - } - - - if (is_loaded) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Found locale ID %#p in the cache.\n", - __FUNCTION__, __LINE__, locale_item->id); - - // Set the previous local to the current locale. - locale_previous = locale_item; - - // Check and see if the locale is our current active locale. - if (locale_item->id == hlk_focus) { - locale_current = locale_item; - } - - count++; - } - else { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Removing locale ID %#p from the cache.\n", - __FUNCTION__, __LINE__, locale_item->id); - - // If the old id is not in the new list, remove it. - locale_previous->next = locale_item->next; - - // Make sure the locale_current points NULL or something valid. - if (locale_item == locale_current) { - locale_current = NULL; - } - - // Free the memory used by locale_item; - free(locale_item); - - // Set the item to the pervious item to guarantee a next. - locale_item = locale_previous; - } - - // Iterate to the next linked list item. - locale_item = locale_item->next; - } - - - // Insert anything new into the linked list. - int i; - for (i = 0; i < new_size; i++) { - // Check to see if the item was already in the list. - if (hkl_list[i] != NULL) { - // Set the active keyboard layout for this thread to the HKL. - ActivateKeyboardLayout(hkl_list[i], 0x00); - - // Try to pull the current keyboard layout DLL from the registry. - char layoutFile[MAX_PATH]; - if (get_keyboard_layout_file(layoutFile, sizeof(layoutFile)) == IOHOOK_SUCCESS) { - // You can't trust the %SYSPATH%, look it up manually. - char systemDirectory[MAX_PATH]; - if (GetSystemDirectory(systemDirectory, MAX_PATH) != 0) { - char kbdLayoutFilePath[MAX_PATH]; - snprintf(kbdLayoutFilePath, MAX_PATH, "%s\\%s", systemDirectory, layoutFile); - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Loading layout for %#p: %s.\n", - __FUNCTION__, __LINE__, hkl_list[i], layoutFile); - - // Create the new locale item. - locale_item = malloc(sizeof(KeyboardLocale)); - locale_item->id = hkl_list[i]; - locale_item->library = LoadLibrary(kbdLayoutFilePath); - - // Get the function pointer from the library to get the keyboard layer descriptor. - KbdLayerDescriptor pKbdLayerDescriptor = (KbdLayerDescriptor) GetProcAddress(locale_item->library, "KbdLayerDescriptor"); - if (pKbdLayerDescriptor != NULL) { - PKBDTABLES pKbd = pKbdLayerDescriptor(); - - // Store the memory address of the following 3 structures. - BYTE *base = (BYTE *) pKbd; - - // First element of each structure, no offset adjustment needed. - locale_item->pVkToBit = pKbd->pCharModifiers->pVkToBit; - - // Second element of pKbd, +4 byte offset on wow64. - locale_item->pVkToWcharTable = *((PVK_TO_WCHAR_TABLE *) (base + offsetof(KBDTABLES, pVkToWcharTable) + ptr_padding)); - - // Third element of pKbd, +8 byte offset on wow64. - locale_item->pDeadKey = *((PDEADKEY *) (base + offsetof(KBDTABLES, pDeadKey) + (ptr_padding * 2))); - - // This will always be added to the end of the list. - locale_item->next = NULL; - - // Insert the item into the linked list. - if (locale_previous == NULL) { - // If nothing came before, the list is empty. - locale_first = locale_item; - } - else { - // Append the new locale to the end of the list. - locale_previous->next = locale_item; - } - - // Check and see if the locale is our current active locale. - if (locale_item->id == hlk_focus) { - locale_current = locale_item; - } - - // Set the pervious locale item to the new one. - locale_previous = locale_item; - - count++; - } - else { - logger(LOG_LEVEL_ERROR, - "%s [%u]: GetProcAddress() failed for KbdLayerDescriptor!\n", - __FUNCTION__, __LINE__); - - FreeLibrary(locale_item->library); - free(locale_item); - locale_item = NULL; - } - } - else { - logger(LOG_LEVEL_ERROR, - "%s [%u]: GetSystemDirectory() failed!\n", - __FUNCTION__, __LINE__); - } - } - else { - logger(LOG_LEVEL_ERROR, - "%s [%u]: Could not find keyboard map for locale %#p!\n", - __FUNCTION__, __LINE__, hkl_list[i]); - } - } - } - } - else { - logger(LOG_LEVEL_ERROR, - "%s [%u]: GetKeyboardLayoutList() failed!\n", - __FUNCTION__, __LINE__); - - // TODO Try and recover by using the current layout. - // Hint: Use locale_id instead of hkl_list[i] in the loop above. - } - - free(hkl_list); - ActivateKeyboardLayout(hlk_default, 0x00); - } - - return count; -} - -SIZE_T keycode_to_unicode(DWORD keycode, PWCHAR buffer, SIZE_T size) { - // Get the thread id that currently has focus and ask for its current - // locale. - DWORD focus_pid = GetWindowThreadProcessId(GetForegroundWindow(), NULL); - HKL locale_id = GetKeyboardLayout(focus_pid); - - // If the current Locale is not the new locale, search the linked list. - if (locale_current == NULL || locale_current->id != locale_id) { - locale_current = NULL; - KeyboardLocale* locale_item = locale_first; - - // Search the linked list... - while (locale_item != NULL && locale_item->id != locale_id) { - locale_item = locale_item->next; - } - - // You may already be a winner! - if (locale_item != NULL && locale_item->id != locale_id) { - logger(LOG_LEVEL_INFO, - "%s [%u]: Activating keyboard layout %#p.\n", - __FUNCTION__, __LINE__, locale_item->id); - - // Switch the current locale. - locale_current = locale_item; - locale_item = NULL; - - // If they layout changes the dead key state needs to be reset. - // This is consistent with the way Windows handles locale changes. - deadChar = WCH_NONE; - } - else { - logger(LOG_LEVEL_DEBUG, - "%s [%u]: Refreshing locale cache.\n", - __FUNCTION__, __LINE__); - - refresh_locale_list(); - } - } - - // Initialize to empty. - SIZE_T charCount = 0; - // buffer[i] = WCH_NONE; - - // Check and make sure the Unicode helper was loaded. - if (locale_current != NULL) { - logger(LOG_LEVEL_INFO, - "%s [%u]: Using keyboard layout %#p.\n", - __FUNCTION__, __LINE__, locale_current->id); - - int mod = 0; - - int capsLock = (GetKeyState(VK_CAPITAL) & 0x01); - - PVK_TO_BIT pVkToBit = locale_current->pVkToBit; - PVK_TO_WCHAR_TABLE pVkToWcharTable = locale_current->pVkToWcharTable; - PDEADKEY pDeadKey = locale_current->pDeadKey; - - /* Loop over the modifier keys for this locale and determine what is - * currently depressed. Because this is only a structure of two - * bytes, we don't need to worry about the structure padding of __ptr64 - * offsets on Wow64. - */ - bool is_shift = false, is_ctrl = false, is_alt = false; - int i; - for (i = 0; pVkToBit[i].Vk != 0; i++) { - short state = GetAsyncKeyState(pVkToBit[i].Vk); - - // Check to see if the most significant bit is active. - if (state & ~SHRT_MAX) { - if (pVkToBit[i].Vk == VK_SHIFT) { - is_shift = true; - } - else if (pVkToBit[i].Vk == VK_CONTROL) { - is_ctrl = true; - } - else if (pVkToBit[i].Vk == VK_MENU) { - is_alt = true; - } - } - } - - // Check the Shift modifier. - if (is_shift) { - mod = 1; - } - - // Check for the AltGr modifier. - if (is_ctrl && is_alt) { - mod += 3; - } - - // Default 32 bit structure size should be 6 bytes (4 for the pointer and 2 - // additional byte fields) that are padded out to 8 bytes by the compiler. - unsigned short sizeVkToWcharTable = sizeof(VK_TO_WCHAR_TABLE); - #if defined(_WIN32) && !defined(_WIN64) - if (is_wow64()) { - // If we are running under Wow64 the size of the first pointer will be - // 8 bringing the total size to 10 bytes padded out to 16. - sizeVkToWcharTable = (sizeVkToWcharTable + ptr_padding + 7) & -8; - } - #endif - - BYTE *ptrCurrentVkToWcharTable = (BYTE *) pVkToWcharTable; - - int cbSize, n; - do { - // cbSize is used to calculate n, and n is used for the size of pVkToWchars[j].wch[n] - cbSize = *(ptrCurrentVkToWcharTable + offsetof(VK_TO_WCHAR_TABLE, cbSize) + ptr_padding); - n = (cbSize - 2) / 2; - - // Same as VK_TO_WCHARS pVkToWchars[] = pVkToWcharTable[i].pVkToWchars - PVK_TO_WCHARS pVkToWchars = (PVK_TO_WCHARS) ((PVK_TO_WCHAR_TABLE) ptrCurrentVkToWcharTable)->pVkToWchars; - - if (pVkToWchars != NULL && mod < n) { - // pVkToWchars[j].VirtualKey - BYTE *pCurrentVkToWchars = (BYTE *) pVkToWchars; - - do { - if (((PVK_TO_WCHARS) pCurrentVkToWchars)->VirtualKey == keycode) { - if ((((PVK_TO_WCHARS) pCurrentVkToWchars)->Attributes == CAPLOK) && capsLock) { - if (is_shift && mod > 0) { - mod -= 1; - } - else { - mod += 1; - } - } - - // Set the initial unicode char. - WCHAR unicode = ((PVK_TO_WCHARS) pCurrentVkToWchars)->wch[mod]; - - // Increment the pCurrentVkToWchars by the size of wch[n]. - pCurrentVkToWchars += sizeof(VK_TO_WCHARS) + (sizeof(WCHAR) * n); - - - if (unicode == WCH_DEAD) { - // The current unicode char is a dead key... - if (deadChar == WCH_NONE) { - // No previous dead key was set so cache the next - // wchar so we know what to do next time its pressed. - deadChar = ((PVK_TO_WCHARS) pCurrentVkToWchars)->wch[mod]; - } - else { - if (size >= 2) { - // Received a second dead key. - memset(buffer, deadChar, 2); - //buffer[0] = deadChar; - //buffer[1] = deadChar; - - deadChar = WCH_NONE; - charCount = 2; - } - } - } - else if (unicode != WCH_NONE) { - // We are not WCH_NONE or WCH_DEAD - if (size >= 1) { - buffer[0] = unicode; - charCount = 1; - } - } - - break; - } - else { - // Add sizeof WCHAR because we are really an array of WCHAR[n] not WCHAR[] - pCurrentVkToWchars += sizeof(VK_TO_WCHARS) + (sizeof(WCHAR) * n); - } - } while ( ((PVK_TO_WCHARS) pCurrentVkToWchars)->VirtualKey != 0 ); - } - - // This is effectively the same as: ptrCurrentVkToWcharTable = pVkToWcharTable[++i]; - ptrCurrentVkToWcharTable += sizeVkToWcharTable; - } while (cbSize != 0); - - - // If the current local has a dead key set. - if (deadChar != WCH_NONE) { - // Loop over the pDeadKey lookup table for the locale. - int i; - for (i = 0; pDeadKey[i].dwBoth != 0; i++) { - WCHAR baseChar = (WCHAR) pDeadKey[i].dwBoth; - WCHAR diacritic = (WCHAR) (pDeadKey[i].dwBoth >> 16); - - // If we locate an extended dead char, set it. - if (size >= 1 && baseChar == buffer[0] && diacritic == deadChar) { - deadChar = WCH_NONE; - - if (charCount <= size) { - memset(buffer, (WCHAR) pDeadKey[i].wchComposed, charCount); - //buffer[i] = (WCHAR) pDeadKey[i].wchComposed; - } - } - } - } - } - - return charCount; -} - -int load_input_helper() { - int count = 0; - - #if defined(_WIN32) && !defined(_WIN64) - if (is_wow64()) { - ptr_padding = sizeof(void *); - } - #endif - - count = refresh_locale_list(); - - logger(LOG_LEVEL_INFO, - "%s [%u]: refresh_locale_list() found %i locale(s).\n", - __FUNCTION__, __LINE__, count); - - return count; -} - -// This returns the number of locales that were removed. -int unload_input_helper() { - int count = 0; - - // Cleanup and free memory from the old list. - KeyboardLocale* locale_item = locale_first; - while (locale_item != NULL) { - // Remove the first item from the linked list. - FreeLibrary(locale_item->library); - locale_first = locale_item->next; - free(locale_item); - locale_item = locale_first; - - count++; - } - - // Reset the current local. - locale_current = NULL; - - return count; -} diff --git a/cdeps/hook/windows/properties_c.h b/cdeps/hook/windows/properties_c.h deleted file mode 100644 index 3c8ea2b..0000000 --- a/cdeps/hook/windows/properties_c.h +++ /dev/null @@ -1,211 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include "../iohook.h" -#include "input.h" -// #include "logger.h" - -// The handle to the DLL module pulled in DllMain on DLL_PROCESS_ATTACH. -HINSTANCE hInst; - -// input_hook.c -extern void unregister_running_hooks(); - - -// Structure for the monitor_enum_proc() callback so we can track the count. -typedef struct _screen_info { - uint8_t count; - screen_data *data; -} screen_info; - - -static BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { - int width = lprcMonitor->right - lprcMonitor->left; - int height = lprcMonitor->bottom - lprcMonitor->top; - int origin_x = lprcMonitor->left; - int origin_y = lprcMonitor->top; - - if (width > 0 && height > 0) { - screen_info *screens = (screen_info *) dwData; - - if (screens->data == NULL) { - screens->data = (screen_data *) malloc(sizeof(screen_data)); - } - else { - screens->data = (screen_data *) realloc(screens, sizeof(screen_data) * screens->count); - } - - screens->data[screens->count++] = (screen_data) { - // Should monitor count start @ zero? Currently it starts at 1. - .number = screens->count, - .x = origin_x, - .y = origin_y, - .width = width, - .height = height - }; - - logger(LOG_LEVEL_INFO, "%s [%u]: Monitor %d: %ldx%ld (%ld, %ld)\n", - __FUNCTION__, __LINE__, screens->count, width, height, origin_x, origin_y); - } - - return TRUE; -} - -IOHOOK_API screen_data* hook_create_screen_info(unsigned char *count) { - // Initialize count to zero. - *count = 0; - - // Create a simple structure to make working with monitor_enum_proc easier. - screen_info screens = { - .count = 0, - .data = NULL - }; - - BOOL status = EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM) &screens); - - if (!status || screens.count == 0) { - // Fallback in case EnumDisplayMonitors fails. - logger(LOG_LEVEL_INFO, "%s [%u]: EnumDisplayMonitors failed. Fallback.\n", - __FUNCTION__, __LINE__); - - int width = GetSystemMetrics(SM_CXSCREEN); - int height = GetSystemMetrics(SM_CYSCREEN); - - if (width > 0 && height > 0) { - screens.data = (screen_data *) malloc(sizeof(screen_data)); - - if (screens.data != NULL) { - *count = 1; - screens.data[0] = (screen_data) { - .number = 1, - .x = 0, - .y = 0, - .width = width, - .height = height - }; - } - } - } else { - // Populate the count. - *count = screens.count; - } - - return screens.data; -} - -IOHOOK_API long int hook_get_auto_repeat_rate() { - long int value = -1; - long int rate; - - if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &rate, 0)) { - logger(LOG_LEVEL_INFO, "%s [%u]: SPI_GETKEYBOARDSPEED: %li.\n", - __FUNCTION__, __LINE__, rate); - - value = rate; - } - - return value; -} - -IOHOOK_API long int hook_get_auto_repeat_delay() { - long int value = -1; - long int delay; - - if (SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &delay, 0)) { - logger(LOG_LEVEL_INFO, "%s [%u]: SPI_GETKEYBOARDDELAY: %li.\n", - __FUNCTION__, __LINE__, delay); - - value = delay; - } - - return value; -} - -IOHOOK_API long int hook_get_pointer_acceleration_multiplier() { - long int value = -1; - int mouse[3]; // 0-Threshold X, 1-Threshold Y and 2-Speed. - - if (SystemParametersInfo(SPI_GETMOUSE, 0, &mouse, 0)) { - logger(LOG_LEVEL_INFO, "%s [%u]: SPI_GETMOUSE[2]: %i.\n", - __FUNCTION__, __LINE__, mouse[2]); - - value = mouse[2]; - } - - return value; -} - -IOHOOK_API long int hook_get_pointer_acceleration_threshold() { - long int value = -1; - int mouse[3]; // 0-Threshold X, 1-Threshold Y and 2-Speed. - - if (SystemParametersInfo(SPI_GETMOUSE, 0, &mouse, 0)) { - logger(LOG_LEVEL_INFO, "%s [%u]: SPI_GETMOUSE[0]: %i.\n", - __FUNCTION__, __LINE__, mouse[0]); - logger(LOG_LEVEL_INFO, "%s [%u]: SPI_GETMOUSE[1]: %i.\n", - __FUNCTION__, __LINE__, mouse[1]); - - // Average the x and y thresholds. - value = (mouse[0] + mouse[1]) / 2; - } - - return value; -} - -IOHOOK_API long int hook_get_pointer_sensitivity() { - long int value = -1; - int sensitivity; - - if (SystemParametersInfo(SPI_GETMOUSESPEED, 0, &sensitivity, 0)) { - logger(LOG_LEVEL_INFO, "%s [%u]: SPI_GETMOUSESPEED: %i.\n", - __FUNCTION__, __LINE__, sensitivity); - - value = sensitivity; - } - - return value; -} - -IOHOOK_API long int hook_get_multi_click_time() { - long int value = -1; - UINT clicktime; - - clicktime = GetDoubleClickTime(); - logger(LOG_LEVEL_INFO, "%s [%u]: GetDoubleClickTime: %u.\n", - __FUNCTION__, __LINE__, (unsigned int) clicktime); - - value = (long int) clicktime; - - return value; -} - -// DLL Entry point. -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) { - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - // Save the DLL address. - hInst = hInstDLL; - - // Initialize native input helper functions. - load_input_helper(); - break; - - case DLL_PROCESS_DETACH: - // Unregister any hooks that may still be installed. - unregister_running_hooks(); - - // Deinitialize native input helper functions. - unload_input_helper(); - break; - - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - // Do Nothing. - break; - } - - return TRUE; -} diff --git a/cdeps/hook/x11/event_c.h b/cdeps/hook/x11/event_c.h deleted file mode 100644 index 50e5ede..0000000 --- a/cdeps/hook/x11/event_c.h +++ /dev/null @@ -1,386 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include -#include -#include -#include -#ifdef USE_XTEST - #include -#endif - -#include "../iohook.h" -#include "input.h" -// #include "../logger.h" - -extern Display *properties_disp; - -// This lookup table must be in the same order the masks are defined. -#ifdef USE_XTEST -static KeySym keymask_lookup[8] = { - XK_Shift_L, - XK_Control_L, - XK_Meta_L, - XK_Alt_L, - - XK_Shift_R, - XK_Control_R, - XK_Meta_R, - XK_Alt_R -}; - -static unsigned int btnmask_lookup[5] = { - MASK_BUTTON1, - MASK_BUTTON2, - MASK_BUTTON3, - MASK_BUTTON4, - MASK_BUTTON5 -}; -#else -// TODO Possibly relocate to input helper. -static unsigned int convert_to_native_mask(unsigned int mask) { - unsigned int native_mask = 0x00; - - if (mask & (MASK_SHIFT)) { native_mask |= ShiftMask; } - if (mask & (MASK_CTRL)) { native_mask |= ControlMask; } - if (mask & (MASK_META)) { native_mask |= Mod4Mask; } - if (mask & (MASK_ALT)) { native_mask |= Mod1Mask; } - - if (mask & MASK_BUTTON1) { native_mask |= Button1Mask; } - if (mask & MASK_BUTTON2) { native_mask |= Button2Mask; } - if (mask & MASK_BUTTON3) { native_mask |= Button3Mask; } - if (mask & MASK_BUTTON4) { native_mask |= Button4Mask; } - if (mask & MASK_BUTTON5) { native_mask |= Button5Mask; } - - return native_mask; -} -#endif - -static inline void post_key_event(iohook_event * const event) { - #ifdef USE_XTEST - // FIXME Currently ignoring EVENT_KEY_TYPED. - if (event->type == EVENT_KEY_PRESSED) { - XTestFakeKeyEvent( - properties_disp, - scancode_to_keycode(event->data.keyboard.keycode), - True, - 0); - } - else if (event->type == EVENT_KEY_RELEASED) { - XTestFakeKeyEvent( - properties_disp, - scancode_to_keycode(event->data.keyboard.keycode), - False, - 0); - } - #else - XKeyEvent key_event; - - key_event.serial = 0x00; - key_event.send_event = False; - key_event.display = properties_disp; - key_event.time = CurrentTime; - key_event.same_screen = True; - - unsigned int mask; - if (!XQueryPointer(properties_disp, DefaultRootWindow(properties_disp), &(key_event.root), &(key_event.subwindow), &(key_event.x_root), &(key_event.y_root), &(key_event.x), &(key_event.y), &mask)) { - key_event.root = DefaultRootWindow(properties_disp); - key_event.window = key_event.root; - key_event.subwindow = None; - - key_event.x_root = 0; - key_event.y_root = 0; - key_event.x = 0; - key_event.y = 0; - } - - key_event.state = convert_to_native_mask(event->mask); - key_event.keycode = XKeysymToKeycode(properties_disp, scancode_to_keycode(event->data.keyboard.keycode)); - - // FIXME Currently ignoring typed events. - if (event->type == EVENT_KEY_PRESSED) { - key_event.type = KeyPress; - XSendEvent(properties_disp, InputFocus, False, KeyPressMask, (XEvent *) &key_event); - } - else if (event->type == EVENT_KEY_RELEASED) { - key_event.type = KeyRelease; - XSendEvent(properties_disp, InputFocus, False, KeyReleaseMask, (XEvent *) &key_event); - } - #endif -} - -static inline void post_mouse_button_event(iohook_event * const event) { - #ifdef USE_XTEST - Window ret_root; - Window ret_child; - int root_x; - int root_y; - int win_x; - int win_y; - unsigned int mask; - - Window win_root = XDefaultRootWindow(properties_disp); - Bool query_status = XQueryPointer(properties_disp, win_root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask); - if (query_status) { - if (event->data.mouse.x != root_x || event->data.mouse.y != root_y) { - // Move the pointer to the specified position. - XTestFakeMotionEvent(properties_disp, -1, event->data.mouse.x, event->data.mouse.y, 0); - } - else { - query_status = False; - } - } - - if (event->type == EVENT_MOUSE_WHEEL) { - // Wheel events should be the same as click events on X11. - // type, amount and rotation - if (event->data.wheel.rotation < 0) { - XTestFakeButtonEvent(properties_disp, WheelUp, True, 0); - XTestFakeButtonEvent(properties_disp, WheelUp, False, 0); - } - else { - XTestFakeButtonEvent(properties_disp, WheelDown, True, 0); - XTestFakeButtonEvent(properties_disp, WheelDown, False, 0); - } - } - else if (event->type == EVENT_MOUSE_PRESSED) { - XTestFakeButtonEvent(properties_disp, event->data.mouse.button, True, 0); - } - else if (event->type == EVENT_MOUSE_RELEASED) { - XTestFakeButtonEvent(properties_disp, event->data.mouse.button, False, 0); - } - else if (event->type == EVENT_MOUSE_CLICKED) { - XTestFakeButtonEvent(properties_disp, event->data.mouse.button, True, 0); - XTestFakeButtonEvent(properties_disp, event->data.mouse.button, False, 0); - } - - if (query_status) { - // Move the pointer back to the original position. - XTestFakeMotionEvent(properties_disp, -1, root_x, root_y, 0); - } - #else - XButtonEvent btn_event; - - btn_event.serial = 0x00; - btn_event.send_event = False; - btn_event.display = properties_disp; - btn_event.time = CurrentTime; - btn_event.same_screen = True; - - btn_event.root = DefaultRootWindow(properties_disp); - btn_event.window = btn_event.root; - btn_event.subwindow = None; - - btn_event.type = 0x00; - btn_event.state = 0x00; - btn_event.x_root = 0; - btn_event.y_root = 0; - btn_event.x = 0; - btn_event.y = 0; - btn_event.button = 0x00; - - btn_event.state = convert_to_native_mask(event->mask); - - btn_event.x = event->data.mouse.x; - btn_event.y = event->data.mouse.y; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t screen_count; - screen_data *screens = hook_create_screen_info(&screen_count); - if (screen_count > 1) { - btn_event.x += screens[0].x; - btn_event.y += screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - // These are the same because Window == Root Window. - btn_event.x_root = btn_event.x; - btn_event.y_root = btn_event.y; - - if (event->type == EVENT_MOUSE_WHEEL) { - // type, amount and rotation - if (event->data.wheel.rotation < 0) { - btn_event.button = WheelUp; - } - else { - btn_event.button = WheelDown; - } - } - - if (event->type != EVENT_MOUSE_RELEASED) { - // FIXME Where do we set event->button? - btn_event.type = ButtonPress; - XSendEvent(properties_disp, InputFocus, False, ButtonPressMask, (XEvent *) &btn_event); - } - - if (event->type != EVENT_MOUSE_PRESSED) { - btn_event.type = ButtonRelease; - XSendEvent(properties_disp, InputFocus, False, ButtonReleaseMask, (XEvent *) &btn_event); - } - #endif -} - -static inline void post_mouse_motion_event(iohook_event * const event) { - #ifdef USE_XTEST - XTestFakeMotionEvent(properties_disp, -1, event->data.mouse.x, event->data.mouse.y, 0); - #else - XMotionEvent mov_event; - - mov_event.serial = MotionNotify; - mov_event.send_event = False; - mov_event.display = properties_disp; - mov_event.time = CurrentTime; - mov_event.same_screen = True; - mov_event.is_hint = NotifyNormal, - mov_event.root = DefaultRootWindow(properties_disp); - mov_event.window = mov_event.root; - mov_event.subwindow = None; - - mov_event.type = 0x00; - mov_event.state = 0x00; - mov_event.x_root = 0; - mov_event.y_root = 0; - mov_event.x = 0; - mov_event.y = 0; - - mov_event.state = convert_to_native_mask(event->mask); - - mov_event.x = event->data.mouse.x; - mov_event.y = event->data.mouse.y; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t screen_count; - screen_data *screens = hook_create_screen_info(&screen_count); - if (screen_count > 1) { - mov_event.x += screens[0].x; - mov_event.y += screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - // These are the same because Window == Root Window. - mov_event.x_root = mov_event.x; - mov_event.y_root = mov_event.y; - - long int event_mask = NoEventMask; - if (event->type == EVENT_MOUSE_DRAGGED) { - #if Button1Mask == Button1MotionMask && \ - Button2Mask == Button2MotionMask && \ - Button3Mask == Button3MotionMask && \ - Button4Mask == Button4MotionMask && \ - Button5Mask == Button5MotionMask - // This little trick only works if Button#MotionMasks align with - // the Button#Masks. - event_mask = mov_event.state & - (Button1MotionMask | Button2MotionMask | - Button2MotionMask | Button3MotionMask | Button5MotionMask); - #else - // Fallback to some slightly larger... - if (event->state & Button1Mask) { - event_mask |= Button1MotionMask; - } - - if (event->state & Button2Mask) { - event_mask |= Button2MotionMask; - } - - if (event->state & Button3Mask) { - event_mask |= Button3MotionMask; - } - - if (event->state & Button4Mask) { - event_mask |= Button4MotionMask; - } - - if (event->state & Button5Mask) { - event_mask |= Button5MotionMask; - } - #endif - } - - // NOTE x_mask = NoEventMask. - XSendEvent(properties_disp, InputFocus, False, event_mask, (XEvent *) &mov_event); - #endif -} - -IOHOOK_API void hook_post_event(iohook_event * const event) { - XLockDisplay(properties_disp); - - #ifdef USE_XTEST - // XTest does not have modifier support, so we fake it by depressing the - // appropriate modifier keys. - unsigned int i; - for (i = 0; i < sizeof(keymask_lookup) / sizeof(KeySym); i++) { - if (event->mask & 1 << i) { - XTestFakeKeyEvent(properties_disp, XKeysymToKeycode(properties_disp, keymask_lookup[i]), True, 0); - } - } - - unsigned int i; - for (i = 0; i < sizeof(btnmask_lookup) / sizeof(unsigned int); i++) { - if (event->mask & btnmask_lookup[i]) { - XTestFakeButtonEvent(properties_disp, i + 1, True, 0); - } - } - #endif - - switch (event->type) { - case EVENT_KEY_PRESSED: - case EVENT_KEY_RELEASED: - case EVENT_KEY_TYPED: - post_key_event(event); - break; - - case EVENT_MOUSE_PRESSED: - case EVENT_MOUSE_RELEASED: - case EVENT_MOUSE_WHEEL: - case EVENT_MOUSE_CLICKED: - post_mouse_button_event(event); - break; - - case EVENT_MOUSE_DRAGGED: - case EVENT_MOUSE_MOVED: - post_mouse_motion_event(event); - break; - - case EVENT_HOOK_ENABLED: - case EVENT_HOOK_DISABLED: - // Ignore hook enabled / disabled events. - - default: - // Ignore any other garbage. - logger(LOG_LEVEL_WARN, "%s [%u]: Ignoring post event type %#X\n", - __FUNCTION__, __LINE__, event->type); - break; - } - - #ifdef USE_XTEST - // Release the previously held modifier keys used to fake the event mask. - unsigned int i ; - for (i= 0; i < sizeof(keymask_lookup) / sizeof(KeySym); i++) { - if (event->mask & 1 << i) { - XTestFakeKeyEvent(properties_disp, XKeysymToKeycode(properties_disp, keymask_lookup[i]), False, 0); - } - } - unsigned int i; - for (i = 0; i < sizeof(btnmask_lookup) / sizeof(unsigned int); i++) { - if (event->mask & btnmask_lookup[i]) { - XTestFakeButtonEvent(properties_disp, i + 1, False, 0); - } - } - #endif - - // Don't forget to flush! - XSync(properties_disp, True); - XUnlockDisplay(properties_disp); -} diff --git a/cdeps/hook/x11/hook_c.h b/cdeps/hook/x11/hook_c.h deleted file mode 100644 index 4be4b60..0000000 --- a/cdeps/hook/x11/hook_c.h +++ /dev/null @@ -1,1132 +0,0 @@ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#define USE_XKB 0 -#define USE_XKBCOMMON 0 -#include -#include -#ifdef USE_XRECORD_ASYNC - #include -#endif -#include - -#include -#include -#include -#include -// #ifdef USE_XKB -#include -#include -// #endif -#if defined(USE_XINERAMA) && !defined(USE_XRANDR) - #include -#elif defined(USE_XRANDR) - #include -#else -// TODO We may need to fallback to the xf86vm extension for things like TwinView. -// #pragma message("*** Warning: Xinerama or XRandR support is required to produce cross-platform mouse coordinates for multi-head configurations!") -// #pragma message("... Assuming single-head display.") -#endif - -#include "../iohook.h" -// #include "../logger.h" -#include "input.h" - -// Thread and hook handles. -#ifdef USE_XRECORD_ASYNC -static bool running; - -static pthread_cond_t hook_xrecord_cond = PTHREAD_COND_INITIALIZER; -static pthread_mutex_t hook_xrecord_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -typedef struct _hook_info { - struct _data { - Display *display; - XRecordRange *range; - } data; - struct _ctrl { - Display *display; - XRecordContext context; - } ctrl; - struct _input { - #ifdef USE_XKBCOMMON - xcb_connection_t *connection; - struct xkb_context *context; - #endif - uint16_t mask; - struct _mouse { - bool is_dragged; - struct _click { - unsigned short int count; - long int time; - unsigned short int button; - } click; - } mouse; - } input; -} hook_info; -static hook_info *hook; - -// For this struct, refer to libxnee, requires Xlibint.h -typedef union { - unsigned char type; - xEvent event; - xResourceReq req; - xGenericReply reply; - xError error; - xConnSetupPrefix setup; -} XRecordDatum; - -#if defined(USE_XKBCOMMON) -//struct xkb_keymap *keymap; -//struct xkb_state *state = xkb_state_new(keymap); -static struct xkb_state *state = NULL; -#endif - -// Virtual event pointer. -static iohook_event event; - -// Event dispatch callback. -static dispatcher_t dispatcher = NULL; - -IOHOOK_API void hook_set_dispatch_proc(dispatcher_t dispatch_proc) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Setting new dispatch callback to %#p.\n", - __FUNCTION__, __LINE__, dispatch_proc); - - dispatcher = dispatch_proc; -} - -// Send out an event if a dispatcher was set. -static inline void dispatch_event(iohook_event *const event) { - if (dispatcher != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Dispatching event type %u.\n", - __FUNCTION__, __LINE__, event->type); - - dispatcher(event); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: No dispatch callback set!\n", - __FUNCTION__, __LINE__); - } -} - -// Set the native modifier mask for future events. -static inline void set_modifier_mask(uint16_t mask) { - hook->input.mask |= mask; -} - -// Unset the native modifier mask for future events. -static inline void unset_modifier_mask(uint16_t mask) { - hook->input.mask &= ~mask; -} - -// Get the current native modifier mask state. -static inline uint16_t get_modifiers() { - return hook->input.mask; -} - -// Initialize the modifier lock masks. -static void initialize_locks() { - #ifdef USE_XKBCOMMON - - if (xkb_state_led_name_is_active(state, XKB_LED_NAME_CAPS)) { - set_modifier_mask(MASK_CAPS_LOCK); - } - else { - unset_modifier_mask(MASK_CAPS_LOCK); - } - - if (xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM)) { - set_modifier_mask(MASK_NUM_LOCK); - } - else { - unset_modifier_mask(MASK_NUM_LOCK); - } - - if (xkb_state_led_name_is_active(state, XKB_LED_NAME_SCROLL)) { - set_modifier_mask(MASK_SCROLL_LOCK); - } - else { - unset_modifier_mask(MASK_SCROLL_LOCK); - } - #else - unsigned int led_mask = 0x00; - if (XkbGetIndicatorState(hook->ctrl.display, XkbUseCoreKbd, &led_mask) == Success) { - if (led_mask & 0x01) { - set_modifier_mask(MASK_CAPS_LOCK); - } - else { - unset_modifier_mask(MASK_CAPS_LOCK); - } - - if (led_mask & 0x02) { - set_modifier_mask(MASK_NUM_LOCK); - } - else { - unset_modifier_mask(MASK_NUM_LOCK); - } - - if (led_mask & 0x04) { - set_modifier_mask(MASK_SCROLL_LOCK); - } - else { - unset_modifier_mask(MASK_SCROLL_LOCK); - } - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: XkbGetIndicatorState failed to get current led mask!\n", - __FUNCTION__, __LINE__); - } - #endif -} - -// Initialize the modifier mask to the current modifiers. -static void initialize_modifiers() { - hook->input.mask = 0x0000; - - KeyCode keycode; - char keymap[32]; - XQueryKeymap(hook->ctrl.display, keymap); - - Window unused_win; - int unused_int; - unsigned int mask; - if (XQueryPointer(hook->ctrl.display, DefaultRootWindow(hook->ctrl.display), &unused_win, &unused_win, &unused_int, &unused_int, &unused_int, &unused_int, &mask)) { - if (mask & ShiftMask) { - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Shift_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_SHIFT_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Shift_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_SHIFT_R); } - } - if (mask & ControlMask) { - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Control_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_CTRL_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Control_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_CTRL_R); } - } - if (mask & Mod1Mask) { - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Alt_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_ALT_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Alt_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_ALT_R); } - } - if (mask & Mod4Mask) { - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Super_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_META_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Super_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_META_R); } - } - - if (mask & Button1Mask) { set_modifier_mask(MASK_BUTTON1); } - if (mask & Button2Mask) { set_modifier_mask(MASK_BUTTON2); } - if (mask & Button3Mask) { set_modifier_mask(MASK_BUTTON3); } - if (mask & Button4Mask) { set_modifier_mask(MASK_BUTTON4); } - if (mask & Button5Mask) { set_modifier_mask(MASK_BUTTON5); } - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: XQueryPointer failed to get current modifiers!\n", - __FUNCTION__, __LINE__); - - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Shift_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_SHIFT_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Shift_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_SHIFT_R); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Control_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_CTRL_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Control_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_CTRL_R); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Alt_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_ALT_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Alt_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_ALT_R); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Super_L); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_META_L); } - keycode = XKeysymToKeycode(hook->ctrl.display, XK_Super_R); - if (keymap[keycode / 8] & (1 << (keycode % 8))) { set_modifier_mask(MASK_META_R); } - } - - initialize_locks(); -} - -void hook_event_proc(XPointer closeure, XRecordInterceptData *recorded_data) { - uint64_t timestamp = (uint64_t) recorded_data->server_time; - - if (recorded_data->category == XRecordStartOfData) { - // Populate the hook start event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_HOOK_ENABLED; - event.mask = 0x00; - - // Fire the hook start event. - dispatch_event(&event); - } - else if (recorded_data->category == XRecordEndOfData) { - // Populate the hook stop event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_HOOK_DISABLED; - event.mask = 0x00; - - // Fire the hook stop event. - dispatch_event(&event); - } - else if (recorded_data->category == XRecordFromServer || recorded_data->category == XRecordFromClient) { - // Get XRecord data. - XRecordDatum *data = (XRecordDatum *) recorded_data->data; - - if (data->type == KeyPress) { - // The X11 KeyCode associated with this event. - KeyCode keycode = (KeyCode) data->event.u.u.detail; - KeySym keysym = 0x00; - #if defined(USE_XKBCOMMON) - if (state != NULL) { - keysym = xkb_state_key_get_one_sym(state, keycode); - } - #else - keysym = keycode_to_keysym(keycode, data->event.u.keyButtonPointer.state); - #endif - - unsigned short int scancode = keycode_to_scancode(keycode); - - // TODO If you have a better suggestion for this ugly, let me know. - if (scancode == VC_SHIFT_L) { set_modifier_mask(MASK_SHIFT_L); } - else if (scancode == VC_SHIFT_R) { set_modifier_mask(MASK_SHIFT_R); } - else if (scancode == VC_CONTROL_L) { set_modifier_mask(MASK_CTRL_L); } - else if (scancode == VC_CONTROL_R) { set_modifier_mask(MASK_CTRL_R); } - else if (scancode == VC_ALT_L) { set_modifier_mask(MASK_ALT_L); } - else if (scancode == VC_ALT_R) { set_modifier_mask(MASK_ALT_R); } - else if (scancode == VC_META_L) { set_modifier_mask(MASK_META_L); } - else if (scancode == VC_META_R) { set_modifier_mask(MASK_META_R); } - xkb_state_update_key(state, keycode, XKB_KEY_DOWN); - initialize_locks(); - - if ((get_modifiers() & MASK_NUM_LOCK) == 0) { - switch (scancode) { - case VC_KP_SEPARATOR: - case VC_KP_1: - case VC_KP_2: - case VC_KP_3: - case VC_KP_4: - case VC_KP_5: - case VC_KP_6: - case VC_KP_7: - case VC_KP_8: - case VC_KP_0: - case VC_KP_9: - scancode |= 0xEE00; - break; - } - } - - // Populate key pressed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_KEY_PRESSED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = scancode; - event.data.keyboard.rawcode = keysym; - event.data.keyboard.keychar = CHAR_UNDEFINED; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X pressed. (%#X)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, event.data.keyboard.rawcode); - - // Fire key pressed event. - dispatch_event(&event); - - // If the pressed event was not consumed... - if (event.reserved ^ 0x01) { - uint16_t buffer[2]; - size_t count = 0; - - // Check to make sure the key is printable. - #ifdef USE_XKBCOMMON - if (state != NULL) { - count = keycode_to_unicode(state, keycode, buffer, sizeof(buffer) / sizeof(uint16_t)); - } - #else - count = keysym_to_unicode(keysym, buffer, sizeof(buffer) / sizeof(uint16_t)); - #endif - - unsigned int i; - for (i = 0; i < count; i++) { - // Populate key typed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_KEY_TYPED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = VC_UNDEFINED; - event.data.keyboard.rawcode = keysym; - event.data.keyboard.keychar = buffer[i]; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X typed. (%lc)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, (uint16_t) event.data.keyboard.keychar); - - // Fire key typed event. - dispatch_event(&event); - } - } - } - else if (data->type == KeyRelease) { - // The X11 KeyCode associated with this event. - KeyCode keycode = (KeyCode) data->event.u.u.detail; - KeySym keysym = 0x00; - #ifdef USE_XKBCOMMON - if (state != NULL) { - keysym = xkb_state_key_get_one_sym(state, keycode); - } - #else - keysym = keycode_to_keysym(keycode, data->event.u.keyButtonPointer.state); - #endif - - unsigned short int scancode = keycode_to_scancode(keycode); - - // TODO If you have a better suggestion for this ugly, let me know. - if (scancode == VC_SHIFT_L) { unset_modifier_mask(MASK_SHIFT_L); } - else if (scancode == VC_SHIFT_R) { unset_modifier_mask(MASK_SHIFT_R); } - else if (scancode == VC_CONTROL_L) { unset_modifier_mask(MASK_CTRL_L); } - else if (scancode == VC_CONTROL_R) { unset_modifier_mask(MASK_CTRL_R); } - else if (scancode == VC_ALT_L) { unset_modifier_mask(MASK_ALT_L); } - else if (scancode == VC_ALT_R) { unset_modifier_mask(MASK_ALT_R); } - else if (scancode == VC_META_L) { unset_modifier_mask(MASK_META_L); } - else if (scancode == VC_META_R) { unset_modifier_mask(MASK_META_R); } - xkb_state_update_key(state, keycode, XKB_KEY_UP); - initialize_locks(); - - if ((get_modifiers() & MASK_NUM_LOCK) == 0) { - switch (scancode) { - case VC_KP_SEPARATOR: - case VC_KP_1: - case VC_KP_2: - case VC_KP_3: - case VC_KP_4: - case VC_KP_5: - case VC_KP_6: - case VC_KP_7: - case VC_KP_8: - case VC_KP_0: - case VC_KP_9: - scancode |= 0xEE00; - break; - } - } - - // Populate key released event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_KEY_RELEASED; - event.mask = get_modifiers(); - - event.data.keyboard.keycode = scancode; - event.data.keyboard.rawcode = keysym; - event.data.keyboard.keychar = CHAR_UNDEFINED; - - logger(LOG_LEVEL_INFO, "%s [%u]: Key %#X released. (%#X)\n", - __FUNCTION__, __LINE__, event.data.keyboard.keycode, event.data.keyboard.rawcode); - - // Fire key released event. - dispatch_event(&event); - } - else if (data->type == ButtonPress) { - // X11 handles wheel events as button events. - if (data->event.u.u.detail == WheelUp || data->event.u.u.detail == WheelDown - || data->event.u.u.detail == WheelLeft || data->event.u.u.detail == WheelRight) { - - // Reset the click count and previous button. - hook->input.mouse.click.count = 1; - hook->input.mouse.click.button = MOUSE_NOBUTTON; - - /* Scroll wheel release events. - * Scroll type: WHEEL_UNIT_SCROLL - * Scroll amount: 3 unit increments per notch - * Units to scroll: 3 unit increments - * Vertical unit increment: 15 pixels - */ - - // Populate mouse wheel event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_WHEEL; - event.mask = get_modifiers(); - - event.data.wheel.clicks = hook->input.mouse.click.count; - event.data.wheel.x = data->event.u.keyButtonPointer.rootX; - event.data.wheel.y = data->event.u.keyButtonPointer.rootY; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t count; - screen_data *screens = hook_create_screen_info(&count); - if (count > 1) { - event.data.wheel.x -= screens[0].x; - event.data.wheel.y -= screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - /* X11 does not have an API call for acquiring the mouse scroll type. This - * maybe part of the XInput2 (XI2) extention but I will wont know until it - * is available on my platform. For the time being we will just use the - * unit scroll value. - */ - event.data.wheel.type = WHEEL_UNIT_SCROLL; - - /* Some scroll wheel properties are available via the new XInput2 (XI2) - * extension. Unfortunately the extension is not available on my - * development platform at this time. For the time being we will just - * use the Windows default value of 3. - */ - event.data.wheel.amount = 3; - - if (data->event.u.u.detail == WheelUp || data->event.u.u.detail == WheelLeft) { - // Wheel Rotated Up and Away. - event.data.wheel.rotation = -1; - } - else { // data->event.u.u.detail == WheelDown - // Wheel Rotated Down and Towards. - event.data.wheel.rotation = 1; - } - - if (data->event.u.u.detail == WheelUp || data->event.u.u.detail == WheelDown) { - // Wheel Rotated Up or Down. - event.data.wheel.direction = WHEEL_VERTICAL_DIRECTION; - } - else { // data->event.u.u.detail == WheelLeft || data->event.u.u.detail == WheelRight - // Wheel Rotated Left or Right. - event.data.wheel.direction = WHEEL_HORIZONTAL_DIRECTION; - } - - logger(LOG_LEVEL_INFO, "%s [%u]: Mouse wheel type %u, rotated %i units in the %u direction at %u, %u.\n", - __FUNCTION__, __LINE__, event.data.wheel.type, - event.data.wheel.amount * event.data.wheel.rotation, - event.data.wheel.direction, - event.data.wheel.x, event.data.wheel.y); - - // Fire mouse wheel event. - dispatch_event(&event); - } - else { - /* This information is all static for X11, its up to the WM to - * decide how to interpret the wheel events. - */ - uint16_t button = MOUSE_NOBUTTON; - switch (data->event.u.u.detail) { - // FIXME This should use a lookup table to handle button remapping. - case Button1: - button = MOUSE_BUTTON1; - set_modifier_mask(MASK_BUTTON1); - break; - - case Button2: - button = MOUSE_BUTTON2; - set_modifier_mask(MASK_BUTTON2); - break; - - case Button3: - button = MOUSE_BUTTON3; - set_modifier_mask(MASK_BUTTON3); - break; - - case XButton1: - button = MOUSE_BUTTON4; - set_modifier_mask(MASK_BUTTON5); - break; - - case XButton2: - button = MOUSE_BUTTON5; - set_modifier_mask(MASK_BUTTON5); - break; - - default: - // Do not set modifier masks past button MASK_BUTTON5. - break; - } - - - // Track the number of clicks, the button must match the previous button. - if (button == hook->input.mouse.click.button && (long int) (timestamp - hook->input.mouse.click.time) <= hook_get_multi_click_time()) { - if (hook->input.mouse.click.count < USHRT_MAX) { - hook->input.mouse.click.count++; - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: Click count overflow detected!\n", - __FUNCTION__, __LINE__); - } - } - else { - // Reset the click count. - hook->input.mouse.click.count = 1; - - // Set the previous button. - hook->input.mouse.click.button = button; - } - - // Save this events time to calculate the hook->input.mouse.click.count. - hook->input.mouse.click.time = timestamp; - - - // Populate mouse pressed event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_PRESSED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = hook->input.mouse.click.count; - event.data.mouse.x = data->event.u.keyButtonPointer.rootX; - event.data.mouse.y = data->event.u.keyButtonPointer.rootY; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t count; - screen_data *screens = hook_create_screen_info(&count); - if (count > 1) { - event.data.mouse.x -= screens[0].x; - event.data.mouse.y -= screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u pressed %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse pressed event. - dispatch_event(&event); - } - } - else if (data->type == ButtonRelease) { - // X11 handles wheel events as button events. - if (data->event.u.u.detail != WheelUp && data->event.u.u.detail != WheelDown) { - /* This information is all static for X11, its up to the WM to - * decide how to interpret the wheel events. - */ - uint16_t button = MOUSE_NOBUTTON; - switch (data->event.u.u.detail) { - // FIXME This should use a lookup table to handle button remapping. - case Button1: - button = MOUSE_BUTTON1; - unset_modifier_mask(MASK_BUTTON1); - break; - - case Button2: - button = MOUSE_BUTTON2; - unset_modifier_mask(MASK_BUTTON2); - break; - - case Button3: - button = MOUSE_BUTTON3; - unset_modifier_mask(MASK_BUTTON3); - break; - - case XButton1: - button = MOUSE_BUTTON4; - unset_modifier_mask(MASK_BUTTON5); - break; - - case XButton2: - button = MOUSE_BUTTON5; - unset_modifier_mask(MASK_BUTTON5); - break; - - default: - // Do not set modifier masks past button MASK_BUTTON5. - break; - } - - // Populate mouse released event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_RELEASED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = hook->input.mouse.click.count; - event.data.mouse.x = data->event.u.keyButtonPointer.rootX; - event.data.mouse.y = data->event.u.keyButtonPointer.rootY; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t count; - screen_data *screens = hook_create_screen_info(&count); - if (count > 1) { - event.data.mouse.x -= screens[0].x; - event.data.mouse.y -= screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u released %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, - event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse released event. - dispatch_event(&event); - - // If the pressed event was not consumed... - if (event.reserved ^ 0x01 && hook->input.mouse.is_dragged != true) { - // Populate mouse clicked event. - event.time = timestamp; - event.reserved = 0x00; - - event.type = EVENT_MOUSE_CLICKED; - event.mask = get_modifiers(); - - event.data.mouse.button = button; - event.data.mouse.clicks = hook->input.mouse.click.count; - event.data.mouse.x = data->event.u.keyButtonPointer.rootX; - event.data.mouse.y = data->event.u.keyButtonPointer.rootY; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t count; - screen_data *screens = hook_create_screen_info(&count); - if (count > 1) { - event.data.mouse.x -= screens[0].x; - event.data.mouse.y -= screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - logger(LOG_LEVEL_INFO, "%s [%u]: Button %u clicked %u time(s). (%u, %u)\n", - __FUNCTION__, __LINE__, event.data.mouse.button, - event.data.mouse.clicks, - event.data.mouse.x, event.data.mouse.y); - - // Fire mouse clicked event. - dispatch_event(&event); - } - - // Reset the number of clicks. - if (button == hook->input.mouse.click.button && (long int) (event.time - hook->input.mouse.click.time) > hook_get_multi_click_time()) { - // Reset the click count. - hook->input.mouse.click.count = 0; - } - } - } - else if (data->type == MotionNotify) { - // Reset the click count. - if (hook->input.mouse.click.count != 0 && (long int) (timestamp - hook->input.mouse.click.time) > hook_get_multi_click_time()) { - hook->input.mouse.click.count = 0; - } - - // Populate mouse move event. - event.time = timestamp; - event.reserved = 0x00; - - event.mask = get_modifiers(); - - // Check the upper half of virtual modifiers for non-zero - // values and set the mouse dragged flag. - hook->input.mouse.is_dragged = (event.mask >> 8 > 0); - if (hook->input.mouse.is_dragged) { - // Create Mouse Dragged event. - event.type = EVENT_MOUSE_DRAGGED; - } - else { - // Create a Mouse Moved event. - event.type = EVENT_MOUSE_MOVED; - } - - event.data.mouse.button = MOUSE_NOBUTTON; - event.data.mouse.clicks = hook->input.mouse.click.count; - event.data.mouse.x = data->event.u.keyButtonPointer.rootX; - event.data.mouse.y = data->event.u.keyButtonPointer.rootY; - - #if defined(USE_XINERAMA) || defined(USE_XRANDR) - uint8_t count; - screen_data *screens = hook_create_screen_info(&count); - if (count > 1) { - event.data.mouse.x -= screens[0].x; - event.data.mouse.y -= screens[0].y; - } - - if (screens != NULL) { - free(screens); - } - #endif - - logger(LOG_LEVEL_INFO, "%s [%u]: Mouse %s to %i, %i. (%#X)\n", - __FUNCTION__, __LINE__, hook->input.mouse.is_dragged ? "dragged" : "moved", - event.data.mouse.x, event.data.mouse.y, event.mask); - - // Fire mouse move event. - dispatch_event(&event); - } - else { - // In theory this *should* never execute. - logger(LOG_LEVEL_DEBUG, "%s [%u]: Unhandled X11 event: %#X.\n", - __FUNCTION__, __LINE__, (unsigned int) data->type); - } - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: Unhandled X11 hook category! (%#X)\n", - __FUNCTION__, __LINE__, recorded_data->category); - } - - // TODO There is no way to consume the XRecord event. - - XRecordFreeData(recorded_data); -} - - -static inline bool enable_key_repeate() { - // Attempt to setup detectable autorepeat. - // NOTE: is_auto_repeat is NOT stdbool! - Bool is_auto_repeat = False; - #ifdef USE_XKB - // Enable detectable auto-repeat. - XkbSetDetectableAutoRepeat(hook->ctrl.display, True, &is_auto_repeat); - #else - XAutoRepeatOn(hook->ctrl.display); - - XKeyboardState kb_state; - XGetKeyboardControl(hook->ctrl.display, &kb_state); - - is_auto_repeat = (kb_state.global_auto_repeat == AutoRepeatModeOn); - #endif - - return is_auto_repeat; -} - - -static inline int xrecord_block() { - int status = IOHOOK_FAILURE; - - // Save the data display associated with this hook so it is passed to each event. - //XPointer closeure = (XPointer) (ctrl_display); - XPointer closeure = NULL; - - #ifdef USE_XRECORD_ASYNC - // Async requires that we loop so that our thread does not return. - if (XRecordEnableContextAsync(hook->data.display, context, hook_event_proc, closeure) != 0) { - // Time in MS to sleep the runloop. - int timesleep = 100; - - // Allow the thread loop to block. - pthread_mutex_lock(&hook_xrecord_mutex); - running = true; - - do { - // Unlock the mutex from the previous iteration. - pthread_mutex_unlock(&hook_xrecord_mutex); - - XRecordProcessReplies(hook->data.display); - - // Prevent 100% CPU utilization. - struct timeval tv; - gettimeofday(&tv, NULL); - - struct timespec ts; - ts.tv_sec = time(NULL) + timesleep / 1000; - ts.tv_nsec = tv.tv_usec * 1000 + 1000 * 1000 * (timesleep % 1000); - ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000); - ts.tv_nsec %= (1000 * 1000 * 1000); - - pthread_mutex_lock(&hook_xrecord_mutex); - pthread_cond_timedwait(&hook_xrecord_cond, &hook_xrecord_mutex, &ts); - } while (running); - - // Unlock after loop exit. - pthread_mutex_unlock(&hook_xrecord_mutex); - - // Set the exit status. - status = NULL; - } - #else - // Sync blocks until XRecordDisableContext() is called. - if (XRecordEnableContext(hook->data.display, hook->ctrl.context, hook_event_proc, closeure) != 0) { - status = IOHOOK_SUCCESS; - } - #endif - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XRecordEnableContext failure!\n", - __FUNCTION__, __LINE__); - - #ifdef USE_XRECORD_ASYNC - // Reset the running state. - pthread_mutex_lock(&hook_xrecord_mutex); - running = false; - pthread_mutex_unlock(&hook_xrecord_mutex); - #endif - - // Set the exit status. - status = IOHOOK_ERROR_X_RECORD_ENABLE_CONTEXT; - } - - return status; -} - -static int xrecord_alloc() { - int status = IOHOOK_FAILURE; - - // Make sure the data display is synchronized to prevent late event delivery! - // See Bug 42356 for more information. - // https://bugs.freedesktop.org/show_bug.cgi?id=42356#c4 - XSynchronize(hook->data.display, True); - - // Setup XRecord range. - XRecordClientSpec clients = XRecordAllClients; - - hook->data.range = XRecordAllocRange(); - if (hook->data.range != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: XRecordAllocRange successful.\n", - __FUNCTION__, __LINE__); - - hook->data.range->device_events.first = KeyPress; - hook->data.range->device_events.last = MotionNotify; - - // Note that the documentation for this function is incorrect, - // hook->data.display should be used! - // See: http://www.x.org/releases/X11R7.6/doc/libXtst/recordlib.txt - hook->ctrl.context = XRecordCreateContext(hook->data.display, XRecordFromServerTime, &clients, 1, &hook->data.range, 1); - if (hook->ctrl.context != 0) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: XRecordCreateContext successful.\n", - __FUNCTION__, __LINE__); - - // Block until hook_stop() is called. - status = xrecord_block(); - - // Free up the context if it was set. - XRecordFreeContext(hook->data.display, hook->ctrl.context); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XRecordCreateContext failure!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_X_RECORD_CREATE_CONTEXT; - } - - // Free the XRecord range. - XFree(hook->data.range); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XRecordAllocRange failure!\n", - __FUNCTION__, __LINE__); - - // Set the exit status. - status = IOHOOK_ERROR_X_RECORD_ALLOC_RANGE; - } - - return status; -} - -static int xrecord_query() { - int status = IOHOOK_FAILURE; - - // Check to make sure XRecord is installed and enabled. - int major, minor; - if (XRecordQueryVersion(hook->ctrl.display, &major, &minor) != 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: XRecord version: %i.%i.\n", - __FUNCTION__, __LINE__, major, minor); - - status = xrecord_alloc(); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XRecord is not currently available!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_X_RECORD_NOT_FOUND; - } - - return status; -} - -static int xrecord_start() { - int status = IOHOOK_FAILURE; - - // Open the control display for XRecord. - hook->ctrl.display = XOpenDisplay(NULL); - - // Open a data display for XRecord. - // NOTE This display must be opened on the same thread as XRecord. - hook->data.display = XOpenDisplay(NULL); - if (hook->ctrl.display != NULL && hook->data.display != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: XOpenDisplay successful.\n", - __FUNCTION__, __LINE__); - - bool is_auto_repeat = enable_key_repeate(); - if (is_auto_repeat) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Successfully enabled detectable autorepeat.\n", - __FUNCTION__, __LINE__); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: Could not enable detectable auto-repeat!\n", - __FUNCTION__, __LINE__); - } - - #if defined(USE_XKBCOMMON) - // Open XCB Connection - hook->input.connection = XGetXCBConnection(hook->ctrl.display); - int xcb_status = xcb_connection_has_error(hook->input.connection); - if (xcb_status <= 0) { - // Initialize xkbcommon context. - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - if (context != NULL) { - hook->input.context = xkb_context_ref(context); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: xkb_context_new failure!\n", - __FUNCTION__, __LINE__); - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: xcb_connect failure! (%d)\n", - __FUNCTION__, __LINE__, xcb_status); - } - #endif - - #ifdef USE_XKBCOMMON - state = create_xkb_state(hook->input.context, hook->input.connection); - #endif - - // Initialize starting modifiers. - initialize_modifiers(); - - status = xrecord_query(); - - #ifdef USE_XKBCOMMON - if (state != NULL) { - destroy_xkb_state(state); - } - - if (hook->input.context != NULL) { - xkb_context_unref(hook->input.context); - hook->input.context = NULL; - } - - if (hook->input.connection != NULL) { - // xcb_disconnect(hook->input.connection); - hook->input.connection = NULL; - } - #endif - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XOpenDisplay failure!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_X_OPEN_DISPLAY; - } - - // Close down the XRecord data display. - if (hook->data.display != NULL) { - XCloseDisplay(hook->data.display); - hook->data.display = NULL; - } - - // Close down the XRecord control display. - if (hook->ctrl.display) { - XCloseDisplay(hook->ctrl.display); - hook->ctrl.display = NULL; - } - - return status; -} - -IOHOOK_API int hook_run() { - int status = IOHOOK_FAILURE; - - // Hook data for future cleanup. - hook = malloc(sizeof(hook_info)); - if (hook != NULL) { - hook->input.mask = 0x0000; - hook->input.mouse.is_dragged = false; - hook->input.mouse.click.count = 0; - hook->input.mouse.click.time = 0; - hook->input.mouse.click.button = MOUSE_NOBUTTON; - - status = xrecord_start(); - - // Free data associated with this hook. - free(hook); - hook = NULL; - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to allocate memory for hook structure!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_OUT_OF_MEMORY; - } - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Something, something, something, complete.\n", - __FUNCTION__, __LINE__); - - return status; -} - -IOHOOK_API int hook_stop() { - int status = IOHOOK_FAILURE; - - if (hook != NULL && hook->ctrl.display != NULL && hook->ctrl.context != 0) { - // We need to make sure the context is still valid. - XRecordState *state = malloc(sizeof(XRecordState)); - if (state != NULL) { - if (XRecordGetContext(hook->ctrl.display, hook->ctrl.context, &state) != 0) { - // Try to exit the thread naturally. - if (state->enabled && XRecordDisableContext(hook->ctrl.display, hook->ctrl.context) != 0) { - #ifdef USE_XRECORD_ASYNC - pthread_mutex_lock(&hook_xrecord_mutex); - running = false; - pthread_cond_signal(&hook_xrecord_cond); - pthread_mutex_unlock(&hook_xrecord_mutex); - #endif - - // See Bug 42356 for more information. - // https://bugs.freedesktop.org/show_bug.cgi?id=42356#c4 - //XFlush(hook->ctrl.display); - XSync(hook->ctrl.display, False); - if (hook->ctrl.display) { - XCloseDisplay(hook->ctrl.display); - hook->ctrl.display = NULL; - } - - status = IOHOOK_SUCCESS; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XRecordGetContext failure!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_X_RECORD_GET_CONTEXT; - } - - free(state); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to allocate memory for XRecordState!\n", - __FUNCTION__, __LINE__); - - status = IOHOOK_ERROR_OUT_OF_MEMORY; - } - - return status; - } - - logger(LOG_LEVEL_DEBUG, "%s [%u]: Status: %#X.\n", - __FUNCTION__, __LINE__, status); - - return status; -} diff --git a/cdeps/hook/x11/input.h b/cdeps/hook/x11/input.h deleted file mode 100644 index 905983f..0000000 --- a/cdeps/hook/x11/input.h +++ /dev/null @@ -1,86 +0,0 @@ - -#define USE_XKBCOMMON 0 -//#define _included_input_helper 0 -#ifndef _included_input_helper -#define _included_input_helper - -#include -#include - -#ifdef USE_XKBCOMMON - #include - #include - #include -#endif - - -// Virtual button codes that are not defined by X11. -#define Button1 1 -#define Button2 2 -#define Button3 3 -#define WheelUp 4 -#define WheelDown 5 -#define WheelLeft 6 -#define WheelRight 7 -#define XButton1 8 -#define XButton2 9 - -/* Converts an X11 key symbol to a single Unicode character. No direct X11 - * functionality exists to provide this information. - */ -extern size_t keysym_to_unicode(KeySym keysym, uint16_t *buffer, size_t size); - -/* Convert a single Unicode character to an X11 key symbol. This function - * provides a better translation than XStringToKeysym() for Unicode characters. - */ -extern KeySym unicode_to_keysym(uint16_t unicode); - -/* Converts an X11 key code to the appropriate keyboard scan code. - */ -extern uint16_t keycode_to_scancode(KeyCode keycode); - -/* Converts a keyboard scan code to the appropriate X11 key code. - */ -extern KeyCode scancode_to_keycode(uint16_t scancode); - - -#ifdef USE_XKBCOMMON - -/* Converts an X11 key code to a Unicode character sequence. libXKBCommon support - * is required for this method. - */ -extern size_t keycode_to_unicode(struct xkb_state* state, KeyCode keycode, uint16_t *buffer, size_t size); - -/* Create a xkb_state structure and return a pointer to it. - */ -extern struct xkb_state * create_xkb_state(struct xkb_context *context, xcb_connection_t *connection); - -/* Release xkb_state structure created by create_xkb_state(). - */ -extern void destroy_xkb_state(struct xkb_state* state); - -#else - -/* Converts an X11 key code and event mask to the appropriate X11 key symbol. - * This functions in much the same way as XKeycodeToKeysym() but allows for a - * faster and more flexible lookup. - */ -extern KeySym keycode_to_keysym(KeyCode keycode, unsigned int modifier_mask); - -#endif - -/* Initialize items required for KeyCodeToKeySym() and KeySymToUnicode() - * functionality. This method is called by OnLibraryLoad() and may need to be - * called in combination with UnloadInputHelper() if the native keyboard layout - * is changed. - */ -extern void load_input_helper(); - -/* De-initialize items required for KeyCodeToKeySym() and KeySymToUnicode() - * functionality. This method is called by OnLibraryUnload() and may need to be - * called in combination with LoadInputHelper() if the native keyboard layout - * is changed. - */ -extern void unload_input_helper(); - -#endif diff --git a/cdeps/hook/x11/input_c.h b/cdeps/hook/x11/input_c.h deleted file mode 100644 index 8d7f39d..0000000 --- a/cdeps/hook/x11/input_c.h +++ /dev/null @@ -1,1970 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define USE_XKB 0 -#define USE_XKBCOMMON 0 -#include -#include -#include -#include -#include -#include - -#ifdef USE_XKB -#ifdef USE_EVDEV - #include - static bool is_evdev = false; -#endif - -#include -static XkbDescPtr keyboard_map; -#else - #include - static KeySym *keyboard_map; - static int keysym_per_keycode; - static bool is_caps_lock = false, is_shift_lock = false; -#endif - -#ifdef USE_XKBCOMMON -#include -#include -#include - -#ifdef USE_XKBFILE -#include - -static struct xkb_rule_names xkb_names = { - .rules = "base", - .model = "us", - .layout = "pc105", - .variant = NULL, - .options = NULL -}; -#endif - -#endif - -#include "../logger_c.h" - -/* The follwoing two tables are based on QEMU's x_keymap.c, under the following - * terms: - * - * Copyright (C) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#if defined(USE_EVDEV) && defined(USE_XKB) -/* This table is generated based off the evdev -> scancode mapping above - * and the keycode mappings in the following files: - * /usr/include/linux/input.h - * /usr/share/X11/xkb/keycodes/evdev - * - * NOTE This table only works for Linux. - */ -static const uint16_t evdev_scancode_table[][2] = { - /* idx { keycode, scancode }, idx evdev code */ - /* 0 */ { VC_UNDEFINED, 0x00 }, /* 0x00 KEY_RESERVED */ - /* 1 */ { VC_UNDEFINED, 0x09 }, /* 0x01 KEY_ESC */ - /* 2 */ { VC_UNDEFINED, 0x0A }, /* 0x02 KEY_1 */ - /* 3 */ { VC_UNDEFINED, 0x0B }, /* 0x03 KEY_2 */ - /* 4 */ { VC_UNDEFINED, 0x0C }, /* 0x04 KEY_3 */ - /* 5 */ { VC_UNDEFINED, 0x0D }, /* 0x05 KEY_4 */ - /* 6 */ { VC_UNDEFINED, 0x0E }, /* 0x06 KEY_5 */ - /* 7 */ { VC_UNDEFINED, 0x0F }, /* 0x07 KEY_6 */ - /* 8 */ { VC_UNDEFINED, 0x10 }, /* 0x08 KEY_7 */ - /* 9 */ { VC_ESCAPE, 0x11 }, /* 0x09 KEY_8 */ - /* 10 */ { VC_1, 0x12 }, /* 0x0A KEY_9 */ - /* 11 */ { VC_2, 0x13 }, /* 0x0B KEY_0 */ - /* 12 */ { VC_3, 0x14 }, /* 0x0C KEY_MINUS */ - /* 13 */ { VC_4, 0x15 }, /* 0x0D KEY_EQUAL */ - /* 14 */ { VC_5, 0x16 }, /* 0x0E KEY_BACKSPACE */ - /* 15 */ { VC_6, 0x17 }, /* 0x0F KEY_TAB */ - /* 16 */ { VC_7, 0x18 }, /* 0x10 KEY_Q */ - /* 17 */ { VC_8, 0x19 }, /* 0x11 KEY_W */ - /* 18 */ { VC_9, 0x1A }, /* 0x12 KEY_E */ - /* 19 */ { VC_0, 0x1B }, /* 0x13 KEY_T */ - /* 20 */ { VC_MINUS, 0x1C }, /* 0x14 KEY_R */ - /* 21 */ { VC_EQUALS, 0x1D }, /* 0x15 KEY_Y */ - /* 22 */ { VC_BACKSPACE, 0x1E }, /* 0x16 KEY_U */ - /* 23 */ { VC_TAB, 0x1F }, /* 0x17 KEY_I */ - /* 24 */ { VC_Q, 0x20 }, /* 0x18 KEY_O */ - /* 25 */ { VC_W, 0x21 }, /* 0x19 KEY_P */ - /* 26 */ { VC_E, 0x22 }, /* 0x1A KEY_LEFTBRACE */ - /* 27 */ { VC_R, 0x23 }, /* 0x1B KEY_RIGHTBRACE */ - /* 28 */ { VC_T, 0x24 }, /* 0x1C KEY_ENTER */ - /* 29 */ { VC_Y, 0x25 }, /* 0x1D KEY_LEFTCTRL */ - /* 30 */ { VC_U, 0x26 }, /* 0x1E KEY_A */ - /* 31 */ { VC_I, 0x27 }, /* 0x1F KEY_S */ - /* 32 */ { VC_O, 0x28 }, /* 0x20 KEY_D */ - /* 33 */ { VC_P, 0x29 }, /* 0x21 KEY_F */ - /* 34 */ { VC_OPEN_BRACKET, 0x2A }, /* 0x22 KEY_G */ - /* 35 */ { VC_CLOSE_BRACKET, 0x2B }, /* 0x23 KEY_H */ - /* 36 */ { VC_ENTER, 0x2C }, /* 0x24 KEY_J */ - /* 37 */ { VC_CONTROL_L, 0x2D }, /* 0x25 KEY_K */ - /* 38 */ { VC_A, 0x2E }, /* 0x26 KEY_L */ - /* 39 */ { VC_S, 0x2F }, /* 0x27 KEY_SEMICOLON */ - /* 40 */ { VC_D, 0x30 }, /* 0x28 KEY_APOSTROPHE */ - /* 41 */ { VC_F, 0x31 }, /* 0x29 KEY_GRAVE */ - /* 42 */ { VC_G, 0x32 }, /* 0x2A KEY_LEFTSHIFT */ - /* 43 */ { VC_H, 0x33 }, /* 0x2B KEY_BACKSLASH */ - /* 44 */ { VC_J, 0x34 }, /* 0x2C KEY_Z */ - /* 45 */ { VC_K, 0x35 }, /* 0x2D KEY_X */ - /* 46 */ { VC_L, 0x36 }, /* 0x2E KEY_C */ - /* 47 */ { VC_SEMICOLON, 0x37 }, /* 0x2F KEY_V */ - /* 48 */ { VC_QUOTE, 0x38 }, /* 0x30 KEY_B */ - /* 49 */ { VC_BACKQUOTE, 0x39 }, /* 0x31 KEY_N */ - /* 50 */ { VC_SHIFT_L, 0x3A }, /* 0x32 KEY_M */ - /* 51 */ { VC_BACK_SLASH, 0x3B }, /* 0x33 KEY_COMMA */ - /* 52 */ { VC_Z, 0x3C }, /* 0x34 KEY_DOT */ - /* 53 */ { VC_X, 0x3D }, /* 0x35 KEY_SLASH */ - /* 54 */ { VC_C, 0x3E }, /* 0x36 KEY_RIGHTSHIFT */ - /* 55 */ { VC_V, 0x3F }, /* 0x37 KEY_KPASTERISK */ - /* 56 */ { VC_B, 0x40 }, /* 0x38 KEY_LEFTALT */ - /* 57 */ { VC_N, 0x41 }, /* 0x39 KEY_SPACE */ - /* 58 */ { VC_M, 0x42 }, /* 0x3A KEY_CAPSLOCK */ - /* 59 */ { VC_COMMA, 0x43 }, /* 0x3B KEY_F1 */ - /* 60 */ { VC_PERIOD, 0x44 }, /* 0x3C KEY_F2 */ - /* 61 */ { VC_SLASH, 0x45 }, /* 0x3D KEY_F3 */ - /* 62 */ { VC_SHIFT_R, 0x46 }, /* 0x3E KEY_F4 */ - /* 63 */ { VC_KP_MULTIPLY, 0x47 }, /* 0x3F KEY_F5 */ - /* 64 */ { VC_ALT_L, 0x48 }, /* 0x40 KEY_F6 */ - /* 65 */ { VC_SPACE, 0x49 }, /* 0x41 KEY_F7 */ - /* 66 */ { VC_CAPS_LOCK, 0x4A }, /* 0x42 KEY_F8 */ - /* 67 */ { VC_F1, 0x4B }, /* 0x43 KEY_F9 */ - /* 68 */ { VC_F2, 0x4C }, /* 0x44 KEY_F10 */ - /* 69 */ { VC_F3, 0x4D }, /* 0x45 KEY_NUMLOCK */ - /* 70 */ { VC_F4, 0x4E }, /* 0x46 KEY_SCROLLLOCK */ - /* 71 */ { VC_F5, 0x4F }, /* 0x47 KEY_KP7 */ - /* 72 */ { VC_F6, 0x50 }, /* 0x48 KEY_KP8 */ - /* 73 */ { VC_F7, 0x51 }, /* 0x49 KEY_KP9 */ - /* 74 */ { VC_F8, 0x52 }, /* 0x4A KEY_KPMINUS */ - /* 75 */ { VC_F9, 0x53 }, /* 0x4B KEY_KP4 */ - /* 76 */ { VC_F10, 0x54 }, /* 0x4C KEY_KP5 */ - /* 77 */ { VC_NUM_LOCK, 0x55 }, /* 0x4D KEY_KP6 */ - /* 78 */ { VC_SCROLL_LOCK, 0x56 }, /* 0x4E KEY_KPPLUS */ - /* 79 */ { VC_KP_7, 0x57 }, /* 0x4F KEY_KP1 */ - /* 80 */ { VC_KP_8, 0x58 }, /* 0x50 KEY_KP2 */ - /* 81 */ { VC_KP_9, 0x59 }, /* 0x51 KEY_KP3 */ - /* 82 */ { VC_KP_SUBTRACT, 0x5A }, /* 0x52 KEY_KP0 */ - /* 83 */ { VC_KP_4, 0x5B }, /* 0x53 KEY_KPDOT */ - /* 84 */ { VC_KP_5, 0x00 }, /* 0x54 */ - /* 85 */ { VC_KP_6, 0x00 }, /* 0x55 TODO [KEY_ZENKAKUHANKAKU][0] == [VC_?][1] */ - /* 86 */ { VC_KP_ADD, 0x00 }, /* 0x56 TODO [KEY_102ND][0] == [VC_?][1] */ - /* 87 */ { VC_KP_1, 0x5F }, /* 0x57 KEY_F11 */ - /* 88 */ { VC_KP_2, 0x60 }, /* 0x58 KEY_F12 */ - /* 89 */ { VC_KP_3, 0x00 }, /* 0x59 TODO [KEY_RO][0] == [VC_?][1] */ - /* 90 */ { VC_KP_0, 0x00 }, /* 0x5A */ - /* 91 */ { VC_KP_SEPARATOR, 0xBF }, /* 0x5B KEY_F13 */ - /* 92 */ { VC_UNDEFINED, 0xC0 }, /* 0x5C KEY_F14 */ - /* 93 */ { VC_UNDEFINED, 0xC1 }, /* 0x5D KEY_F15 */ - /* 94 */ { VC_UNDEFINED, 0x00 }, /* 0x5E TODO [KEY_MUHENKAN][0] == [VC_?][1] */ - /* 95 */ { VC_F11, 0x00 }, /* 0x5F */ - /* 96 */ { VC_F12, 0x00 }, /* 0x60 */ - - /* First 97 chars are identical to XFree86! */ - - /* 97 */ { VC_UNDEFINED, 0x00 }, /* 0x61 */ - /* 98 */ { VC_KATAKANA, 0x00 }, /* 0x62 */ - /* 99 */ { VC_HIRAGANA, 0xC2 }, /* 0x63 KEY_F16 */ - /* 100 */ { VC_KANJI, 0xC3 }, /* 0x64 KEY_F17 */ - /* 101 */ { VC_UNDEFINED, 0xC4 }, /* 0x65 KEY_F18 */ - /* 102 */ { VC_UNDEFINED, 0xC5 }, /* 0x66 KEY_F19 */ - /* 103 */ { VC_KP_COMMA, 0xC6 }, /* 0x67 KEY_F20 */ - /* 104 */ { VC_KP_ENTER, 0xC7 }, /* 0x68 KEY_F21 */ - /* 105 */ { VC_CONTROL_R, 0xC8 }, /* 0x69 KEY_F22 */ - /* 106 */ { VC_KP_DIVIDE, 0xC9 }, /* 0x6A KEY_F23 */ - /* 107 */ { VC_PRINTSCREEN, 0xCA }, /* 0x6B KEY_F24 */ - /* 108 */ { VC_ALT_R, 0x00 }, /* 0x6C */ - /* 109 */ { VC_UNDEFINED, 0x00 }, /* 0x6D */ - /* 110 */ { VC_HOME, 0x00 }, /* 0x6E */ - /* 111 */ { VC_UP, 0x00 }, /* 0x6F */ - /* 112 */ { VC_PAGE_UP, 0x62 }, /* 0x70 KEY_KATAKANA */ - /* 113 */ { VC_LEFT, 0x00 }, /* 0x71 */ - /* 114 */ { VC_RIGHT, 0x00 }, /* 0x72 */ - /* 115 */ { VC_END, 0x00 }, /* 0x73 TODO KEY_? = [VC_UNDERSCORE][1] */ - /* 116 */ { VC_DOWN, 0x00 }, /* 0x74 TODO KEY_? = [VC_FURIGANA][1] */ - /* 117 */ { VC_PAGE_DOWN, 0x00 }, /* 0x75 */ - /* 118 */ { VC_INSERT, 0x00 }, /* 0x76 TODO [KEY_KPPLUSMINUS][0] = [VC_?][1] */ - /* 119 */ { VC_DELETE, 0x00 }, /* 0x77 */ - /* 120 */ { VC_UNDEFINED, 0x00 }, /* 0x78 TODO [KEY_SCALE][0] = [VC_?][1] */ - /* 121 */ { VC_VOLUME_MUTE, 0x64 }, /* 0x79 KEY_HENKAN */ - /* 122 */ { VC_VOLUME_DOWN, 0x00 }, /* 0x7A */ - /* 123 */ { VC_VOLUME_UP, 0x63 }, /* 0x7B KEY_HIRAGANA */ - /* 124 */ { VC_POWER, 0x00 }, /* 0x7C */ - /* 125 */ { VC_KP_EQUALS, 0x84 }, /* 0x7D KEY_YEN */ - /* 126 */ { VC_UNDEFINED, 0x67 }, /* 0x7E KEY_KPJPCOMMA */ - /* 127 */ { VC_PAUSE, 0x00 }, /* 0x7F */ - - /* No Offset Offset (i & 0x007F) + 128 */ - - /* 128 */ { VC_UNDEFINED, 0 }, /* 0x80 */ - /* 129 */ { VC_UNDEFINED, 0 }, /* 0x81 */ - /* 130 */ { VC_UNDEFINED, 0 }, /* 0x82 */ - /* 131 */ { VC_UNDEFINED, 0 }, /* 0x83 */ - /* 132 */ { VC_YEN, 0 }, /* 0x84 */ - /* 133 */ { VC_META_L, 0 }, /* 0x85 */ - /* 134 */ { VC_META_R, 0 }, /* 0x86 */ - /* 135 */ { VC_CONTEXT_MENU, 0 }, /* 0x87 */ - /* 136 */ { VC_SUN_STOP, 0 }, /* 0x88 */ - /* 137 */ { VC_SUN_AGAIN, 0 }, /* 0x89 */ - /* 138 */ { VC_SUN_PROPS, 0 }, /* 0x8A */ - /* 139 */ { VC_SUN_UNDO, 0 }, /* 0x8B */ - /* 140 */ { VC_SUN_FRONT, 0 }, /* 0x8C */ - /* 141 */ { VC_SUN_COPY, 0x7D }, /* 0x8D KEY_KPEQUAL */ - /* 142 */ { VC_SUN_OPEN, 0 }, /* 0x8E */ - /* 143 */ { VC_SUN_INSERT, 0 }, /* 0x8F */ - /* 144 */ { VC_SUN_FIND, 0 }, /* 0x90 */ - /* 145 */ { VC_SUN_CUT, 0 }, /* 0x91 */ - /* 146 */ { VC_SUN_HELP, 0 }, /* 0x92 */ - /* 147 */ { VC_UNDEFINED, 0 }, /* 0x93 */ - /* 148 */ { VC_APP_CALCULATOR, 0 }, /* 0x94 */ - /* 149 */ { VC_UNDEFINED, 0 }, /* 0x95 */ - /* 150 */ { VC_SLEEP, 0 }, /* 0x96 */ - /* 151 */ { VC_UNDEFINED, 0 }, /* 0x97 */ - /* 152 */ { VC_UNDEFINED, 0 }, /* 0x98 */ - /* 153 */ { VC_UNDEFINED, 0 }, /* 0x99 */ - /* 154 */ { VC_UNDEFINED, 0 }, /* 0x9A */ - /* 155 */ { VC_UNDEFINED, 0 }, /* 0x9B */ - /* 156 */ { VC_UNDEFINED, 0x68 }, /* 0x9C KEY_KPENTER */ - /* 157 */ { VC_UNDEFINED, 0x69 }, /* 0x9D KEY_RIGHTCTRL */ - /* 158 */ { VC_UNDEFINED, 0 }, /* 0x9E */ - /* 159 */ { VC_UNDEFINED, 0 }, /* 0x9F */ - /* 160 */ { VC_UNDEFINED, 0x79 }, /* 0xA0 KEY_MUTE */ - /* 161 */ { VC_UNDEFINED, 0x94 }, /* 0xA1 KEY_CALC */ - /* 162 */ { VC_UNDEFINED, 0xA7 }, /* 0xA2 KEY_FORWARD */ - /* 163 */ { VC_UNDEFINED, 0 }, /* 0xA3 */ - /* 164 */ { VC_UNDEFINED, 0 }, /* 0xA4 */ - /* 165 */ { VC_UNDEFINED, 0 }, /* 0xA5 */ - /* 166 */ { VC_APP_MAIL, 0 }, /* 0xA6 */ - /* 167 */ { VC_MEDIA_PLAY, 0 }, /* 0xA7 */ - /* 168 */ { VC_UNDEFINED, 0 }, /* 0xA8 */ - /* 169 */ { VC_UNDEFINED, 0 }, /* 0xA9 */ - /* 170 */ { VC_UNDEFINED, 0 }, /* 0xAA */ - /* 171 */ { VC_UNDEFINED, 0 }, /* 0xAB */ - /* 172 */ { VC_UNDEFINED, 0 }, /* 0xAC */ - /* 173 */ { VC_UNDEFINED, 0 }, /* 0xAD */ - /* 174 */ { VC_UNDEFINED, 0x7A }, /* 0xAE KEY_VOLUMEDOWN */ - /* 175 */ { VC_UNDEFINED, 0 }, /* 0xAF */ - /* 176 */ { VC_UNDEFINED, 0x7B }, /* 0xB0 KEY_VOLUMEUP */ - /* 177 */ { VC_UNDEFINED, 0x00 }, /* 0xB1 */ - /* 178 */ { VC_UNDEFINED, 0xBA }, /* 0xB2 KEY_SCROLLUP */ - /* 179 */ { VC_UNDEFINED, 0x00 }, /* 0xB3 */ - /* 180 */ { VC_UNDEFINED, 0x00 }, /* 0xB4 */ - /* 181 */ { VC_UNDEFINED, 0x6A }, /* 0xB5 KEY_KPSLASH */ - /* 182 */ { VC_UNDEFINED, 0x00 }, /* 0xB6 */ - /* 183 */ { VC_UNDEFINED, 0x6B }, /* 0xB7 KEY_SYSRQ */ - /* 184 */ { VC_UNDEFINED, 0x6C }, /* 0xB8 KEY_RIGHTALT */ - /* 185 */ { VC_UNDEFINED, 0x00 }, /* 0xB9 */ - /* 186 */ { VC_BROWSER_HOME, 0x00 }, /* 0xBA */ - /* 187 */ { VC_UNDEFINED, 0x00 }, /* 0xBB */ - /* 188 */ { VC_UNDEFINED, 0x00 }, /* 0xBC */ - /* 189 */ { VC_UNDEFINED, 0x00 }, /* 0xBD */ - /* 190 */ { VC_UNDEFINED, 0x00 }, /* 0xBE */ - /* 191 */ { VC_F13, 0x00 }, /* 0xBF */ - /* 192 */ { VC_F14, 0x00 }, /* 0xC0 */ - /* 193 */ { VC_F15, 0x00 }, /* 0xC1 */ - /* 194 */ { VC_F16, 0x00 }, /* 0xC2 */ - /* 195 */ { VC_F17, 0x00 }, /* 0xC3 */ - /* 196 */ { VC_F18, 0x00 }, /* 0xC4 */ - /* 197 */ { VC_F19, 0x7F }, /* 0xC5 KEY_PAUSE */ - /* 198 */ { VC_F20, 0x00 }, /* 0xC6 */ - /* 199 */ { VC_F21, 0x6E }, /* 0xC7 KEY_HOME */ - /* 200 */ { VC_F22, 0x6F }, /* 0xC8 KEY_UP */ - /* 201 */ { VC_F23, 0x70 }, /* 0xC9 KEY_PAGEUP */ - /* 202 */ { VC_F24, 0x00 }, /* 0xCA */ - /* 203 */ { VC_UNDEFINED, 0x71 }, /* 0xCB KEY_LEFT */ - /* 204 */ { VC_UNDEFINED, 0x00 }, /* 0xCC */ - /* 205 */ { VC_UNDEFINED, 0x72 }, /* 0xCD KEY_RIGHT */ - /* 206 */ { VC_UNDEFINED, 0x00 }, /* 0xCE */ - /* 207 */ { VC_UNDEFINED, 0x73 }, /* 0xCF KEY_END */ - /* 208 */ { VC_UNDEFINED, 0x74 }, /* 0xD0 KEY_DOWN */ - /* 209 */ { VC_UNDEFINED, 0x75 }, /* 0xD1 KEY_PAGEDOWN */ - /* 210 */ { VC_UNDEFINED, 0x76 }, /* 0xD2 KEY_INSERT */ - /* 211 */ { VC_UNDEFINED, 0x77 }, /* 0xD3 KEY_DELETE */ - /* 212 */ { VC_UNDEFINED, 0x00 }, /* 0xD4 */ - /* 213 */ { VC_UNDEFINED, 0x00 }, /* 0xD5 */ - /* 214 */ { VC_UNDEFINED, 0x00 }, /* 0xD6 */ - /* 215 */ { VC_UNDEFINED, 0x00 }, /* 0xD7 */ - /* 216 */ { VC_UNDEFINED, 0x00 }, /* 0xD8 */ - /* 217 */ { VC_UNDEFINED, 0x00 }, /* 0xD9 */ - /* 218 */ { VC_UNDEFINED, 0x00 }, /* 0xDA */ - /* 219 */ { VC_UNDEFINED, 0x85 }, /* 0xDB KEY_LEFTMETA */ - /* 220 */ { VC_UNDEFINED, 0x86 }, /* 0xDC KEY_RIGHTMETA */ - /* 221 */ { VC_UNDEFINED, 0x87 }, /* 0xDD KEY_COMPOSE */ - /* 222 */ { VC_UNDEFINED, 0x7C }, /* 0xDE KEY_POWER */ - /* 223 */ { VC_UNDEFINED, 0x96 }, /* 0xDF KEY_SLEEP */ - /* 224 */ { VC_UNDEFINED, 0x00 }, /* 0xE0 */ - /* 225 */ { VC_BROWSER_SEARCH, 0x00 }, /* 0xE1 */ - /* 226 */ { VC_UNDEFINED, 0x00 }, /* 0xE2 */ - /* 227 */ { VC_UNDEFINED, 0x00 }, /* 0xE3 */ - /* 228 */ { VC_UNDEFINED, 0x00 }, /* 0xE4 */ - /* 229 */ { VC_UNDEFINED, 0xE1 }, /* 0xE5 KEY_SEARCH */ - /* 230 */ { VC_UNDEFINED, 0x00 }, /* 0xE6 */ - /* 231 */ { VC_UNDEFINED, 0x00 }, /* 0xE7 */ - /* 232 */ { VC_UNDEFINED, 0x00 }, /* 0xE8 */ - /* 233 */ { VC_UNDEFINED, 0x00 }, /* 0xE9 */ - /* 234 */ { VC_UNDEFINED, 0x00 }, /* 0xEA */ - /* 235 */ { VC_UNDEFINED, 0x00 }, /* 0xEB */ - /* 236 */ { VC_UNDEFINED, 0xA6 }, /* 0xEC KEY_BACK */ - /* 237 */ { VC_UNDEFINED, 0x00 }, /* 0xED */ - /* 238 */ { VC_UNDEFINED, 0x00 }, /* 0xEE */ - /* 239 */ { VC_UNDEFINED, 0x00 }, /* 0xEF */ - /* 240 */ { VC_UNDEFINED, 0x00 }, /* 0xF0 */ - /* 241 */ { VC_UNDEFINED, 0x00 }, /* 0xF1 */ - /* 242 */ { VC_UNDEFINED, 0x00 }, /* 0xF2 */ - /* 243 */ { VC_UNDEFINED, 0x00 }, /* 0xF3 */ - /* 244 */ { VC_UNDEFINED, 0x8E }, /* 0xF4 KEY_OPEN */ - /* 245 */ { VC_UNDEFINED, 0x92 }, /* 0xF5 KEY_HELP */ - /* 246 */ { VC_UNDEFINED, 0x8A }, /* 0xF6 KEY_PROPS */ - /* 247 */ { VC_UNDEFINED, 0x8C }, /* 0xF7 KEY_FRONT */ - /* 248 */ { VC_UNDEFINED, 0x88 }, /* 0xF8 KEY_STOP */ - /* 249 */ { VC_UNDEFINED, 0x89 }, /* 0xF9 KEY_AGAIN */ - /* 250 */ { VC_UNDEFINED, 0x8B }, /* 0xFA KEY_UNDO */ - /* 251 */ { VC_UNDEFINED, 0x91 }, /* 0xFB KEY_CUT */ - /* 252 */ { VC_UNDEFINED, 0x8D }, /* 0xFC KEY_COPY */ - /* 253 */ { VC_UNDEFINED, 0x8F }, /* 0xFD KEY_PASTE */ - /* 254 */ { VC_UNDEFINED, 0x90 }, /* 0xFE KEY_FIND */ - /* 255 */ { VC_UNDEFINED, 0x00 }, /* 0xFF */ -}; -#endif - - -/* This table is generated based off the xfree86 -> scancode mapping above - * and the keycode mappings in the following files: - * /usr/share/X11/xkb/keycodes/xfree86 - * - * TODO Everything after 157 needs to be populated with scancodes for media - * controls and internet keyboards. - */ -static const uint16_t xfree86_scancode_table[][2] = { - /* idx { keycode, scancode }, */ - /* 0 */ { VC_UNDEFINED, 0 /* */ }, // Unused - /* 1 */ { VC_UNDEFINED, 9 /* */ }, // - /* 2 */ { VC_UNDEFINED, 10 /* */ }, // - /* 3 */ { VC_UNDEFINED, 11 /* */ }, // - /* 4 */ { VC_UNDEFINED, 12 /* */ }, // - /* 5 */ { VC_UNDEFINED, 13 /* */ }, // - /* 6 */ { VC_UNDEFINED, 14 /* */ }, // - /* 7 */ { VC_UNDEFINED, 15 /* */ }, // - /* 8 */ { VC_UNDEFINED, 16 /* */ }, // - /* 9 */ { VC_ESCAPE, 17 /* */ }, // - /* 10 */ { VC_1, 18 /* */ }, // - /* 11 */ { VC_2, 19 /* */ }, // - /* 12 */ { VC_3, 20 /* */ }, // - /* 13 */ { VC_4, 21 /* */ }, // - /* 14 */ { VC_5, 22 /* */ }, // - /* 15 */ { VC_6, 23 /* */ }, // - /* 16 */ { VC_7, 24 /* */ }, // - /* 17 */ { VC_8, 25 /* */ }, // - /* 18 */ { VC_9, 26 /* */ }, // - /* 19 */ { VC_0, 27 /* */ }, // - /* 20 */ { VC_MINUS, 28 /* */ }, // - /* 21 */ { VC_EQUALS, 29 /* */ }, // - /* 22 */ { VC_BACKSPACE, 30 /* */ }, // - /* 23 */ { VC_TAB, 31 /* */ }, // - /* 24 */ { VC_Q, 32 /* */ }, // - /* 25 */ { VC_W, 33 /* */ }, // - /* 26 */ { VC_E, 34 /* */ }, // - /* 27 */ { VC_R, 35 /* */ }, // - /* 28 */ { VC_T, 36 /* */ }, // - /* 29 */ { VC_Y, 37 /* */ }, // - /* 30 */ { VC_U, 38 /* */ }, // - /* 31 */ { VC_I, 39 /* */ }, // - /* 32 */ { VC_O, 40 /* */ }, // - /* 33 */ { VC_P, 41 /* */ }, // - /* 34 */ { VC_OPEN_BRACKET, 42 /* */ }, // - /* 35 */ { VC_CLOSE_BRACKET, 43 /* */ }, // - /* 36 */ { VC_ENTER, 44 /* */ }, // - /* 37 */ { VC_CONTROL_L, 45 /* */ }, // - /* 38 */ { VC_A, 46 /* */ }, // - /* 39 */ { VC_S, 47 /* */ }, // - /* 40 */ { VC_D, 48 /* */ }, // - /* 41 */ { VC_F, 49 /* */ }, // - /* 42 */ { VC_G, 50 /* */ }, // - /* 43 */ { VC_H, 51 /* */ }, // - /* 44 */ { VC_J, 52 /* */ }, // - /* 45 */ { VC_K, 53 /* */ }, // - /* 46 */ { VC_L, 54 /* */ }, // - /* 47 */ { VC_SEMICOLON, 55 /* */ }, // - /* 48 */ { VC_QUOTE, 56 /* */ }, // - /* 49 */ { VC_BACKQUOTE, 57 /* */ }, // - /* 50 */ { VC_SHIFT_L, 58 /* */ }, // - /* 51 */ { VC_BACK_SLASH, 59 /* */ }, // - /* 52 */ { VC_Z, 60 /* */ }, // - /* 53 */ { VC_X, 61 /* */ }, // - /* 54 */ { VC_C, 62 /* */ }, // - /* 55 */ { VC_V, 63 /* */ }, // - /* 56 */ { VC_B, 64 /* */ }, // - /* 57 */ { VC_N, 65 /* */ }, // - /* 58 */ { VC_M, 66 /* */ }, // - /* 59 */ { VC_COMMA, 67 /* */ }, // - /* 60 */ { VC_PERIOD, 68 /* */ }, // - /* 61 */ { VC_SLASH, 69 /* */ }, // - /* 62 */ { VC_SHIFT_R, 70 /* */ }, // - /* 63 */ { VC_KP_MULTIPLY, 71 /* */ }, // - /* 64 */ { VC_ALT_L, 72 /* */ }, // - /* 65 */ { VC_SPACE, 73 /* */ }, // - /* 66 */ { VC_CAPS_LOCK, 74 /* */ }, // - /* 67 */ { VC_F1, 75 /* */ }, // - /* 68 */ { VC_F2, 76 /* */ }, // - /* 69 */ { VC_F3, 77 /* */ }, // - /* 70 */ { VC_F4, 78 /* */ }, // - /* 71 */ { VC_F5, 79 /* */ }, // - /* 72 */ { VC_F6, 80 /* */ }, // - /* 73 */ { VC_F7, 81 /* */ }, // - /* 74 */ { VC_F8, 82 /* */ }, // - /* 75 */ { VC_F9, 83 /* */ }, // - /* 76 */ { VC_F10, 84 /* */ }, // - /* 77 */ { VC_NUM_LOCK, 85 /* */ }, // - /* 78 */ { VC_SCROLL_LOCK, 86 /* */ }, // - /* 79 */ { VC_KP_7, 87 /* */ }, // - /* 80 */ { VC_KP_8, 88 /* */ }, // - /* 81 */ { VC_KP_9, 89 /* */ }, // - /* 82 */ { VC_KP_SUBTRACT, 90 /* */ }, // - /* 83 */ { VC_KP_4, 91 /* */ }, // - /* 84 */ { VC_KP_5, 0 }, // - /* 85 */ { VC_KP_6, 0 }, // - /* 86 */ { VC_KP_ADD, 0 }, // - /* 87 */ { VC_KP_1, 95 /* */ }, // - /* 88 */ { VC_KP_2, 96 /* */ }, - /* 89 */ { VC_KP_3, 0 }, - /* 90 */ { VC_KP_0, 0 }, - /* 91 */ { VC_KP_SEPARATOR, 118 /* */ }, - /* 92 */ { VC_UNDEFINED, 119 /* */ }, - /* 93 */ { VC_UNDEFINED, 120 /* */ }, - /* 94 */ { VC_UNDEFINED, 0 }, - /* 95 */ { VC_F11, 0 }, - /* 96 */ { VC_F12, 0 }, - - /* First 97 chars are identical to XFree86! */ - - /* 97 */ { VC_HOME, 0 }, - /* 98 */ { VC_UP, 0 }, - /* 99 */ { VC_PAGE_UP, 121 /* */ }, - /* 100 */ { VC_LEFT, 122 /* */ }, - /* 101 */ { VC_UNDEFINED, 0 }, // TODO lower brightness key? - /* 102 */ { VC_RIGHT, 0 }, - /* 103 */ { VC_END, 0 }, - /* 104 */ { VC_DOWN, 0 }, - /* 105 */ { VC_PAGE_DOWN, 0 }, - /* 106 */ { VC_INSERT, 0 }, - /* 107 */ { VC_DELETE, 0 }, - /* 108 */ { VC_KP_ENTER, 0 }, - /* 109 */ { VC_CONTROL_R, 0 }, - /* 110 */ { VC_PAUSE, 0 }, - /* 111 */ { VC_PRINTSCREEN, 0 }, - /* 112 */ { VC_KP_DIVIDE, 0 }, - /* 113 */ { VC_ALT_R, 0 }, - /* 114 */ { VC_UNDEFINED, 0 }, // VC_BREAK? - /* 115 */ { VC_META_L, 0 }, - /* 116 */ { VC_META_R, 0 }, - /* 117 */ { VC_CONTEXT_MENU, 0 }, - /* 118 */ { VC_F13, 0 }, - /* 119 */ { VC_F14, 0 }, - /* 120 */ { VC_F15, 0 }, - /* 121 */ { VC_F16, 0 }, - /* 122 */ { VC_F17, 0 }, - /* 123 */ { VC_UNDEFINED, 0 }, // FIXME What is this key? - /* 124 */ { VC_UNDEFINED, 0 }, // Never Generated - /* 125 */ { VC_UNDEFINED, 133 /* */ }, // Never Generated - /* 126 */ { VC_KP_EQUALS, 0 }, - /* 127 */ { VC_UNDEFINED, 0 }, // Never Generated - /* 128 */ { VC_UNDEFINED, 0 }, // Never Generated - /* 129 */ { VC_UNDEFINED, 0 }, // Henkan - /* 130 */ { VC_UNDEFINED, 0 }, // Some extended Internet key - /* 131 */ { VC_UNDEFINED, 0 }, // Muhenkan - /* 132 */ { VC_UNDEFINED, 0 }, // - /* 133 */ { VC_YEN, 0 }, // - /* 134 */ { VC_UNDEFINED, 0 }, // - /* 135 */ { VC_UNDEFINED, 0 }, // - /* 136 */ { VC_UNDEFINED, 0 }, // - /* 137 */ { VC_UNDEFINED, 0 }, // - /* 138 */ { VC_UNDEFINED, 0 }, // - /* 139 */ { VC_UNDEFINED, 0 }, // - /* 140 */ { VC_UNDEFINED, 0 }, // - /* 141 */ { VC_UNDEFINED, 126 }, // - /* 142 */ { VC_UNDEFINED, 0 }, // - /* 143 */ { VC_UNDEFINED, 0 }, // - /* 144 */ { VC_UNDEFINED, 0 }, // - /* 145 */ { VC_UNDEFINED, 0 }, // - /* 146 */ { VC_UNDEFINED, 0 }, // - /* 147 */ { VC_UNDEFINED, 0 }, // - /* 148 */ { VC_UNDEFINED, 0 }, // - /* 149 */ { VC_UNDEFINED, 0 }, // - /* 150 */ { VC_UNDEFINED, 0 }, // - /* 151 */ { VC_UNDEFINED, 0 }, // - /* 152 */ { VC_UNDEFINED, 0 }, // - /* 153 */ { VC_UNDEFINED, 0 }, // - /* 154 */ { VC_UNDEFINED, 0 }, // - /* 155 */ { VC_UNDEFINED, 0 }, // - /* 156 */ { VC_UNDEFINED, 108 /* */ }, // Never Generated - /* 157 */ { VC_UNDEFINED, 109 /* */ }, // - /* 158 */ { VC_UNDEFINED, 0 }, // - /* 159 */ { VC_UNDEFINED, 0 }, // - /* 160 */ { VC_UNDEFINED, 0 }, // - /* 161 */ { VC_UNDEFINED, 0 }, // - /* 162 */ { VC_UNDEFINED, 0 }, // - /* 163 */ { VC_UNDEFINED, 0 }, // - /* 164 */ { VC_UNDEFINED, 0 }, // - /* 165 */ { VC_UNDEFINED, 0 }, // - /* 166 */ { VC_UNDEFINED, 0 }, // - /* 167 */ { VC_UNDEFINED, 0 }, // - /* 168 */ { VC_UNDEFINED, 0 }, // - /* 169 */ { VC_UNDEFINED, 0 }, // - /* 170 */ { VC_UNDEFINED, 0 }, // - /* 171 */ { VC_UNDEFINED, 0 }, // - /* 172 */ { VC_UNDEFINED, 0 }, // - /* 173 */ { VC_UNDEFINED, 0 }, // - /* 174 */ { VC_UNDEFINED, 0 }, // - /* 175 */ { VC_UNDEFINED, 0 }, // - /* 176 */ { VC_UNDEFINED, 0 }, // - /* 177 */ { VC_UNDEFINED, 0 }, // - /* 178 */ { VC_UNDEFINED, 0 }, // - /* 179 */ { VC_UNDEFINED, 0 }, // - /* 180 */ { VC_UNDEFINED, 0 }, // - /* 181 */ { VC_UNDEFINED, 112 }, // - /* 182 */ { VC_UNDEFINED, 0 }, // - /* 183 */ { VC_UNDEFINED, 111 }, // - /* 184 */ { VC_UNDEFINED, 113 }, // - /* 185 */ { VC_UNDEFINED, 0 }, // - /* 186 */ { VC_UNDEFINED, 0 }, // - /* 187 */ { VC_UNDEFINED, 0 }, // - /* 188 */ { VC_UNDEFINED, 0 }, // - /* 189 */ { VC_UNDEFINED, 0 }, // - /* 190 */ { VC_UNDEFINED, 0 }, // - /* 191 */ { VC_UNDEFINED, 0 }, // - /* 192 */ { VC_UNDEFINED, 0 }, // - /* 193 */ { VC_UNDEFINED, 0 }, // - /* 194 */ { VC_UNDEFINED, 0 }, // - /* 195 */ { VC_UNDEFINED, 0 }, // - /* 196 */ { VC_UNDEFINED, 0 }, // // 114 ? - /* 197 */ { VC_UNDEFINED, 110 }, // - /* 198 */ { VC_UNDEFINED, 0 }, // - /* 199 */ { VC_UNDEFINED, 97 /* */ }, // - /* 200 */ { VC_UNDEFINED, 98 }, // - /* 201 */ { VC_UNDEFINED, 99 }, // - /* 202 */ { VC_UNDEFINED, 0 }, // - /* 204 */ { VC_UNDEFINED, 0 }, // - /* 205 */ { VC_UNDEFINED, 102 }, // - /* 206 */ { VC_UNDEFINED, 0 }, // - /* 207 */ { VC_UNDEFINED, 103 }, // - /* 208 */ { VC_UNDEFINED, 104 }, // - /* 209 */ { VC_UNDEFINED, 105 }, // - /* 210 */ { VC_UNDEFINED, 106 }, // - /* 211 */ { VC_UNDEFINED, 107 }, // - /* 212 */ { VC_UNDEFINED, 0 }, // - /* 213 */ { VC_UNDEFINED, 0 }, // - /* 214 */ { VC_UNDEFINED, 0 }, // - /* 215 */ { VC_UNDEFINED, 0 }, // - /* 216 */ { VC_UNDEFINED, 0 }, // - /* 217 */ { VC_UNDEFINED, 0 }, // - /* 218 */ { VC_UNDEFINED, 0 }, // - /* 219 */ { VC_UNDEFINED, 115 /* */ }, // - /* 220 */ { VC_UNDEFINED, 116 /* */ }, // - /* 221 */ { VC_UNDEFINED, 117 /* */ }, // - /* 222 */ { VC_UNDEFINED, 0 }, // - /* 223 */ { VC_UNDEFINED, 0 }, // - /* 224 */ { VC_UNDEFINED, 0 }, // - /* 225 */ { VC_UNDEFINED, 0 }, // - /* 226 */ { VC_UNDEFINED, 0 }, // - /* 227 */ { VC_UNDEFINED, 0 }, // - /* 228 */ { VC_UNDEFINED, 0 }, // - /* 229 */ { VC_UNDEFINED, 0 }, // - /* 230 */ { VC_UNDEFINED, 0 }, // - /* 231 */ { VC_UNDEFINED, 0 }, // - /* 232 */ { VC_UNDEFINED, 0 }, // - /* 233 */ { VC_UNDEFINED, 0 }, // - /* 234 */ { VC_UNDEFINED, 0 }, // - /* 235 */ { VC_UNDEFINED, 0 }, // - /* 236 */ { VC_UNDEFINED, 0 }, // - /* 237 */ { VC_UNDEFINED, 0 }, // - /* 238 */ { VC_UNDEFINED, 0 }, // - /* 239 */ { VC_UNDEFINED, 0 }, // - /* 240 */ { VC_UNDEFINED, 0 }, // - /* 241 */ { VC_UNDEFINED, 0 }, // - /* 242 */ { VC_UNDEFINED, 0 }, // - /* 243 */ { VC_UNDEFINED, 0 }, // - /* 244 */ { VC_UNDEFINED, 0 }, // - /* 245 */ { VC_UNDEFINED, 0 }, // - /* 246 */ { VC_UNDEFINED, 0 }, // - /* 247 */ { VC_UNDEFINED, 0 }, // - /* 248 */ { VC_UNDEFINED, 0 }, // - /* 249 */ { VC_UNDEFINED, 0 }, // - /* 250 */ { VC_UNDEFINED, 0 }, // - /* 251 */ { VC_UNDEFINED, 0 }, // - /* 252 */ { VC_UNDEFINED, 0 }, // - /* 253 */ { VC_UNDEFINED, 0 }, // - /* 254 */ { VC_UNDEFINED, 0 }, // - /* 255 */ { VC_UNDEFINED, 0 }, // - }; - - -/*********************************************************************** - * The following table contains pairs of X11 keysym values for graphical - * characters and the corresponding Unicode value. The function - * keysym_to_unicode() maps a keysym onto a Unicode value using a binary - * search, therefore keysym_unicode_table[] must remain SORTED by KeySym - * value. - * - * We allow to represent any UCS character in the range U+00000000 to - * U+00FFFFFF by a keysym value in the range 0x01000000 to 0x01FFFFFF. - * This admittedly does not cover the entire 31-bit space of UCS, but - * it does cover all of the characters up to U+10FFFF, which can be - * represented by UTF-16, and more, and it is very unlikely that higher - * UCS codes will ever be assigned by ISO. So to get Unicode character - * U+ABCD you can directly use keysym 0x1000ABCD. - * - * NOTE: The comments in the table below contain the actual character - * encoded in UTF-8, so for viewing and editing best use an editor in - * UTF-8 mode. - * - * Author: Markus G. Kuhn , University of Cambridge, - * June 1999 - * - * Special thanks to Richard Verhoeven for preparing - * an initial draft of the mapping table. - * - * This table is in the public domain. Share and enjoy! - ***********************************************************************/ -static struct codepair { - uint16_t keysym; - uint16_t unicode; -} keysym_unicode_table[] = { - { 0x01A1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ - { 0x01A2, 0x02D8 }, /* breve ˘ BREVE */ - { 0x01A3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ - { 0x01A5, 0x013D }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ - { 0x01A6, 0x015A }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ - { 0x01A9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ - { 0x01AA, 0x015E }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ - { 0x01AB, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ - { 0x01AC, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ - { 0x01AE, 0x017D }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ - { 0x01AF, 0x017B }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ - { 0x01B1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ - { 0x01B2, 0x02DB }, /* ogonek ˛ OGONEK */ - { 0x01B3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ - { 0x01B5, 0x013E }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ - { 0x01B6, 0x015B }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ - { 0x01B7, 0x02C7 }, /* caron ˇ CARON */ - { 0x01B9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ - { 0x01BA, 0x015F }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ - { 0x01BB, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ - { 0x01BC, 0x017A }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ - { 0x01BD, 0x02DD }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ - { 0x01BE, 0x017E }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ - { 0x01BF, 0x017C }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ - { 0x01C0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ - { 0x01C3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ - { 0x01C5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ - { 0x01C6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ - { 0x01C8, 0x010C }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ - { 0x01CA, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ - { 0x01CC, 0x011A }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ - { 0x01CF, 0x010E }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ - { 0x01D0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ - { 0x01D1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ - { 0x01D2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ - { 0x01D5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ - { 0x01D8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ - { 0x01D9, 0x016E }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ - { 0x01DB, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ - { 0x01DE, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ - { 0x01E0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ - { 0x01E3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ - { 0x01E5, 0x013A }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ - { 0x01E6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ - { 0x01E8, 0x010D }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ - { 0x01EA, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ - { 0x01EC, 0x011B }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ - { 0x01EF, 0x010F }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ - { 0x01F0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ - { 0x01F1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ - { 0x01F2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ - { 0x01F5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ - { 0x01F8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ - { 0x01F9, 0x016F }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ - { 0x01FB, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ - { 0x01FE, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ - { 0x01FF, 0x02D9 }, /* abovedot ˙ DOT ABOVE */ - { 0x02A1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ - { 0x02A6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ - { 0x02A9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ - { 0x02AB, 0x011E }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ - { 0x02AC, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ - { 0x02B1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ - { 0x02B6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ - { 0x02B9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ - { 0x02BB, 0x011F }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ - { 0x02BC, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ - { 0x02C5, 0x010A }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ - { 0x02C6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ - { 0x02D5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ - { 0x02D8, 0x011C }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ - { 0x02DD, 0x016C }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ - { 0x02DE, 0x015C }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ - { 0x02E5, 0x010B }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ - { 0x02E6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ - { 0x02F5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ - { 0x02F8, 0x011D }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ - { 0x02FD, 0x016D }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ - { 0x02FE, 0x015D }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ - { 0x03A2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ - { 0x03A3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ - { 0x03A5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ - { 0x03A6, 0x013B }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ - { 0x03AA, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ - { 0x03AB, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ - { 0x03AC, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ - { 0x03B3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ - { 0x03B5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ - { 0x03B6, 0x013C }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ - { 0x03BA, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ - { 0x03BB, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ - { 0x03BC, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ - { 0x03BD, 0x014A }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ - { 0x03BF, 0x014B }, /* eng ŋ LATIN SMALL LETTER ENG */ - { 0x03C0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ - { 0x03C7, 0x012E }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ - { 0x03CC, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ - { 0x03CF, 0x012A }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ - { 0x03D1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ - { 0x03D2, 0x014C }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ - { 0x03D3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ - { 0x03D9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ - { 0x03DD, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ - { 0x03DE, 0x016A }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ - { 0x03E0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ - { 0x03E7, 0x012F }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ - { 0x03EC, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ - { 0x03EF, 0x012B }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ - { 0x03F1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ - { 0x03F2, 0x014D }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ - { 0x03F3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ - { 0x03F9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ - { 0x03FD, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ - { 0x03FE, 0x016B }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ - { 0x047E, 0x203E }, /* overline ‾ OVERLINE */ - { 0x04A1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ - { 0x04A2, 0x300C }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ - { 0x04A3, 0x300D }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ - { 0x04A4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ - { 0x04A5, 0x30FB }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ - { 0x04A6, 0x30F2 }, /* kana_WO ヲ KATAKANA LETTER WO */ - { 0x04A7, 0x30A1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ - { 0x04A8, 0x30A3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ - { 0x04A9, 0x30A5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ - { 0x04AA, 0x30A7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ - { 0x04AB, 0x30A9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ - { 0x04AC, 0x30E3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ - { 0x04AD, 0x30E5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ - { 0x04AE, 0x30E7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ - { 0x04AF, 0x30C3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ - { 0x04B0, 0x30FC }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - { 0x04B1, 0x30A2 }, /* kana_A ア KATAKANA LETTER A */ - { 0x04B2, 0x30A4 }, /* kana_I イ KATAKANA LETTER I */ - { 0x04B3, 0x30A6 }, /* kana_U ウ KATAKANA LETTER U */ - { 0x04B4, 0x30A8 }, /* kana_E エ KATAKANA LETTER E */ - { 0x04B5, 0x30AA }, /* kana_O オ KATAKANA LETTER O */ - { 0x04B6, 0x30AB }, /* kana_KA カ KATAKANA LETTER KA */ - { 0x04B7, 0x30AD }, /* kana_KI キ KATAKANA LETTER KI */ - { 0x04B8, 0x30AF }, /* kana_KU ク KATAKANA LETTER KU */ - { 0x04B9, 0x30B1 }, /* kana_KE ケ KATAKANA LETTER KE */ - { 0x04BA, 0x30B3 }, /* kana_KO コ KATAKANA LETTER KO */ - { 0x04BB, 0x30B5 }, /* kana_SA サ KATAKANA LETTER SA */ - { 0x04BC, 0x30B7 }, /* kana_SHI シ KATAKANA LETTER SI */ - { 0x04BD, 0x30B9 }, /* kana_SU ス KATAKANA LETTER SU */ - { 0x04BE, 0x30BB }, /* kana_SE セ KATAKANA LETTER SE */ - { 0x04BF, 0x30BD }, /* kana_SO ソ KATAKANA LETTER SO */ - { 0x04C0, 0x30BF }, /* kana_TA タ KATAKANA LETTER TA */ - { 0x04C1, 0x30C1 }, /* kana_CHI チ KATAKANA LETTER TI */ - { 0x04C2, 0x30C4 }, /* kana_TSU ツ KATAKANA LETTER TU */ - { 0x04C3, 0x30C6 }, /* kana_TE テ KATAKANA LETTER TE */ - { 0x04C4, 0x30C8 }, /* kana_TO ト KATAKANA LETTER TO */ - { 0x04C5, 0x30CA }, /* kana_NA ナ KATAKANA LETTER NA */ - { 0x04C6, 0x30CB }, /* kana_NI ニ KATAKANA LETTER NI */ - { 0x04C7, 0x30CC }, /* kana_NU ヌ KATAKANA LETTER NU */ - { 0x04C8, 0x30CD }, /* kana_NE ネ KATAKANA LETTER NE */ - { 0x04C9, 0x30CE }, /* kana_NO ノ KATAKANA LETTER NO */ - { 0x04CA, 0x30CF }, /* kana_HA ハ KATAKANA LETTER HA */ - { 0x04CB, 0x30D2 }, /* kana_HI ヒ KATAKANA LETTER HI */ - { 0x04CC, 0x30D5 }, /* kana_FU フ KATAKANA LETTER HU */ - { 0x04CD, 0x30D8 }, /* kana_HE ヘ KATAKANA LETTER HE */ - { 0x04CE, 0x30DB }, /* kana_HO ホ KATAKANA LETTER HO */ - { 0x04CF, 0x30DE }, /* kana_MA マ KATAKANA LETTER MA */ - { 0x04D0, 0x30DF }, /* kana_MI ミ KATAKANA LETTER MI */ - { 0x04D1, 0x30E0 }, /* kana_MU ム KATAKANA LETTER MU */ - { 0x04D2, 0x30E1 }, /* kana_ME メ KATAKANA LETTER ME */ - { 0x04D3, 0x30E2 }, /* kana_MO モ KATAKANA LETTER MO */ - { 0x04D4, 0x30E4 }, /* kana_YA ヤ KATAKANA LETTER YA */ - { 0x04D5, 0x30E6 }, /* kana_YU ユ KATAKANA LETTER YU */ - { 0x04D6, 0x30E8 }, /* kana_YO ヨ KATAKANA LETTER YO */ - { 0x04D7, 0x30E9 }, /* kana_RA ラ KATAKANA LETTER RA */ - { 0x04D8, 0x30EA }, /* kana_RI リ KATAKANA LETTER RI */ - { 0x04D9, 0x30EB }, /* kana_RU ル KATAKANA LETTER RU */ - { 0x04DA, 0x30EC }, /* kana_RE レ KATAKANA LETTER RE */ - { 0x04DB, 0x30ED }, /* kana_RO ロ KATAKANA LETTER RO */ - { 0x04DC, 0x30EF }, /* kana_WA ワ KATAKANA LETTER WA */ - { 0x04DD, 0x30F3 }, /* kana_N ン KATAKANA LETTER N */ - { 0x04DE, 0x309B }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ - { 0x04DF, 0x309C }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - { 0x05AC, 0x060C }, /* Arabic_comma ، ARABIC COMMA */ - { 0x05BB, 0x061B }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ - { 0x05BF, 0x061F }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ - { 0x05C1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ - { 0x05C2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ - { 0x05C3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ - { 0x05C4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ - { 0x05C5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ - { 0x05C6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ - { 0x05C7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ - { 0x05C8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ - { 0x05C9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ - { 0x05CA, 0x062A }, /* Arabic_teh ت ARABIC LETTER TEH */ - { 0x05CB, 0x062B }, /* Arabic_theh ث ARABIC LETTER THEH */ - { 0x05CC, 0x062C }, /* Arabic_jeem ج ARABIC LETTER JEEM */ - { 0x05CD, 0x062D }, /* Arabic_hah ح ARABIC LETTER HAH */ - { 0x05CE, 0x062E }, /* Arabic_khah خ ARABIC LETTER KHAH */ - { 0x05CF, 0x062F }, /* Arabic_dal د ARABIC LETTER DAL */ - { 0x05D0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ - { 0x05D1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ - { 0x05D2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ - { 0x05D3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ - { 0x05D4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ - { 0x05D5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ - { 0x05D6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ - { 0x05D7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ - { 0x05D8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ - { 0x05D9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ - { 0x05DA, 0x063A }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ - { 0x05E0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ - { 0x05E1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ - { 0x05E2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ - { 0x05E3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ - { 0x05E4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ - { 0x05E5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ - { 0x05E6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ - { 0x05E7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ - { 0x05E8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ - { 0x05E9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ - { 0x05EA, 0x064A }, /* Arabic_yeh ي ARABIC LETTER YEH */ - { 0x05EB, 0x064B }, /* Arabic_fathatan ً ARABIC FATHATAN */ - { 0x05EC, 0x064C }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ - { 0x05ED, 0x064D }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ - { 0x05EE, 0x064E }, /* Arabic_fatha َ ARABIC FATHA */ - { 0x05EF, 0x064F }, /* Arabic_damma ُ ARABIC DAMMA */ - { 0x05F0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ - { 0x05F1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ - { 0x05F2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ - { 0x06A1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ - { 0x06A2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ - { 0x06A3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ - { 0x06A4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ - { 0x06A5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ - { 0x06A6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ - { 0x06A7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ - { 0x06A8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ - { 0x06A9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ - { 0x06AA, 0x045A }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ - { 0x06AB, 0x045B }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ - { 0x06AC, 0x045C }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ - { 0x06AE, 0x045E }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ - { 0x06AF, 0x045F }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ - { 0x06B0, 0x2116 }, /* numerosign № NUMERO SIGN */ - { 0x06B1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ - { 0x06B2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ - { 0x06B3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ - { 0x06B4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ - { 0x06B5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ - { 0x06B6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ - { 0x06B7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ - { 0x06B8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ - { 0x06B9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ - { 0x06BA, 0x040A }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ - { 0x06BB, 0x040B }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ - { 0x06BC, 0x040C }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ - { 0x06BE, 0x040E }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ - { 0x06BF, 0x040F }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ - { 0x06C0, 0x044E }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ - { 0x06C1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ - { 0x06C2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ - { 0x06C3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ - { 0x06C4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ - { 0x06C5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ - { 0x06C6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ - { 0x06C7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ - { 0x06C8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ - { 0x06C9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ - { 0x06CA, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ - { 0x06CB, 0x043A }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ - { 0x06CC, 0x043B }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ - { 0x06CD, 0x043C }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ - { 0x06CE, 0x043D }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ - { 0x06CF, 0x043E }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ - { 0x06D0, 0x043F }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ - { 0x06D1, 0x044F }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ - { 0x06D2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ - { 0x06D3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ - { 0x06D4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ - { 0x06D5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ - { 0x06D6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ - { 0x06D7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ - { 0x06D8, 0x044C }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ - { 0x06D9, 0x044B }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ - { 0x06DA, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ - { 0x06DB, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ - { 0x06DC, 0x044D }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ - { 0x06DD, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ - { 0x06DE, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ - { 0x06DF, 0x044A }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ - { 0x06E0, 0x042E }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ - { 0x06E1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ - { 0x06E2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ - { 0x06E3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ - { 0x06E4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ - { 0x06E5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ - { 0x06E6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ - { 0x06E7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ - { 0x06E8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ - { 0x06E9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ - { 0x06EA, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ - { 0x06EB, 0x041A }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ - { 0x06EC, 0x041B }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ - { 0x06ED, 0x041C }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ - { 0x06EE, 0x041D }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ - { 0x06EF, 0x041E }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ - { 0x06F0, 0x041F }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ - { 0x06F1, 0x042F }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ - { 0x06F2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ - { 0x06F3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ - { 0x06F4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ - { 0x06F5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ - { 0x06F6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ - { 0x06F7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ - { 0x06F8, 0x042C }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ - { 0x06F9, 0x042B }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ - { 0x06FA, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ - { 0x06FB, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ - { 0x06FC, 0x042D }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ - { 0x06FD, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ - { 0x06FE, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ - { 0x06FF, 0x042A }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ - { 0x07A1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ - { 0x07A2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ - { 0x07A3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ - { 0x07A4, 0x038A }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ - { 0x07A5, 0x03AA }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ - { 0x07A7, 0x038C }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ - { 0x07A8, 0x038E }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ - { 0x07A9, 0x03AB }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ - { 0x07AB, 0x038F }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ - { 0x07AE, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ - { 0x07AF, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ - { 0x07B1, 0x03AC }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ - { 0x07B2, 0x03AD }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ - { 0x07B3, 0x03AE }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ - { 0x07B4, 0x03AF }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ - { 0x07B5, 0x03CA }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ - { 0x07B6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ - { 0x07B7, 0x03CC }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ - { 0x07B8, 0x03CD }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ - { 0x07B9, 0x03CB }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ - { 0x07BA, 0x03B0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ - { 0x07BB, 0x03CE }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ - { 0x07C1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ - { 0x07C2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ - { 0x07C3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ - { 0x07C4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ - { 0x07C5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ - { 0x07C6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ - { 0x07C7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ - { 0x07C8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ - { 0x07C9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ - { 0x07CA, 0x039A }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ - { 0x07CB, 0x039B }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ - { 0x07CC, 0x039C }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ - { 0x07CD, 0x039D }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ - { 0x07CE, 0x039E }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ - { 0x07CF, 0x039F }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ - { 0x07D0, 0x03A0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ - { 0x07D1, 0x03A1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ - { 0x07D2, 0x03A3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ - { 0x07D4, 0x03A4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ - { 0x07D5, 0x03A5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ - { 0x07D6, 0x03A6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ - { 0x07D7, 0x03A7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ - { 0x07D8, 0x03A8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ - { 0x07D9, 0x03A9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ - { 0x07E1, 0x03B1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ - { 0x07E2, 0x03B2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ - { 0x07E3, 0x03B3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ - { 0x07E4, 0x03B4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ - { 0x07E5, 0x03B5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ - { 0x07E6, 0x03B6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ - { 0x07E7, 0x03B7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ - { 0x07E8, 0x03B8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ - { 0x07E9, 0x03B9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ - { 0x07EA, 0x03BA }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ - { 0x07EB, 0x03BB }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ - { 0x07EC, 0x03BC }, /* Greek_mu μ GREEK SMALL LETTER MU */ - { 0x07ED, 0x03BD }, /* Greek_nu ν GREEK SMALL LETTER NU */ - { 0x07EE, 0x03BE }, /* Greek_xi ξ GREEK SMALL LETTER XI */ - { 0x07EF, 0x03BF }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ - { 0x07F0, 0x03C0 }, /* Greek_pi π GREEK SMALL LETTER PI */ - { 0x07F1, 0x03C1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ - { 0x07F2, 0x03C3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ - { 0x07F3, 0x03C2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ - { 0x07F4, 0x03C4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ - { 0x07F5, 0x03C5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ - { 0x07F6, 0x03C6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ - { 0x07F7, 0x03C7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ - { 0x07F8, 0x03C8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ - { 0x07F9, 0x03C9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ - { 0x08A1, 0x23B7 }, /* leftradical ⎷ ??? */ - { 0x08A2, 0x250C }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ - { 0x08A3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */ - { 0x08A4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ - { 0x08A5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ - { 0x08A6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ - { 0x08A7, 0x23A1 }, /* topleftsqbracket ⎡ ??? */ - { 0x08A8, 0x23A3 }, /* botleftsqbracket ⎣ ??? */ - { 0x08A9, 0x23A4 }, /* toprightsqbracket ⎤ ??? */ - { 0x08AA, 0x23A6 }, /* botrightsqbracket ⎦ ??? */ - { 0x08AB, 0x239B }, /* topleftparens ⎛ ??? */ - { 0x08AC, 0x239D }, /* botleftparens ⎝ ??? */ - { 0x08AD, 0x239E }, /* toprightparens ⎞ ??? */ - { 0x08AE, 0x23A0 }, /* botrightparens ⎠ ??? */ - { 0x08AF, 0x23A8 }, /* leftmiddlecurlybrace ⎨ ??? */ - { 0x08B0, 0x23AC }, /* rightmiddlecurlybrace ⎬ ??? */ -/* 0x08B1 topleftsummation ? ??? */ -/* 0x08B2 botleftsummation ? ??? */ -/* 0x08B3 topvertsummationconnector ? ??? */ -/* 0x08B4 botvertsummationconnector ? ??? */ -/* 0x08B5 toprightsummation ? ??? */ -/* 0x08B6 botrightsummation ? ??? */ -/* 0x08B7 rightmiddlesummation ? ??? */ - { 0x08BC, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ - { 0x08BD, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ - { 0x08BE, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ - { 0x08BF, 0x222B }, /* integral ∫ INTEGRAL */ - { 0x08C0, 0x2234 }, /* therefore ∴ THEREFORE */ - { 0x08C1, 0x221D }, /* variation ∝ PROPORTIONAL TO */ - { 0x08C2, 0x221E }, /* infinity ∞ INFINITY */ - { 0x08C5, 0x2207 }, /* nabla ∇ NABLA */ - { 0x08C8, 0x223C }, /* approximate ∼ TILDE OPERATOR */ - { 0x08C9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */ - { 0x08CD, 0x21D4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ - { 0x08CE, 0x21D2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ - { 0x08CF, 0x2261 }, /* identical ≡ IDENTICAL TO */ - { 0x08D6, 0x221A }, /* radical √ SQUARE ROOT */ - { 0x08DA, 0x2282 }, /* includedin ⊂ SUBSET OF */ - { 0x08DB, 0x2283 }, /* includes ⊃ SUPERSET OF */ - { 0x08DC, 0x2229 }, /* intersection ∩ INTERSECTION */ - { 0x08DD, 0x222A }, /* union ∪ UNION */ - { 0x08DE, 0x2227 }, /* logicaland ∧ LOGICAL AND */ - { 0x08DF, 0x2228 }, /* logicalor ∨ LOGICAL OR */ - { 0x08EF, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ - { 0x08F6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ - { 0x08FB, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ - { 0x08FC, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ - { 0x08FD, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ - { 0x08FE, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ -/* 0x09DF blank ? ??? */ - { 0x09E0, 0x25C6 }, /* soliddiamond ◆ BLACK DIAMOND */ - { 0x09E1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ - { 0x09E2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ - { 0x09E3, 0x240C }, /* ff ␌ SYMBOL FOR FORM FEED */ - { 0x09E4, 0x240D }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ - { 0x09E5, 0x240A }, /* lf ␊ SYMBOL FOR LINE FEED */ - { 0x09E8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ - { 0x09E9, 0x240B }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ - { 0x09EA, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ - { 0x09EB, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ - { 0x09EC, 0x250C }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ - { 0x09ED, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ - { 0x09EE, 0x253C }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ - { 0x09EF, 0x23BA }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ - { 0x09F0, 0x23BB }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ - { 0x09F1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ - { 0x09F2, 0x23BC }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ - { 0x09F3, 0x23BD }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ - { 0x09F4, 0x251C }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ - { 0x09F5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ - { 0x09F6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ - { 0x09F7, 0x252C }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ - { 0x09F8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ - { 0x0AA1, 0x2003 }, /* emspace   EM SPACE */ - { 0x0AA2, 0x2002 }, /* enspace   EN SPACE */ - { 0x0AA3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ - { 0x0AA4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ - { 0x0AA5, 0x2007 }, /* digitspace   FIGURE SPACE */ - { 0x0AA6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ - { 0x0AA7, 0x2009 }, /* thinspace   THIN SPACE */ - { 0x0AA8, 0x200A }, /* hairspace   HAIR SPACE */ - { 0x0AA9, 0x2014 }, /* emdash — EM DASH */ - { 0x0AAA, 0x2013 }, /* endash – EN DASH */ -/* 0x0AAC signifblank ? ??? */ - { 0x0AAE, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ - { 0x0AAF, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */ - { 0x0AB0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ - { 0x0AB1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ - { 0x0AB2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ - { 0x0AB3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ - { 0x0AB4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ - { 0x0AB5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ - { 0x0AB6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ - { 0x0AB7, 0x215A }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ - { 0x0AB8, 0x2105 }, /* careof ℅ CARE OF */ - { 0x0ABB, 0x2012 }, /* figdash ‒ FIGURE DASH */ - { 0x0ABC, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ -/* 0x0ABD decimalpoint ? ??? */ - { 0x0ABE, 0x232A }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ -/* 0x0ABF marker ? ??? */ - { 0x0AC3, 0x215B }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ - { 0x0AC4, 0x215C }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ - { 0x0AC5, 0x215D }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ - { 0x0AC6, 0x215E }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ - { 0x0AC9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ - { 0x0ACA, 0x2613 }, /* signaturemark ☓ SALTIRE */ -/* 0x0ACB trademarkincircle ? ??? */ - { 0x0ACC, 0x25C1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ - { 0x0ACD, 0x25B7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ - { 0x0ACE, 0x25CB }, /* emopencircle ○ WHITE CIRCLE */ - { 0x0ACF, 0x25AF }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */ - { 0x0AD0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ - { 0x0AD1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ - { 0x0AD2, 0x201C }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ - { 0x0AD3, 0x201D }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ - { 0x0AD4, 0x211E }, /* prescription ℞ PRESCRIPTION TAKE */ - { 0x0AD6, 0x2032 }, /* minutes ′ PRIME */ - { 0x0AD7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ - { 0x0AD9, 0x271D }, /* latincross ✝ LATIN CROSS */ -/* 0x0ADA hexagram ? ??? */ - { 0x0ADB, 0x25AC }, /* filledrectbullet ▬ BLACK RECTANGLE */ - { 0x0ADC, 0x25C0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ - { 0x0ADD, 0x25B6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ - { 0x0ADE, 0x25CF }, /* emfilledcircle ● BLACK CIRCLE */ - { 0x0ADF, 0x25AE }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */ - { 0x0AE0, 0x25E6 }, /* enopencircbullet ◦ WHITE BULLET */ - { 0x0AE1, 0x25AB }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ - { 0x0AE2, 0x25AD }, /* openrectbullet ▭ WHITE RECTANGLE */ - { 0x0AE3, 0x25B3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ - { 0x0AE4, 0x25BD }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ - { 0x0AE5, 0x2606 }, /* openstar ☆ WHITE STAR */ - { 0x0AE6, 0x2022 }, /* enfilledcircbullet • BULLET */ - { 0x0AE7, 0x25AA }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ - { 0x0AE8, 0x25B2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ - { 0x0AE9, 0x25BC }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ - { 0x0AEA, 0x261C }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ - { 0x0AEB, 0x261E }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ - { 0x0AEC, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ - { 0x0AED, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ - { 0x0AEE, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ - { 0x0AF0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ - { 0x0AF1, 0x2020 }, /* dagger † DAGGER */ - { 0x0AF2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ - { 0x0AF3, 0x2713 }, /* checkmark ✓ CHECK MARK */ - { 0x0AF4, 0x2717 }, /* ballotcross ✗ BALLOT X */ - { 0x0AF5, 0x266F }, /* musicalsharp ♯ MUSIC SHARP SIGN */ - { 0x0AF6, 0x266D }, /* musicalflat ♭ MUSIC FLAT SIGN */ - { 0x0AF7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ - { 0x0AF8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ - { 0x0AF9, 0x260E }, /* telephone ☎ BLACK TELEPHONE */ - { 0x0AFA, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ - { 0x0AFB, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ - { 0x0AFC, 0x2038 }, /* caret ‸ CARET */ - { 0x0AFD, 0x201A }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ - { 0x0AFE, 0x201E }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ -/* 0x0AFF cursor ? ??? */ - { 0x0BA3, 0x003C }, /* leftcaret < LESS-THAN SIGN */ - { 0x0BA6, 0x003E }, /* rightcaret > GREATER-THAN SIGN */ - { 0x0BA8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ - { 0x0BA9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ - { 0x0BC0, 0x00AF }, /* overbar ¯ MACRON */ - { 0x0BC2, 0x22A5 }, /* downtack ⊥ UP TACK */ - { 0x0BC3, 0x2229 }, /* upshoe ∩ INTERSECTION */ - { 0x0BC4, 0x230A }, /* downstile ⌊ LEFT FLOOR */ - { 0x0BC6, 0x005F }, /* underbar _ LOW LINE */ - { 0x0BCA, 0x2218 }, /* jot ∘ RING OPERATOR */ - { 0x0BCC, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ - { 0x0BCE, 0x22A4 }, /* uptack ⊤ DOWN TACK */ - { 0x0BCF, 0x25CB }, /* circle ○ WHITE CIRCLE */ - { 0x0BD3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ - { 0x0BD6, 0x222A }, /* downshoe ∪ UNION */ - { 0x0BD8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ - { 0x0BDA, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ - { 0x0BDC, 0x22A2 }, /* lefttack ⊢ RIGHT TACK */ - { 0x0BFC, 0x22A3 }, /* righttack ⊣ LEFT TACK */ - { 0x0CDF, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ - { 0x0CE0, 0x05D0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ - { 0x0CE1, 0x05D1 }, /* hebrew_bet ב HEBREW LETTER BET */ - { 0x0CE2, 0x05D2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ - { 0x0CE3, 0x05D3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ - { 0x0CE4, 0x05D4 }, /* hebrew_he ה HEBREW LETTER HE */ - { 0x0CE5, 0x05D5 }, /* hebrew_waw ו HEBREW LETTER VAV */ - { 0x0CE6, 0x05D6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ - { 0x0CE7, 0x05D7 }, /* hebrew_chet ח HEBREW LETTER HET */ - { 0x0CE8, 0x05D8 }, /* hebrew_tet ט HEBREW LETTER TET */ - { 0x0CE9, 0x05D9 }, /* hebrew_yod י HEBREW LETTER YOD */ - { 0x0CEA, 0x05DA }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ - { 0x0CEB, 0x05DB }, /* hebrew_kaph כ HEBREW LETTER KAF */ - { 0x0CEC, 0x05DC }, /* hebrew_lamed ל HEBREW LETTER LAMED */ - { 0x0CED, 0x05DD }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ - { 0x0CEE, 0x05DE }, /* hebrew_mem מ HEBREW LETTER MEM */ - { 0x0CEF, 0x05DF }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ - { 0x0CF0, 0x05E0 }, /* hebrew_nun נ HEBREW LETTER NUN */ - { 0x0CF1, 0x05E1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ - { 0x0CF2, 0x05E2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ - { 0x0CF3, 0x05E3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ - { 0x0CF4, 0x05E4 }, /* hebrew_pe פ HEBREW LETTER PE */ - { 0x0CF5, 0x05E5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ - { 0x0CF6, 0x05E6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ - { 0x0CF7, 0x05E7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ - { 0x0CF8, 0x05E8 }, /* hebrew_resh ר HEBREW LETTER RESH */ - { 0x0CF9, 0x05E9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ - { 0x0CFA, 0x05EA }, /* hebrew_taw ת HEBREW LETTER TAV */ - { 0x0DA1, 0x0E01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ - { 0x0DA2, 0x0E02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ - { 0x0DA3, 0x0E03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ - { 0x0DA4, 0x0E04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ - { 0x0DA5, 0x0E05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ - { 0x0DA6, 0x0E06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ - { 0x0DA7, 0x0E07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ - { 0x0DA8, 0x0E08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ - { 0x0DA9, 0x0E09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ - { 0x0DAA, 0x0E0A }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ - { 0x0DAB, 0x0E0B }, /* Thai_soso ซ THAI CHARACTER SO SO */ - { 0x0DAC, 0x0E0C }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ - { 0x0DAD, 0x0E0D }, /* Thai_yoying ญ THAI CHARACTER YO YING */ - { 0x0DAE, 0x0E0E }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ - { 0x0DAF, 0x0E0F }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ - { 0x0DB0, 0x0E10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ - { 0x0DB1, 0x0E11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ - { 0x0DB2, 0x0E12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ - { 0x0DB3, 0x0E13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ - { 0x0DB4, 0x0E14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ - { 0x0DB5, 0x0E15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ - { 0x0DB6, 0x0E16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ - { 0x0DB7, 0x0E17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ - { 0x0DB8, 0x0E18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ - { 0x0DB9, 0x0E19 }, /* Thai_nonu น THAI CHARACTER NO NU */ - { 0x0DBA, 0x0E1A }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ - { 0x0DBB, 0x0E1B }, /* Thai_popla ป THAI CHARACTER PO PLA */ - { 0x0DBC, 0x0E1C }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ - { 0x0DBD, 0x0E1D }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ - { 0x0DBE, 0x0E1E }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ - { 0x0DBF, 0x0E1F }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ - { 0x0DC0, 0x0E20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ - { 0x0DC1, 0x0E21 }, /* Thai_moma ม THAI CHARACTER MO MA */ - { 0x0DC2, 0x0E22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ - { 0x0DC3, 0x0E23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ - { 0x0DC4, 0x0E24 }, /* Thai_ru ฤ THAI CHARACTER RU */ - { 0x0DC5, 0x0E25 }, /* Thai_loling ล THAI CHARACTER LO LING */ - { 0x0DC6, 0x0E26 }, /* Thai_lu ฦ THAI CHARACTER LU */ - { 0x0DC7, 0x0E27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ - { 0x0DC8, 0x0E28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ - { 0x0DC9, 0x0E29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ - { 0x0DCA, 0x0E2A }, /* Thai_sosua ส THAI CHARACTER SO SUA */ - { 0x0DCB, 0x0E2B }, /* Thai_hohip ห THAI CHARACTER HO HIP */ - { 0x0DCC, 0x0E2C }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ - { 0x0DCD, 0x0E2D }, /* Thai_oang อ THAI CHARACTER O ANG */ - { 0x0DCE, 0x0E2E }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ - { 0x0DCF, 0x0E2F }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ - { 0x0DD0, 0x0E30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ - { 0x0DD1, 0x0E31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ - { 0x0DD2, 0x0E32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ - { 0x0DD3, 0x0E33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ - { 0x0DD4, 0x0E34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ - { 0x0DD5, 0x0E35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ - { 0x0DD6, 0x0E36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ - { 0x0DD7, 0x0E37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ - { 0x0DD8, 0x0E38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ - { 0x0DD9, 0x0E39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ - { 0x0DDA, 0x0E3A }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ -/* 0x0DDE Thai_maihanakat_maitho ? ??? */ - { 0x0DDF, 0x0E3F }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ - { 0x0DE0, 0x0E40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ - { 0x0DE1, 0x0E41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ - { 0x0DE2, 0x0E42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ - { 0x0DE3, 0x0E43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ - { 0x0DE4, 0x0E44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ - { 0x0DE5, 0x0E45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ - { 0x0DE6, 0x0E46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ - { 0x0DE7, 0x0E47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ - { 0x0DE8, 0x0E48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ - { 0x0DE9, 0x0E49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ - { 0x0DEA, 0x0E4A }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ - { 0x0DEB, 0x0E4B }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ - { 0x0DEC, 0x0E4C }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ - { 0x0DED, 0x0E4D }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ - { 0x0DF0, 0x0E50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ - { 0x0DF1, 0x0E51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ - { 0x0DF2, 0x0E52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ - { 0x0DF3, 0x0E53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ - { 0x0DF4, 0x0E54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ - { 0x0DF5, 0x0E55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ - { 0x0DF6, 0x0E56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ - { 0x0DF7, 0x0E57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ - { 0x0DF8, 0x0E58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ - { 0x0DF9, 0x0E59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ - { 0x0EA1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ - { 0x0EA2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ - { 0x0EA3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ - { 0x0EA4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ - { 0x0EA5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ - { 0x0EA6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ - { 0x0EA7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ - { 0x0EA8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ - { 0x0EA9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ - { 0x0EAA, 0x313A }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ - { 0x0EAB, 0x313B }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ - { 0x0EAC, 0x313C }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ - { 0x0EAD, 0x313D }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ - { 0x0EAE, 0x313E }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ - { 0x0EAF, 0x313F }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ - { 0x0EB0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ - { 0x0EB1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ - { 0x0EB2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ - { 0x0EB3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ - { 0x0EB4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ - { 0x0EB5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ - { 0x0EB6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ - { 0x0EB7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ - { 0x0EB8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ - { 0x0EB9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ - { 0x0EBA, 0x314A }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ - { 0x0EBB, 0x314B }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ - { 0x0EBC, 0x314C }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ - { 0x0EBD, 0x314D }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ - { 0x0EBE, 0x314E }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ - { 0x0EBF, 0x314F }, /* Hangul_A ㅏ HANGUL LETTER A */ - { 0x0EC0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ - { 0x0EC1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ - { 0x0EC2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ - { 0x0EC3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ - { 0x0EC4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ - { 0x0EC5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ - { 0x0EC6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ - { 0x0EC7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ - { 0x0EC8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ - { 0x0EC9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ - { 0x0ECA, 0x315A }, /* Hangul_OE ㅚ HANGUL LETTER OE */ - { 0x0ECB, 0x315B }, /* Hangul_YO ㅛ HANGUL LETTER YO */ - { 0x0ECC, 0x315C }, /* Hangul_U ㅜ HANGUL LETTER U */ - { 0x0ECD, 0x315D }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ - { 0x0ECE, 0x315E }, /* Hangul_WE ㅞ HANGUL LETTER WE */ - { 0x0ECF, 0x315F }, /* Hangul_WI ㅟ HANGUL LETTER WI */ - { 0x0ED0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ - { 0x0ED1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ - { 0x0ED2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ - { 0x0ED3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ - { 0x0ED4, 0x11A8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ - { 0x0ED5, 0x11A9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ - { 0x0ED6, 0x11AA }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ - { 0x0ED7, 0x11AB }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ - { 0x0ED8, 0x11AC }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ - { 0x0ED9, 0x11AD }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ - { 0x0EDA, 0x11AE }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ - { 0x0EDB, 0x11AF }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ - { 0x0EDC, 0x11B0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ - { 0x0EDD, 0x11B1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ - { 0x0EDE, 0x11B2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ - { 0x0EDF, 0x11B3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ - { 0x0EE0, 0x11B4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ - { 0x0EE1, 0x11B5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ - { 0x0EE2, 0x11B6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ - { 0x0EE3, 0x11B7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ - { 0x0EE4, 0x11B8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ - { 0x0EE5, 0x11B9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ - { 0x0EE6, 0x11BA }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ - { 0x0EE7, 0x11BB }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ - { 0x0EE8, 0x11BC }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ - { 0x0EE9, 0x11BD }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ - { 0x0EEA, 0x11BE }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ - { 0x0EEB, 0x11BF }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ - { 0x0EEC, 0x11C0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ - { 0x0EED, 0x11C1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ - { 0x0EEE, 0x11C2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ - { 0x0EEF, 0x316D }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ - { 0x0EF0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ - { 0x0EF1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ - { 0x0EF2, 0x317F }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ - { 0x0EF3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */ - { 0x0EF4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ - { 0x0EF5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ - { 0x0EF6, 0x318D }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ - { 0x0EF7, 0x318E }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ - { 0x0EF8, 0x11EB }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ - { 0x0EF9, 0x11F0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */ - { 0x0EFA, 0x11F9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ - { 0x0EFF, 0x20A9 }, /* Korean_Won ₩ WON SIGN */ - { 0x13A4, 0x20AC }, /* Euro € EURO SIGN */ - { 0x13BC, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ - { 0x13BD, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ - { 0x13BE, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ - { 0x20AC, 0x20AC }, /* EuroSign € EURO SIGN */ -}; - -/*********************************************************************** - * The following function converts ISO 10646-1 (UCS, Unicode) values to - * their corresponding KeySym values. - * - * The UTF-8 -> keysym conversion will hopefully one day be provided by - * Xlib via XmbLookupString() and should ideally not have to be - * done in X applications. But we are not there yet. - * - * Author: Markus G. Kuhn , University of Cambridge, - * June 1999 - * - * Special thanks to Richard Verhoeven for preparing - * an initial draft of the mapping table. - * - * This software is in the public domain. Share and enjoy! - ***********************************************************************/ -KeySym unicode_to_keysym(uint16_t unicode) { - int min = 0; - int max = sizeof(keysym_unicode_table) / sizeof(struct codepair) - 1; - int mid; - - #ifdef XK_LATIN1 - // First check for Latin-1 characters. (1:1 mapping) - if ((unicode >= 0x0020 && unicode <= 0x007E) || - (unicode >= 0x00A0 && unicode <= 0x00FF)) { - return unicode; - } - #endif - - // Binary search the lookup table. - while (max >= min) { - mid = (min + max) / 2; - if (keysym_unicode_table[mid].unicode < unicode) { - min = mid + 1; - } - else if (keysym_unicode_table[mid].unicode > unicode) { - max = mid - 1; - } - else { - // Found it. - return keysym_unicode_table[mid].keysym; - } - } - - // No matching KeySym value found, return UCS2 with bit set. - return unicode | 0x01000000; -} - - -/*********************************************************************** - * The following function converts KeySym values into the corresponding - * ISO 10646-1 (UCS, Unicode) values. - * - * The keysym -> UTF-8 conversion will hopefully one day be provided by - * Xlib via XLookupKeySym and should ideally not have to be done in X - * applications. But we are not there yet. - * - * Author: Markus G. Kuhn , University of Cambridge, - * June 1999 - * - * Special thanks to Richard Verhoeven for preparing - * an initial draft of the mapping table. - * - * This software is in the public domain. Share and enjoy! - ***********************************************************************/ -size_t keysym_to_unicode(KeySym keysym, uint16_t *buffer, size_t size) { - size_t count = 0; - - int min = 0; - int max = sizeof(keysym_unicode_table) / sizeof(struct codepair) - 1; - int mid; - - #ifdef XK_LATIN1 - // First check for Latin-1 characters. (1:1 mapping) - if ((keysym >= 0x0020 && keysym <= 0x007E) - || (keysym >= 0x00A0 && keysym <= 0x00FF)) { - - if (count < size) { - buffer[count++] = keysym; - } - - return count; - } - #endif - - // Also check for directly encoded 24-bit UCS characters. - #if defined(XK_LATIN8) || defined(XK_ARABIC) || defined(XK_CYRILLIC) || \ - defined(XK_ARMENIAN) || defined(XK_GEORGIAN) || defined(XK_CAUCASUS) || \ - defined(XK_VIETNAMESE) || defined(XK_CURRENCY) || \ - defined(XK_MATHEMATICAL) || defined(XK_BRAILLE) || defined(XK_SINHALA) - if ((keysym & 0xFF000000) == 0x01000000) { - if (count < size) { - buffer[count++] = keysym & 0x00FFFFFF; - } - - return count; - } - #endif - - // Binary search in table. - while (max >= min) { - mid = (min + max) / 2; - if (keysym_unicode_table[mid].keysym < keysym) { - min = mid + 1; - } - else if (keysym_unicode_table[mid].keysym > keysym) { - max = mid - 1; - } - else { - // Found it. - if (count < size) { - buffer[count++] = keysym_unicode_table[mid].unicode; - } - - return count; - } - } - - // No matching Unicode value found! - return count; -} - - -/* The following code is based on vncdisplaykeymap.c under the following terms: - * - * Copyright (C) 2008 Anthony Liguori - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2 as - * published by the Free Software Foundation. - */ -uint16_t keycode_to_scancode(KeyCode keycode) { - uint16_t scancode = VC_UNDEFINED; - - #if defined(USE_EVDEV) && defined(USE_XKB) - // Check to see if evdev is enabled. - if (is_evdev) { - unsigned short evdev_size = sizeof(evdev_scancode_table) / sizeof(evdev_scancode_table[0]); - - // NOTE scancodes < 97 appear to be identical between Evdev and XFree86. - if (keycode < evdev_size) { - // For scancode < 97, a simple scancode - 8 offest could be applied, - // but math is generally slower than memory and we cannot save any - // extra space in the lookup table due to binary padding. - scancode = evdev_scancode_table[keycode][0]; - } - } - else { - // Evdev was disabled, fallback to XFree86. - #endif - unsigned short xfree86_size = sizeof(xfree86_scancode_table) / sizeof(xfree86_scancode_table[0]); - - // NOTE scancodes < 97 appear to be identical between Evdev and XFree86. - if (keycode < xfree86_size) { - // For scancode < 97, a simple scancode - 8 offest could be applied, - // but math is generally slower than memory and we cannot save any - // extra space in the lookup table due to binary padding. - scancode = xfree86_scancode_table[keycode][0]; - } - #if defined(USE_EVDEV) && defined(USE_XKB) - } - #endif - - return scancode; -} - -KeyCode scancode_to_keycode(uint16_t scancode) { - KeyCode keycode = 0x0000; - - #if defined(USE_EVDEV) && defined(USE_XKB) - // Check to see if Evdev is enabled. - if (is_evdev) { - unsigned short evdev_size = sizeof(evdev_scancode_table) / sizeof(evdev_scancode_table[0]); - - // NOTE scancodes < 97 appear to be identical between Evdev and XFree86. - if (scancode < 128) { - // For scancode < 97, a simple scancode + 8 offest could be applied, - // but math is generally slower than memory and we cannot save any - // extra space in the lookup table due to binary padding. - keycode = evdev_scancode_table[scancode][1]; - } - else { - // Offset is the lower order bits + 128 - scancode = (scancode & 0x007F) | 0x80; - - if (scancode < evdev_size) { - keycode = evdev_scancode_table[scancode][1]; - } - } - } - else { - // Evdev was disabled, fallback to XFree86. - #endif - unsigned short xfree86_size = sizeof(xfree86_scancode_table) / sizeof(xfree86_scancode_table[0]); - - // NOTE scancodes < 97 appear to be identical between Evdev and XFree86. - if (scancode < 128) { - // For scancode < 97, a simple scancode + 8 offest could be applied, - // but math is generally slower than memory and we cannot save any - // extra space in the lookup table due to binary padding. - keycode = xfree86_scancode_table[scancode][1]; - } - else { - // Offset: lower order bits + 128 (If no size optimization!) - scancode = (scancode & 0x007F) | 0x80; - - if (scancode < xfree86_size) { - keycode = xfree86_scancode_table[scancode][1]; - } - } - #if defined(USE_EVDEV) && defined(USE_XKB) - } - #endif - - return keycode; -} - -#ifdef USE_XKBCOMMON -struct xkb_state * create_xkb_state(struct xkb_context *context, xcb_connection_t *connection) { - struct xkb_keymap *keymap; - struct xkb_state *state; - - int32_t device_id = xkb_x11_get_core_keyboard_device_id(connection); - if (device_id >= 0) { - keymap = xkb_x11_keymap_new_from_device(context, connection, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS); - state = xkb_x11_state_new_from_device(keymap, connection, device_id); - } - #ifdef USE_XKBFILE - else { - // Evdev fallback, - logger(LOG_LEVEL_WARN, "%s [%u]: Unable to retrieve core keyboard device id! (%d)\n", - __FUNCTION__, __LINE__, device_id); - - keymap = xkb_keymap_new_from_names(context, &xkb_names, XKB_KEYMAP_COMPILE_NO_FLAGS); - state = xkb_state_new(keymap); - } - #endif - - xkb_map_unref(keymap); - return xkb_state_ref(state); -} - -void destroy_xkb_state(struct xkb_state* state) { - xkb_state_unref(state); -} - -size_t keycode_to_unicode(struct xkb_state* state, KeyCode keycode, uint16_t *buffer, size_t length) { - size_t count = 0; - - if (state != NULL) { - uint32_t unicode = xkb_state_key_get_utf32(state, keycode); - - if (unicode <= 0x10FFFF) { - if ((unicode <= 0xD7FF || (unicode >= 0xE000 && unicode <= 0xFFFF)) && length >= 1) { - buffer[0] = unicode; - count = 1; - } - else if (unicode >= 0x10000) { - unsigned int code = (unicode - 0x10000); - buffer[0] = 0xD800 | (code >> 10); - buffer[1] = 0xDC00 | (code & 0x3FF); - count = 2; - } - } - } - - return count; -} -#else -// Faster more flexible alternative to XKeycodeToKeysym... -KeySym keycode_to_keysym(KeyCode keycode, unsigned int modifier_mask) { - KeySym keysym = NoSymbol; - - #ifdef USE_XKB - if (keyboard_map != NULL) { - // Get the range and number of symbols groups bound to the key. - unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode); - unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode); - - // Get the group. - unsigned int group = 0x0000; - switch (XkbOutOfRangeGroupAction(info)) { - case XkbRedirectIntoRange: - /* If the RedirectIntoRange flag is set, the four least significant - * bits of the groups wrap control specify the index of a group to - * which all illegal groups correspond. If the specified group is - * also out of range, all illegal groups map to Group1. - */ - group = XkbOutOfRangeGroupInfo(info); - if (group >= num_groups) { - group = 0; - } - break; - - case XkbClampIntoRange: - /* If the ClampIntoRange flag is set, out-of-range groups correspond - * to the nearest legal group. Effective groups larger than the - * highest supported group are mapped to the highest supported group; - * effective groups less than Group1 are mapped to Group1 . For - * example, a key with two groups of symbols uses Group2 type and - * symbols if the global effective group is either Group3 or Group4. - */ - group = num_groups - 1; - break; - - case XkbWrapIntoRange: - /* If neither flag is set, group is wrapped into range using integer - * modulus. For example, a key with two groups of symbols for which - * groups wrap uses Group1 symbols if the global effective group is - * Group3 or Group2 symbols if the global effective group is Group4. - */ - default: - if (num_groups != 0) { - group %= num_groups; - } - break; - } - - XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group); - unsigned int active_mods = modifier_mask & key_type->mods.mask; - - int i, level = 0; - for (i = 0; i < key_type->map_count; i++) { - if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) { - level = key_type->map[i].level; - } - } - - keysym = XkbKeySymEntry(keyboard_map, keycode, level, group); - } - #else - if (keyboard_map != NULL) { - if (modifier_mask & Mod2Mask && - ((keyboard_map[keycode *keysym_per_keycode + 1] >= 0xFF80 && keyboard_map[keycode *keysym_per_keycode + 1] <= 0xFFBD) || - (keyboard_map[keycode *keysym_per_keycode + 1] >= 0x11000000 && keyboard_map[keycode *keysym_per_keycode + 1] <= 0x1100FFFF)) - ) { - - /* If the numlock modifier is on and the second KeySym is a keypad - * KeySym. In this case, if the Shift modifier is on, or if the - * Lock modifier is on and is interpreted as ShiftLock, then the - * first KeySym is used, otherwise the second KeySym is used. - * - * The standard KeySyms with the prefix ``XK_KP_'' in their name are - * called keypad KeySyms; these are KeySyms with numeric value in - * the hexadecimal range 0xFF80 to 0xFFBD inclusive. In addition, - * vendor-specific KeySyms in the hexadecimal range 0x11000000 to - * 0x1100FFFF are also keypad KeySyms. - */ - - - /* The numlock modifier is on and the second KeySym is a keypad - * KeySym. In this case, if the Shift modifier is on, or if the - * Lock modifier is on and is interpreted as ShiftLock, then the - * first KeySym is used, otherwise the second KeySym is used. - */ - if (modifier_mask & ShiftMask || (modifier_mask & LockMask && is_shift_lock)) { - // i = 0 - keysym = keyboard_map[keycode *keysym_per_keycode]; - } - else { - // i = 1 - keysym = keyboard_map[keycode *keysym_per_keycode + 1]; - } - } - else if (modifier_mask ^ ShiftMask && modifier_mask ^ LockMask) { - /* The Shift and Lock modifiers are both off. In this case, - * the first KeySym is used. - */ - // index = 0 - keysym = keyboard_map[keycode *keysym_per_keycode]; - } - else if (modifier_mask ^ ShiftMask && modifier_mask & LockMask && is_caps_lock) { - /* The Shift modifier is off, and the Lock modifier is on - * and is interpreted as CapsLock. In this case, the first - * KeySym is used, but if that KeySym is lowercase - * alphabetic, then the corresponding uppercase KeySym is - * used instead. - */ - // index = 0; - keysym = keyboard_map[keycode *keysym_per_keycode]; - - if (keysym >= 'a' && keysym <= 'z') { - // keysym is an alpha char. - KeySym lower_keysym, upper_keysym; - XConvertCase(keysym, &lower_keysym, &upper_keysym); - keysym = upper_keysym; - } - } - else if (modifier_mask & ShiftMask && modifier_mask & LockMask && is_caps_lock) { - /* The Shift modifier is on, and the Lock modifier is on and - * is interpreted as CapsLock. In this case, the second - * KeySym is used, but if that KeySym is lowercase - * alphabetic, then the corresponding uppercase KeySym is - * used instead. - */ - // index = 1 - keysym = keyboard_map[keycode *keysym_per_keycode + 1]; - - if (keysym >= 'A' && keysym <= 'Z') { - // keysym is an alpha char. - KeySym lower_keysym, upper_keysym; - XConvertCase(keysym, &lower_keysym, &upper_keysym); - keysym = lower_keysym; - } - } - else if (modifier_mask & ShiftMask || (modifier_mask & LockMask && is_shift_lock) || modifier_mask & (ShiftMask + LockMask)) { - /* The Shift modifier is on, or the Lock modifier is on and - * is interpreted as ShiftLock, or both. In this case, the - * second KeySym is used. - */ - // index = 1 - keysym = keyboard_map[keycode *keysym_per_keycode + 1]; - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Unable to determine the KeySym index!\n", - __FUNCTION__, __LINE__); - } - } - #endif - - return keysym; -} -#endif - -void load_input_helper(Display *disp) { - #ifdef USE_XKB - /* The following code block is based on vncdisplaykeymap.c under the terms: - * - * Copyright (C) 2008 Anthony Liguori - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2 as - * published by the Free Software Foundation. - */ - XkbDescPtr desc = XkbGetKeyboard(disp, XkbGBN_AllComponentsMask, XkbUseCoreKbd); - if (desc != NULL && desc->names != NULL) { - const char *layout_name = XGetAtomName(disp, desc->names->keycodes); - logger(LOG_LEVEL_DEBUG, - "%s [%u]: Found keycode atom '%s' (%i)!\n", - __FUNCTION__, __LINE__, layout_name, - (unsigned int) desc->names->keycodes); - - const char *prefix_xfree86 = "xfree86_"; - #if defined(USE_EVDEV) && defined(USE_XKB) - const char *prefix_evdev = "evdev_"; - if (strncmp(layout_name, prefix_evdev, strlen(prefix_evdev)) == 0) { - is_evdev = true; - } else - #endif - if (strncmp(layout_name, prefix_xfree86, strlen(prefix_xfree86)) != 0) { - // logger(LOG_LEVEL_ERROR, - // "%s [%u]: Unknown keycode name '%s', please file a bug report!\n", - // __FUNCTION__, __LINE__, layout_name); - } - else if (layout_name == NULL) { - logger(LOG_LEVEL_ERROR, - "%s [%u]: X atom name failure for desc->names->keycodes!\n", - __FUNCTION__, __LINE__); - } - - XkbFreeClientMap(desc, XkbGBN_AllComponentsMask, True); - } - else { - logger(LOG_LEVEL_ERROR, - "%s [%u]: XkbGetKeyboard failed to locate a valid keyboard!\n", - __FUNCTION__, __LINE__); - } - - // Get the map. - keyboard_map = XkbGetMap(disp, XkbAllClientInfoMask, XkbUseCoreKbd); - #else - // No known alternative to determine scancode mapping, assume XFree86! - // printf("%s\n", "No known alternative to determine scancode mapping, assume XFree86!"); - // #pragma message("*** Warning: XKB support is required to accurately determine keyboard scancodes!") - // #pragma message("... Assuming XFree86 keyboard layout.") - - logger(LOG_LEVEL_WARN, "%s [%u]: Using XFree86 keyboard layout.\n", - __FUNCTION__, __LINE__); - logger(LOG_LEVEL_WARN, "%s [%u]: XKB support is required to accurately determine keyboard characters!\n", - __FUNCTION__, __LINE__); - - int minKeyCode, maxKeyCode; - XDisplayKeycodes(disp, &minKeyCode, &maxKeyCode); - - keyboard_map = XGetKeyboardMapping(disp, minKeyCode, (maxKeyCode - minKeyCode + 1), &keysym_per_keycode); - if (keyboard_map) { - XModifierKeymap *modifierMap = XGetModifierMapping(disp); - - if (modifierMap) { - /* The Lock modifier is interpreted as CapsLock when the KeySym - * named XK_Caps_Lock is attached to some KeyCode and that KeyCode - * is attached to the Lock modifier. The Lock modifier is - * interpreted as ShiftLock when the KeySym named XK_Shift_Lock is - * attached to some KeyCode and that KeyCode is attached to the Lock - * modifier. If the Lock modifier could be interpreted as both - * CapsLock and ShiftLock, the CapsLock interpretation is used. - */ - - KeyCode capsLock = XKeysymToKeycode(disp, XK_Caps_Lock); - KeyCode shiftLock = XKeysymToKeycode(disp, XK_Shift_Lock); - keysym_per_keycode--; - - // Loop over the modifier map to find out if/where shift and caps locks are set. - int i; - for (i = LockMapIndex; i < LockMapIndex + modifierMap->max_keypermod && !is_caps_lock; i++) { - if (capsLock != 0 && modifierMap->modifiermap[i] == capsLock) { - is_caps_lock = true; - is_shift_lock = false; - } - else if (shiftLock != 0 && modifierMap->modifiermap[i] == shiftLock) { - is_shift_lock = true; - } - } - - XFree(modifierMap); - } - else { - XFree(keyboard_map); - - logger(LOG_LEVEL_ERROR, - "%s [%u]: Unable to get modifier mapping table!\n", - __FUNCTION__, __LINE__); - } - } - else { - logger(LOG_LEVEL_ERROR, - "%s [%u]: Unable to get keyboard mapping table!\n", - __FUNCTION__, __LINE__); - } - #endif -} - -void unload_input_helper() { - if (keyboard_map) { - #ifdef USE_XKB - XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true); - #if defined(USE_EVDEV) && defined(USE_XKB) - is_evdev = false; - #endif - #else - XFree(keyboard_map); - #endif - } -} diff --git a/cdeps/hook/x11/properties_c.h b/cdeps/hook/x11/properties_c.h deleted file mode 100644 index 9358143..0000000 --- a/cdeps/hook/x11/properties_c.h +++ /dev/null @@ -1,499 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#ifdef USE_XKB - #include -#endif -#ifdef USE_XF86MISC - #include - #include -#endif -#if defined(USE_XINERAMA) && !defined(USE_XRANDR) - #include -#elif defined(USE_XRANDR) -#include - #include -#endif -#ifdef USE_XT - #include - - static XtAppContext xt_context; - static Display *xt_disp; -#endif - -#include "../iohook.h" -#include "input.h" -// #include "../logger.h" - -Display *properties_disp; - -#ifdef USE_XRANDR -static pthread_mutex_t xrandr_mutex = PTHREAD_MUTEX_INITIALIZER; -static XRRScreenResources *xrandr_resources = NULL; - -static void settings_cleanup_proc(void *arg) { - if (pthread_mutex_trylock(&xrandr_mutex) == 0) { - if (xrandr_resources != NULL) { - XRRFreeScreenResources(xrandr_resources); - xrandr_resources = NULL; - } - - if (arg != NULL) { - XCloseDisplay((Display *) arg); - arg = NULL; - } - - pthread_mutex_unlock(&xrandr_mutex); - } -} - -static void *settings_thread_proc(void *arg) { - Display *settings_disp = XOpenDisplay(XDisplayName(NULL));; - if (settings_disp != NULL) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay success."); - - pthread_cleanup_push(settings_cleanup_proc, settings_disp); - - int event_base = 0; - int error_base = 0; - if (XRRQueryExtension(settings_disp, &event_base, &error_base)) { - Window root = XDefaultRootWindow(settings_disp); - unsigned long event_mask = RRScreenChangeNotifyMask; - XRRSelectInput(settings_disp, root, event_mask); - - XEvent ev; - - while(settings_disp != NULL) { - XNextEvent(settings_disp, &ev); - - if (ev.type == event_base + RRScreenChangeNotifyMask) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Received XRRScreenChangeNotifyEvent.\n", - __FUNCTION__, __LINE__); - - pthread_mutex_lock(&xrandr_mutex); - if (xrandr_resources != NULL) { - XRRFreeScreenResources(xrandr_resources); - } - - xrandr_resources = XRRGetScreenResources(settings_disp, root); - if (xrandr_resources == NULL) { - logger(LOG_LEVEL_WARN, "%s [%u]: XRandR could not get screen resources!\n", - __FUNCTION__, __LINE__); - } - pthread_mutex_unlock(&xrandr_mutex); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: XRandR is not currently available!\n", - __FUNCTION__, __LINE__); - } - } - } - - // Execute the thread cleanup handler. - pthread_cleanup_pop(1); - - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: XOpenDisplay failure!\n", - __FUNCTION__, __LINE__); - } - - return NULL; -} -#endif - -IOHOOK_API screen_data* hook_create_screen_info(unsigned char *count) { - *count = 0; - screen_data *screens = NULL; - - #if defined(USE_XINERAMA) && !defined(USE_XRANDR) - if (XineramaIsActive(properties_disp)) { - int xine_count = 0; - XineramaScreenInfo *xine_info = XineramaQueryScreens(properties_disp, &xine_count); - - if (xine_info != NULL) { - if (xine_count > UINT8_MAX) { - *count = UINT8_MAX; - - logger(LOG_LEVEL_WARN, "%s [%u]: Screen count overflow detected!\n", - __FUNCTION__, __LINE__); - } - else { - *count = (uint8_t) xine_count; - } - - screens = malloc(sizeof(screen_data) * xine_count); - - if (screens != NULL) { - int i; - for (i = 0; i < xine_count; i++) { - screens[i] = (screen_data) { - .number = xine_info[i].screen_number, - .x = xine_info[i].x_org, - .y = xine_info[i].y_org, - .width = xine_info[i].width, - .height = xine_info[i].height - }; - } - } - - XFree(xine_info); - } - } - #elif defined(USE_XRANDR) - pthread_mutex_lock(&xrandr_mutex); - if (xrandr_resources != NULL) { - int xrandr_count = xrandr_resources->ncrtc; - if (xrandr_count > UINT8_MAX) { - *count = UINT8_MAX; - - logger(LOG_LEVEL_WARN, "%s [%u]: Screen count overflow detected!\n", - __FUNCTION__, __LINE__); - } - else { - *count = (uint8_t) xrandr_count; - } - - screens = malloc(sizeof(screen_data) * xrandr_count); - - if (screens != NULL) { - int i; - for (i = 0; i < xrandr_count; i++) { - XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(properties_disp, xrandr_resources, xrandr_resources->crtcs[i]); - - if (crtc_info != NULL) { - screens[i] = (screen_data) { - .number = i + 1, - .x = crtc_info->x, - .y = crtc_info->y, - .width = crtc_info->width, - .height = crtc_info->height - }; - - XRRFreeCrtcInfo(crtc_info); - } - else { - logger(LOG_LEVEL_WARN, "%s [%u]: XRandr failed to return crtc information! (%#X)\n", - __FUNCTION__, __LINE__, xrandr_resources->crtcs[i]); - } - } - } - } - pthread_mutex_unlock(&xrandr_mutex); - #else - Screen* default_screen = DefaultScreenOfDisplay(properties_disp); - - if (default_screen->width > 0 && default_screen->height > 0) { - screens = malloc(sizeof(screen_data)); - - if (screens != NULL) { - *count = 1; - screens[0] = (screen_data) { - .number = 1, - .x = 0, - .y = 0, - .width = default_screen->width, - .height = default_screen->height - }; - } - } - #endif - - return screens; -} - -IOHOOK_API long int hook_get_auto_repeat_rate() { - bool successful = false; - long int value = -1; - unsigned int delay = 0, rate = 0; - - // Check and make sure we could connect to the x server. - if (properties_disp != NULL) { - #ifdef USE_XKB - // Attempt to acquire the keyboard auto repeat rate using the XKB extension. - if (!successful) { - successful = XkbGetAutoRepeatRate(properties_disp, XkbUseCoreKbd, &delay, &rate); - - if (successful) { - logger(LOG_LEVEL_INFO, "%s [%u]: XkbGetAutoRepeatRate: %u.\n", - __FUNCTION__, __LINE__, rate); - } - } - #endif - - #ifdef USE_XF86MISC - // Fallback to the XF86 Misc extension if available and other efforts failed. - if (!successful) { - XF86MiscKbdSettings kb_info; - successful = (bool) XF86MiscGetKbdSettings(properties_disp, &kb_info); - if (successful) { - logger(LOG_LEVEL_INFO, "%s [%u]: XF86MiscGetKbdSettings: %i.\n", - __FUNCTION__, __LINE__, kbdinfo.rate); - - delay = (unsigned int) kbdinfo.delay; - rate = (unsigned int) kbdinfo.rate; - } - } - #endif - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - - if (successful) { - value = (long int) rate; - } - - return value; -} - -IOHOOK_API long int hook_get_auto_repeat_delay() { - bool successful = false; - long int value = -1; - unsigned int delay = 0, rate = 0; - - // Check and make sure we could connect to the x server. - if (properties_disp != NULL) { - #ifdef USE_XKB - // Attempt to acquire the keyboard auto repeat rate using the XKB extension. - if (!successful) { - successful = XkbGetAutoRepeatRate(properties_disp, XkbUseCoreKbd, &delay, &rate); - - if (successful) { - logger(LOG_LEVEL_INFO, "%s [%u]: XkbGetAutoRepeatRate: %u.\n", - __FUNCTION__, __LINE__, delay); - } - } - #endif - - #ifdef USE_XF86MISC - // Fallback to the XF86 Misc extension if available and other efforts failed. - if (!successful) { - XF86MiscKbdSettings kb_info; - successful = (bool) XF86MiscGetKbdSettings(properties_disp, &kb_info); - if (successful) { - logger(LOG_LEVEL_INFO, "%s [%u]: XF86MiscGetKbdSettings: %i.\n", - __FUNCTION__, __LINE__, kbdinfo.delay); - - delay = (unsigned int) kbdinfo.delay; - rate = (unsigned int) kbdinfo.rate; - } - } - #endif - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - - if (successful) { - value = (long int) delay; - } - - return value; -} - -IOHOOK_API long int hook_get_pointer_acceleration_multiplier() { - long int value = -1; - int accel_numerator, accel_denominator, threshold; - - // Check and make sure we could connect to the x server. - if (properties_disp != NULL) { - XGetPointerControl(properties_disp, &accel_numerator, &accel_denominator, &threshold); - if (accel_denominator >= 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: XGetPointerControl: %i.\n", - __FUNCTION__, __LINE__, accel_denominator); - - value = (long int) accel_denominator; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - - return value; -} - -IOHOOK_API long int hook_get_pointer_acceleration_threshold() { - long int value = -1; - int accel_numerator, accel_denominator, threshold; - - // Check and make sure we could connect to the x server. - if (properties_disp != NULL) { - XGetPointerControl(properties_disp, &accel_numerator, &accel_denominator, &threshold); - if (threshold >= 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: XGetPointerControl: %i.\n", - __FUNCTION__, __LINE__, threshold); - - value = (long int) threshold; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - - return value; -} - -IOHOOK_API long int hook_get_pointer_sensitivity() { - long int value = -1; - int accel_numerator, accel_denominator, threshold; - - // Check and make sure we could connect to the x server. - if (properties_disp != NULL) { - XGetPointerControl(properties_disp, &accel_numerator, &accel_denominator, &threshold); - if (accel_numerator >= 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: XGetPointerControl: %i.\n", - __FUNCTION__, __LINE__, accel_numerator); - - value = (long int) accel_numerator; - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - - return value; -} - -IOHOOK_API long int hook_get_multi_click_time() { - long int value = 200; - int click_time; - bool successful = false; - - #ifdef USE_XT - // Check and make sure we could connect to the x server. - if (xt_disp != NULL) { - // Try and use the Xt extention to get the current multi-click. - if (!successful) { - // Fall back to the X Toolkit extension if available and other efforts failed. - click_time = XtGetMultiClickTime(xt_disp); - if (click_time >= 0) { - logger(LOG_LEVEL_INFO, "%s [%u]: XtGetMultiClickTime: %i.\n", - __FUNCTION__, __LINE__, click_time); - - successful = true; - } - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - #endif - - // Check and make sure we could connect to the x server. - if (properties_disp != NULL) { - // Try and acquire the multi-click time from the user defined X defaults. - if (!successful) { - char *xprop = XGetDefault(properties_disp, "*", "multiClickTime"); - if (xprop != NULL && sscanf(xprop, "%4i", &click_time) != EOF) { - logger(LOG_LEVEL_INFO, "%s [%u]: X default 'multiClickTime' property: %i.\n", - __FUNCTION__, __LINE__, click_time); - - successful = true; - } - } - - if (!successful) { - char *xprop = XGetDefault(properties_disp, "OpenWindows", "MultiClickTimeout"); - if (xprop != NULL && sscanf(xprop, "%4i", &click_time) != EOF) { - logger(LOG_LEVEL_INFO, "%s [%u]: X default 'MultiClickTimeout' property: %i.\n", - __FUNCTION__, __LINE__, click_time); - - successful = true; - } - } - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - - if (successful) { - value = (long int) click_time; - } - - return value; -} - -// Create a shared object constructor. -__attribute__ ((constructor)) -void on_library_load() { - // Make sure we are initialized for threading. - XInitThreads(); - - // Open local display. - properties_disp = XOpenDisplay(XDisplayName(NULL)); - if (properties_disp == NULL) { - logger(LOG_LEVEL_ERROR, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay failure!"); - } - else { - logger(LOG_LEVEL_DEBUG, "%s [%u]: %s\n", - __FUNCTION__, __LINE__, "XOpenDisplay success."); - } - - #ifdef USE_XRANDR - // Create the thread attribute. - pthread_attr_t settings_thread_attr; - pthread_attr_init(&settings_thread_attr); - - pthread_t settings_thread_id; - if (pthread_create(&settings_thread_id, &settings_thread_attr, settings_thread_proc, NULL) == 0) { - logger(LOG_LEVEL_DEBUG, "%s [%u]: Successfully created settings thread.\n", - __FUNCTION__, __LINE__); - } - else { - logger(LOG_LEVEL_ERROR, "%s [%u]: Failed to create settings thread!\n", - __FUNCTION__, __LINE__); - } - - // Make sure the thread attribute is removed. - pthread_attr_destroy(&settings_thread_attr); - #endif - - #ifdef USE_XT - XtToolkitInitialize(); - xt_context = XtCreateApplicationContext(); - - int argc = 0; - char ** argv = { NULL }; - xt_disp = XtOpenDisplay(xt_context, NULL, "IOHook", "libIOhook", NULL, 0, &argc, argv); - #endif - - // Initialize. - load_input_helper(properties_disp); -} - -// Create a shared object destructor. -__attribute__ ((destructor)) -void on_library_unload() { - // Disable the event hook. - //hook_stop(); - - // Cleanup. - unload_input_helper(); - - #ifdef USE_XT - XtCloseDisplay(xt_disp); - XtDestroyApplicationContext(xt_context); - #endif - - // Destroy the native displays. - if (properties_disp != NULL) { - XCloseDisplay(properties_disp); - properties_disp = NULL; - } -} diff --git a/robotgo.go b/robotgo.go index dc82a0f..08f67a0 100644 --- a/robotgo.go +++ b/robotgo.go @@ -24,17 +24,14 @@ package robotgo /* //#if defined(IS_MACOSX) - // #cgo darwin CFLAGS: -mmacosx-version-min=10.10 -DMACOSX_DEPLOYMENT_TARGET=10.10 #cgo darwin CFLAGS: -x objective-c -Wno-deprecated-declarations - // #cgo darwin LDFLAGS: -mmacosx-version-min=10.10 #cgo darwin LDFLAGS: -framework Cocoa -framework OpenGL -framework IOKit #cgo darwin LDFLAGS: -framework Carbon -framework CoreFoundation #cgo darwin LDFLAGS:-L${SRCDIR}/cdeps/mac -lpng -lz //#elif defined(USE_X11) // Drop -std=c11 #cgo linux CFLAGS: -I/usr/src - #cgo linux LDFLAGS: -L/usr/src -lpng -lz -lX11 -lXtst -lX11-xcb -lxcb - #cgo linux LDFLAGS: -lxcb-xkb -lxkbcommon -lxkbcommon-x11 -lm + #cgo linux LDFLAGS: -L/usr/src -lpng -lz -lX11 -lXtst -lm //#endif // #cgo windows LDFLAGS: -lgdi32 -luser32 -lpng -lz #cgo windows LDFLAGS: -lgdi32 -luser32 @@ -45,7 +42,7 @@ package robotgo #include "mouse/goMouse.h" #include "key/goKey.h" #include "bitmap/goBitmap.h" -#include "event/goEvent.h" +//#include "event/goEvent.h" #include "window/goWindow.h" */ import "C" @@ -64,6 +61,7 @@ import ( "os/exec" "github.com/go-vgo/robotgo/clipboard" + "github.com/robotn/gohook" "github.com/shirou/gopsutil/process" "github.com/vcaesar/imgo" ) @@ -1247,8 +1245,7 @@ func AddEvent(key string) int { } var ( - cs *C.char - keve string + // cs *C.char mArr = []string{"mleft", "mright", "wheelDown", "wheelUp", "wheelLeft", "wheelRight"} mouseBool bool @@ -1261,24 +1258,18 @@ func AddEvent(key string) int { } if len(key) > 1 && !mouseBool { - keve = keycode[key].(string) - cs = C.CString(keve) - } else { - cs = C.CString(key) + key = keycode[key].(string) } - // cs := C.CString(key) - eve := C.add_event(cs) - // fmt.Println("event@@", eve) - geve := int(eve) - defer C.free(unsafe.Pointer(cs)) + geve := hook.AddEvent(key) + // defer C.free(unsafe.Pointer(cs)) return geve } // StopEvent stop event listener func StopEvent() { - C.stop_event() + hook.StopEvent() } /*