コード例 #1
0
ファイル: demo_properties.c プロジェクト: Nimgoble/libuiohook
int main() {
	// Disable the logger.
	hook_set_logger_proc(&logger_proc);

	// Retrieves an array of screen data for each available monitor.
	uint8_t count = 0;
	screen_data *screens = hook_create_screen_info(&count);
	if (screens != NULL) {
		fprintf(stdout,	"Found %d Monitors:\n", count);

		for (int i = 0; i < count; i++) {
			fprintf(stdout,	"\tNumber:\t\t%d\n", screens[i].number);
			fprintf(stdout,	"\tOffset X:\t%d\n", screens[i].x);
			fprintf(stdout,	"\tOffset Y:\t%d\n", screens[i].y);
			fprintf(stdout,	"\tWidth:\t\t%d\n", screens[i].width);
			fprintf(stdout,	"\tHeight:\t\t%d\n", screens[i].height);
			fprintf(stdout,	"\n");
		}

		// You are responsible for freeing the memory returned by hook_create_screen_info.
		free(screens);
	}
	else {
		fprintf(stderr,	"Failed to aquire screen information!\n");
	}

	// Retrieves the keyboard auto repeat rate.
	long int repeat_rate = hook_get_auto_repeat_rate();
	if (repeat_rate >= 0) {
		fprintf(stdout,	"Auto Repeat Rate:\t%ld\n", repeat_rate);
	}
	else {
		fprintf(stderr,	"Failed to aquire keyboard auto repeat rate!\n");
	}

	// Retrieves the keyboard auto repeat delay.
	long int repeat_delay = hook_get_auto_repeat_delay();
	if (repeat_delay >= 0) {
		fprintf(stdout,	"Auto Repeat Delay:\t%ld\n", repeat_delay);
	}
	else {
		fprintf(stderr,	"Failed to aquire keyboard auto repeat delay!\n");
	}

	// Retrieves the mouse acceleration multiplier.
	long int acceleration_multiplier = hook_get_pointer_acceleration_multiplier();
	if (acceleration_multiplier >= 0) {
		fprintf(stdout,	"Mouse Acceleration Multiplier:\t%ld\n", acceleration_multiplier);
	}
	else {
		fprintf(stderr,	"Failed to aquire mouse acceleration multiplier!\n");
	}

	// Retrieves the mouse acceleration threshold.
	long int acceleration_threshold = hook_get_pointer_acceleration_threshold();
	if (acceleration_threshold >= 0) {
		fprintf(stdout,	"Mouse Acceleration Threshold:\t%ld\n", acceleration_threshold);
	}
	else {
		fprintf(stderr,	"Failed to aquire mouse acceleration threshold!\n");
	}

	// Retrieves the mouse sensitivity.
	long int sensitivity = hook_get_pointer_sensitivity();
	if (sensitivity >= 0) {
		fprintf(stdout,	"Mouse Sensitivity:\t%ld\n", sensitivity);
	}
	else {
		fprintf(stderr,	"Failed to aquire keyboard auto repeat rate!\n");
	}

	// Retrieves the double/triple click interval.
	long int click_time = hook_get_multi_click_time();
	if (click_time >= 0) {
		fprintf(stdout,	"Multi-Click Time:\t%ld\n", click_time);
	}
	else {
		fprintf(stderr,	"Failed to aquire keyboard auto repeat rate!\n");
	}

	return EXIT_SUCCESS;
}
コード例 #2
0
UIOHOOK_API void hook_post_event(uiohook_event * const event) {
	#ifdef USE_XTEST
	// XTest does not have modifier support, so we fake it by depressing the
	// appropriate modifier keys.
	for (unsigned int i = 0; i < sizeof(keymask_lookup) / sizeof(KeySym); i++) {
		if (event->mask & 1 << i) {
			XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, keymask_lookup[i]), True, 0);
		}
	}

	for (unsigned int i = 0; i < sizeof(btnmask_lookup) / sizeof(unsigned int); i++) {
		if (event->mask & btnmask_lookup[i]) {
			XTestFakeButtonEvent(disp, i + 1, True, 0);
		}
	}

	switch (event->type) {
		case EVENT_KEY_PRESSED:
			XTestFakeKeyEvent(
				disp,
				scancode_to_keycode(event->data.keyboard.keycode),
				True,
				0);
			break;

		case EVENT_KEY_RELEASED:
			XTestFakeKeyEvent(
				disp,
				scancode_to_keycode(event->data.keyboard.keycode),
				False,
				0);
			break;


		case EVENT_MOUSE_PRESSED:
			XTestFakeButtonEvent(disp, event->data.mouse.button, True, 0);
			break;

		case EVENT_MOUSE_RELEASED:
			XTestFakeButtonEvent(disp, event->data.mouse.button, False, 0);
			break;

		case 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(disp, WheelUp, True, 0);
				XTestFakeButtonEvent(disp, WheelUp, False, 0);
			}
			else {
				XTestFakeButtonEvent(disp, WheelDown, True, 0);
				XTestFakeButtonEvent(disp, WheelDown, False, 0);
			}
			break;


		case EVENT_MOUSE_DRAGGED:
			// The button masks are all applied with the modifier masks.

		case EVENT_MOUSE_MOVED:
			XTestFakeMotionEvent(disp, -1, event->data.mouse.x, event->data.mouse.y, 0);
			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.
	for (unsigned int i = 0; i < sizeof(keymask_lookup) / sizeof(KeySym); i++) {
		if (event->mask & 1 << i) {
			XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, keymask_lookup[i]), False, 0);
		}
	}

	for (unsigned int i = 0; i < sizeof(btnmask_lookup) / sizeof(unsigned int); i++) {
		if (event->mask & btnmask_lookup[i]) {
			XTestFakeButtonEvent(disp, i + 1, False, 0);
		}
	}
	#else
	XEvent *x_event;

	#if defined(USE_XINERAMA) || defined(USE_XRANDR)
	uint8_t screen_count;
	screen_data *screens;
	#endif

	switch (event->type) {
		case EVENT_KEY_PRESSED:
		case EVENT_KEY_RELEASED:
			// Allocate memory for XKeyEvent and pre-populate.
			x_event = (XEvent *) create_key_event();

			((XKeyEvent *) x_event)->state = convert_to_native_mask(event->mask);
			((XKeyEvent *) x_event)->keycode = XKeysymToKeycode(disp, scancode_to_keycode(event->data.keyboard.keycode));

			if (event->type == EVENT_KEY_PRESSED) {
				((XKeyEvent *) x_event)->type = KeyPress;
				XSendEvent(disp, InputFocus, False, KeyPressMask, x_event);
			}
			else {
				((XKeyEvent *) x_event)->type = KeyRelease;
				XSendEvent(disp, InputFocus, False, KeyReleaseMask, x_event);
			}

			free(x_event);
			break;


		case EVENT_MOUSE_PRESSED:
		case EVENT_MOUSE_RELEASED:
		case EVENT_MOUSE_WHEEL:
			// Allocate memory for XButtonEvent and pre-populate.
			x_event = (XEvent *) create_button_event();

			((XButtonEvent *) x_event)->state = convert_to_native_mask(event->mask);

			((XButtonEvent *) x_event)->x = event->data.mouse.x;
			((XButtonEvent *) x_event)->y = event->data.mouse.y;

			#if defined(USE_XINERAMA) || defined(USE_XRANDR)
			screens = hook_create_screen_info(&screen_count);
			if (screen_count > 1) {
				((XButtonEvent *) x_event)->x += screens[0].x;
				((XButtonEvent *) x_event)->y += screens[0].y;
			}

			if (screens != NULL) {
				free(screens);
			}
			#endif

			// These are the same because Window == Root Window.
			((XButtonEvent *) x_event)->x_root = ((XButtonEvent *) x_event)->x;
			((XButtonEvent *) x_event)->y_root = ((XButtonEvent *) x_event)->y;

			if (event->type == EVENT_MOUSE_WHEEL) {
				((XButtonEvent *) x_event)->type = ButtonPress;

				// type, amount and rotation
				if (event->data.wheel.rotation < 0) {
					((XButtonEvent *) x_event)->button = WheelUp;
				}
				else {
					((XButtonEvent *) x_event)->button = WheelDown;
				}
				XSendEvent(disp, InputFocus, False, ButtonPressMask, x_event);
			}

			if (event->type == EVENT_KEY_PRESSED) {
				((XButtonEvent *) x_event)->type = ButtonPress;
				XSendEvent(disp, InputFocus, False, ButtonPressMask, x_event);
			}
			else {
				((XButtonEvent *) x_event)->type = ButtonRelease;
				XSendEvent(disp, InputFocus, False, ButtonReleaseMask, x_event);
			}

			free(x_event);
			break;

		case EVENT_MOUSE_MOVED:
		case EVENT_MOUSE_DRAGGED:
			x_event = (XEvent *) create_motion_event();

			((XMotionEvent *) x_event)->state = convert_to_native_mask(event->mask);

			((XButtonEvent *) x_event)->x = event->data.mouse.x;
			((XButtonEvent *) x_event)->y = event->data.mouse.y;

			#if defined(USE_XINERAMA) || defined(USE_XRANDR)
			screens = hook_create_screen_info(&screen_count);
			if (screen_count > 1) {
				((XButtonEvent *) x_event)->x += screens[0].x;
				((XButtonEvent *) x_event)->y += screens[0].y;
			}

			if (screens != NULL) {
				free(screens);
			}
			#endif

			// These are the same because Window == Root Window.
			((XButtonEvent *) x_event)->x_root = ((XButtonEvent *) x_event)->x;
			((XButtonEvent *) x_event)->y_root = ((XButtonEvent *) x_event)->y;

			long int x_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.
				x_mask = ((XMotionEvent *) x_event)->state &
						(Button1MotionMask | Button2MotionMask |
						Button2MotionMask | Button3MotionMask | Button5MotionMask);
				#else
				// Fallback to some slightly larger...
				if (((XMotionEvent *) x_event)->state & Button1Mask) {
					x_mask |= Button1MotionMask;
				}

				if (((XMotionEvent *) x_event)->state & Button2Mask) {
					x_mask |= Button2MotionMask;
				}

				if (((XMotionEvent *) x_event)->state & Button3Mask) {
					x_mask |= Button3MotionMask;
				}

				if (((XMotionEvent *) x_event)->state & Button4Mask) {
					x_mask |= Button4MotionMask;
				}

				if (((XMotionEvent *) x_event)->state & Button5Mask) {
					x_mask |= Button5MotionMask;
				}
				#endif
			}

			// NOTE x_mask = NoEventMask.
			XSendEvent(disp, InputFocus, False, x_mask, x_event);
			free(x_event);
			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;
	}


	#endif

	// Don't forget to flush!
	XFlush(disp);
}
コード例 #3
0
static inline void post_mouse_motion_event(uiohook_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
}
コード例 #4
0
ファイル: input_hook.c プロジェクト: kwhat/libuiohook
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

				for (unsigned int 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 {
コード例 #5
0
static inline void post_mouse_button_event(uiohook_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
}