void on_library_load() {
	// Display the copyright on library load.
	COPYRIGHT();

	// Initialize Native Input Functions.
	load_input_helper();
}
Esempio n. 2
0
void on_library_load() {
	// Initialize Native Input Functions.
	load_input_helper();
}
Esempio n. 3
0
static void *hook_thread_proc(void *arg) {
	int *status = (int *) arg;
	*status = UIOHOOK_FAILURE;

	bool accessibilityEnabled = false;

	// FIXME Move to osx_input_helper.h after testing.
	#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);

		accessibilityEnabled = AXIsProcessTrustedWithOptions(options);
	}
	else {
		// Old accessibility check 10.8 and older.
		accessibilityEnabled = AXAPIEnabled();
	}
	#else
	// Dynamically load the application services framework for examination.
	const char *dlError = NULL;
	void *libApplicaitonServices = dlopen("/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices", RTLD_LAZY);
	dlError = dlerror();
	if (libApplicaitonServices != NULL && dlError == NULL) {
		// Check for the new function AXIsProcessTrustedWithOptions().
		*(void **) (&AXIsProcessTrustedWithOptions_t) = dlsym(libApplicaitonServices, "AXIsProcessTrustedWithOptions");
		dlError = dlerror();
		if (AXIsProcessTrustedWithOptions_t != NULL && dlError == NULL) {
			// Check for property kAXTrustedCheckOptionPrompt
			CFStringRef kAXTrustedCheckOptionPrompt_t = (CFStringRef) dlsym(libApplicaitonServices, "kAXTrustedCheckOptionPrompt");
			dlError = dlerror();
			if (kAXTrustedCheckOptionPrompt_t != NULL && dlError == NULL) {
				// New accessibility API 10.9 and later.
				// FIXME This is causing a segfault on 10.9 probably due to an invalid pointer type.
				const void * keys[] = { kAXTrustedCheckOptionPrompt_t };
				const void * values[] = { kCFBooleanTrue };

				CFDictionaryRef options = CFDictionaryCreate(
						kCFAllocatorDefault,
						keys,
						values,
						sizeof(keys) / sizeof(*keys),
						&kCFCopyStringDictionaryKeyCallBacks,
						&kCFTypeDictionaryValueCallBacks);

				accessibilityEnabled = (*AXIsProcessTrustedWithOptions_t)(options);
			}
		}
		else {
			logger(LOG_LEVEL_DEBUG,	"%s [%u]: Falling back to AXAPIEnabled(). (%s)\n",
					__FUNCTION__, __LINE__, dlError);

			// Check for the fallback function AXAPIEnabled().
			*(void **) (&AXAPIEnabled_t) = dlsym(libApplicaitonServices, "AXAPIEnabled");
			dlError = dlerror();
			if (AXAPIEnabled_t != NULL && dlError == NULL) {
				// Old accessibility check 10.8 and older.
				accessibilityEnabled = (*AXAPIEnabled_t)();
			}
			else {
				// Could not load the AXAPIEnabled function!
				logger(LOG_LEVEL_ERROR,	"%s [%u]: Failed to locate AXAPIEnabled()! (%s)\n",
						__FUNCTION__, __LINE__, dlError);
			}
		}

		dlclose(libApplicaitonServices);
	}
	else {
		// Could not load the ApplicationServices framework!
		logger(LOG_LEVEL_ERROR,	"%s [%u]: Failed to lazy load the ApplicationServices framework! (%s)\n",
				__FUNCTION__, __LINE__, dlError);
	}
	#endif

	if (accessibilityEnabled == true) {
		logger(LOG_LEVEL_DEBUG,	"%s [%u]: Accessibility API is enabled.\n",
				__FUNCTION__, __LINE__);

		// Setup the event mask to listen for.
		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);

		#ifdef USE_DEBUG
		event_mask |= CGEventMaskBit(kCGEventNull);
		#endif

		CFMachPortRef event_port = CGEventTapCreate(
										kCGSessionEventTap,				// kCGHIDEventTap
										kCGHeadInsertEventTap,			// kCGTailAppendEventTap
										kCGEventTapOptionListenOnly,	// kCGEventTapOptionDefault See Bug #22
										event_mask,
										hook_event_proc,
										NULL
									);


		if (event_port != NULL) {
			logger(LOG_LEVEL_DEBUG,	"%s [%u]: CGEventTapCreate Successful.\n",
					__FUNCTION__, __LINE__);

			event_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, event_port, 0);
			if (event_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__);

					// Initialize Native Input Functions.
					load_input_helper();


					// Create run loop observers.
					CFRunLoopObserverRef observer = CFRunLoopObserverCreate(
														kCFAllocatorDefault,
														kCFRunLoopEntry | kCFRunLoopExit, //kCFRunLoopAllActivities,
														true,
														0,
														hook_status_proc,
														NULL
													);

					if (observer != NULL) {
						// Set the exit status.
						*status = UIOHOOK_SUCCESS;

						start_message_port_runloop();

						CFRunLoopAddSource(event_loop, event_source, kCFRunLoopDefaultMode);
						CFRunLoopAddObserver(event_loop, observer, kCFRunLoopDefaultMode);

						CFRunLoopRun();

						// Lock back up until we are done processing the exit.
						CFRunLoopRemoveObserver(event_loop, observer, kCFRunLoopDefaultMode);
						CFRunLoopRemoveSource(event_loop, event_source, kCFRunLoopDefaultMode);
						CFRunLoopObserverInvalidate(observer);

						stop_message_port_runloop();
					}
					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 = UIOHOOK_ERROR_OBSERVER_CREATE;
					}

					// Cleanup Native Input Functions.
					unload_input_helper();
				}
				else {
					logger(LOG_LEVEL_ERROR,	"%s [%u]: CFRunLoopGetCurrent failure!\n",
							__FUNCTION__, __LINE__);

					// Set the exit status.
					*status = UIOHOOK_ERROR_GET_RUNLOOP;
				}

				// Clean up the event source.
				CFRelease(event_source);
			}
			else {
				logger(LOG_LEVEL_ERROR,	"%s [%u]: CFMachPortCreateRunLoopSource failure!\n",
					__FUNCTION__, __LINE__);

				// Set the exit status.
				*status = UIOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE;
			}

			// Stop the CFMachPort from receiving any more messages.
			CFMachPortInvalidate(event_port);
			CFRelease(event_port);
		}
		else {
			logger(LOG_LEVEL_ERROR,	"%s [%u]: Failed to create event port!\n",
					__FUNCTION__, __LINE__);

			// Set the exit status.
			*status = UIOHOOK_ERROR_EVENT_PORT;
		}
	}
	else {
		logger(LOG_LEVEL_ERROR,	"%s [%u]: Accessibility API is disabled!\n",
				__FUNCTION__, __LINE__);

		// Set the exit status.
		*status = UIOHOOK_ERROR_AXAPI_DISABLED;
	}

	logger(LOG_LEVEL_DEBUG,	"%s [%u]: Something, something, something, complete.\n",
			__FUNCTION__, __LINE__);

	// Make sure we signal that we have passed any exception throwing code.
	pthread_mutex_unlock(&hook_control_mutex);

	pthread_exit(status);
}
Esempio n. 4
0
UIOHOOK_API int hook_run() {
	int status = UIOHOOK_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 = UIOHOOK_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 = UIOHOOK_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 = UIOHOOK_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;
}