浏览代码

libobs: Use xcb-xinput when available for events

This enables extra mouse buttons to be detected by libobs. This allows
up to 29 extra buttons.
Shaolin 7 年之前
父节点
当前提交
b8e6e7a9fe
共有 4 个文件被更改,包括 216 次插入32 次删除
  1. 19 3
      libobs/CMakeLists.txt
  2. 2 0
      libobs/obs-hotkey.h
  3. 194 29
      libobs/obs-nix.c
  4. 1 0
      libobs/obsconfig.h.in

+ 19 - 3
libobs/CMakeLists.txt

@@ -13,6 +13,13 @@ endif()
 
 
 if(UNIX)
 if(UNIX)
 	if (NOT APPLE)
 	if (NOT APPLE)
+		find_package(X11_XCB REQUIRED)
+		find_package(XCB OPTIONAL_COMPONENTS XINPUT)
+		if (XCB_XINPUT_FOUND)
+			set(USE_XINPUT "1")
+		else()
+			set(USE_XINPUT "0")
+		endif()
 		find_package(PulseAudio)
 		find_package(PulseAudio)
 		if (NOT "${PULSEAUDIO_LIBRARY}" STREQUAL "")
 		if (NOT "${PULSEAUDIO_LIBRARY}" STREQUAL "")
 			message(STATUS "Found PulseAudio - Audio Monitor enabled")
 			message(STATUS "Found PulseAudio - Audio Monitor enabled")
@@ -22,14 +29,13 @@ if(UNIX)
 		endif()
 		endif()
 	else()
 	else()
 		set(HAVE_PULSEAUDIO "0")
 		set(HAVE_PULSEAUDIO "0")
+		set(USE_XINPUT "0")
 	endif()
 	endif()
 	find_package(DBus QUIET)
 	find_package(DBus QUIET)
-	if (NOT APPLE)
-		find_package(X11_XCB REQUIRED)
-	endif()
 else()
 else()
 	set(HAVE_DBUS "0")
 	set(HAVE_DBUS "0")
 	set(HAVE_PULSEAUDIO "0")
 	set(HAVE_PULSEAUDIO "0")
+	set(USE_XINPUT "0")
 endif()
 endif()
 
 
 find_package(ImageMagick QUIET COMPONENTS MagickCore)
 find_package(ImageMagick QUIET COMPONENTS MagickCore)
@@ -199,6 +205,16 @@ elseif(UNIX)
 		${libobs_PLATFORM_DEPS}
 		${libobs_PLATFORM_DEPS}
 		${X11_XCB_LIBRARIES})
 		${X11_XCB_LIBRARIES})
 
 
+	if(USE_XINPUT)
+		include_directories(
+			${XCB_XINPUT_INCLUDE_DIR})
+		add_definitions(
+			${XCB_DEFINITIONS})
+		set(libobs_PLATFORM_DEPS
+			${XCB_XINPUT_LIBRARY}
+			${libobs_PLATFORM_DEPS})
+	endif()
+
 	if(HAVE_PULSEAUDIO)
 	if(HAVE_PULSEAUDIO)
 		set(libobs_PLATFORM_DEPS
 		set(libobs_PLATFORM_DEPS
 			${libobs_PLATFORM_DEPS}
 			${libobs_PLATFORM_DEPS}

+ 2 - 0
libobs/obs-hotkey.h

@@ -32,6 +32,8 @@ const size_t OBS_INVALID_HOTKEY_ID = (size_t)-1;
 const size_t OBS_INVALID_HOTKEY_PAIR_ID = (size_t)-1;
 const size_t OBS_INVALID_HOTKEY_PAIR_ID = (size_t)-1;
 #endif
 #endif
 
 
+#define XINPUT_MOUSE_LEN 33
+
 enum obs_key {
 enum obs_key {
 #define OBS_HOTKEY(x) x,
 #define OBS_HOTKEY(x) x,
 #include "obs-hotkeys.h"
 #include "obs-hotkeys.h"

+ 194 - 29
libobs/obs-nix.c

@@ -16,6 +16,7 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
 ******************************************************************************/
 
 
+#include "obs-internal.h"
 #if defined(__FreeBSD__)
 #if defined(__FreeBSD__)
 #define _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 #endif
@@ -28,13 +29,13 @@
 #include <sys/sysinfo.h>
 #include <sys/sysinfo.h>
 #include <sys/utsname.h>
 #include <sys/utsname.h>
 #include <xcb/xcb.h>
 #include <xcb/xcb.h>
+#if USE_XINPUT
+#include <xcb/xinput.h>
+#endif
 #include <X11/Xlib.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xutil.h>
 #include <X11/Xlib-xcb.h>
 #include <X11/Xlib-xcb.h>
-#include <X11/keysym.h>
 #include <inttypes.h>
 #include <inttypes.h>
-#include "util/dstr.h"
-#include "obs-internal.h"
 
 
 const char *get_module_extension(void)
 const char *get_module_extension(void)
 {
 {
@@ -356,6 +357,12 @@ struct obs_hotkeys_platform {
 	xcb_keysym_t *keysyms;
 	xcb_keysym_t *keysyms;
 	int num_keysyms;
 	int num_keysyms;
 	int syms_per_code;
 	int syms_per_code;
+
+#if USE_XINPUT
+	bool pressed[XINPUT_MOUSE_LEN];
+	bool update[XINPUT_MOUSE_LEN];
+	bool button_pressed[XINPUT_MOUSE_LEN];
+#endif
 };
 };
 
 
 #define MOUSE_1 (1<<16)
 #define MOUSE_1 (1<<16)
@@ -736,6 +743,54 @@ error1:
 	return error != NULL || reply == NULL;
 	return error != NULL || reply == NULL;
 }
 }
 
 
+static xcb_screen_t *default_screen(obs_hotkeys_platform_t *context,
+		xcb_connection_t *connection)
+{
+	int def_screen_idx = XDefaultScreen(context->display);
+	xcb_screen_iterator_t iter;
+
+	iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
+	while (iter.rem) {
+		if (def_screen_idx-- == 0)
+			return iter.data;
+
+		xcb_screen_next(&iter);
+	}
+
+	return NULL;
+}
+
+static inline xcb_window_t root_window(obs_hotkeys_platform_t *context,
+		xcb_connection_t *connection)
+{
+	xcb_screen_t *screen = default_screen(context, connection);
+	if (screen)
+		return screen->root;
+	return 0;
+}
+
+#if USE_XINPUT
+static inline void registerMouseEvents(struct obs_core_hotkeys *hotkeys)
+{
+	obs_hotkeys_platform_t *context    = hotkeys->platform_context;
+	xcb_connection_t       *connection = XGetXCBConnection(
+			context->display);
+	xcb_window_t           window      = root_window(context, connection);
+
+	struct {
+		xcb_input_event_mask_t    head;
+		xcb_input_xi_event_mask_t mask;
+	} mask;
+	mask.head.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
+	mask.head.mask_len = sizeof(mask.mask) / sizeof(uint32_t);
+	mask.mask          = XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS |
+			XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE;
+
+	xcb_input_xi_select_events(connection, window, 1, &mask.head);
+	xcb_flush(connection);
+}
+#endif
+
 bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
 bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
 {
 {
 	Display *display = XOpenDisplay(NULL);
 	Display *display = XOpenDisplay(NULL);
@@ -745,6 +800,9 @@ bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
 	hotkeys->platform_context = bzalloc(sizeof(obs_hotkeys_platform_t));
 	hotkeys->platform_context = bzalloc(sizeof(obs_hotkeys_platform_t));
 	hotkeys->platform_context->display = display;
 	hotkeys->platform_context->display = display;
 
 
+#if USE_XINPUT
+	registerMouseEvents(hotkeys);
+#endif
 	fill_base_keysyms(hotkeys);
 	fill_base_keysyms(hotkeys);
 	fill_keycodes(hotkeys);
 	fill_keycodes(hotkeys);
 	return true;
 	return true;
@@ -764,41 +822,147 @@ void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
 	hotkeys->platform_context = NULL;
 	hotkeys->platform_context = NULL;
 }
 }
 
 
-static xcb_screen_t *default_screen(obs_hotkeys_platform_t *context,
-		xcb_connection_t *connection)
+static bool mouse_button_pressed(xcb_connection_t *connection,
+		obs_hotkeys_platform_t *context, obs_key_t key)
 {
 {
-	int def_screen_idx = XDefaultScreen(context->display);
-	xcb_screen_iterator_t iter;
+	bool ret = false;
 
 
-	iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
-	while (iter.rem) {
-		if (def_screen_idx-- == 0) {
-			return iter.data;
-			break;
+#if USE_XINPUT
+	memset(context->pressed, 0, XINPUT_MOUSE_LEN);
+	memset(context->update, 0, XINPUT_MOUSE_LEN);
+
+	xcb_generic_event_t *ev;
+	while ((ev = xcb_poll_for_event(connection))) {
+		if ((ev->response_type & ~80) == XCB_GE_GENERIC) {
+			switch (((xcb_ge_event_t *) ev)->event_type) {
+			case XCB_INPUT_RAW_BUTTON_PRESS: {
+				xcb_input_raw_button_press_event_t *mot;
+				mot = (xcb_input_raw_button_press_event_t *) ev;
+				if (mot->detail < XINPUT_MOUSE_LEN) {
+					context->pressed[mot->detail-1] = true;
+					context->update[mot->detail-1]  = true;
+				} else {
+					blog(LOG_WARNING, "Unsupported button");
+				}
+				break;
+			}
+			case XCB_INPUT_RAW_BUTTON_RELEASE: {
+				xcb_input_raw_button_release_event_t *mot;
+				mot = (xcb_input_raw_button_release_event_t *) ev;
+				if (mot->detail < XINPUT_MOUSE_LEN)
+					context->update[mot->detail-1]  = true;
+				else
+					blog(LOG_WARNING, "Unsupported button");
+				break;
+			}
+			default:
+				break;
+			}
 		}
 		}
-
-		xcb_screen_next(&iter);
+		free(ev);
 	}
 	}
 
 
-	return NULL;
-}
-
-static inline xcb_window_t root_window(obs_hotkeys_platform_t *context,
-		xcb_connection_t *connection)
-{
-	xcb_screen_t *screen = default_screen(context, connection);
-	if (screen)
-		return screen->root;
-	return 0;
-}
+	// Mouse 2 for OBS is Right Click and Mouse 3 is Wheel Click.
+	// Mouse Wheel axis clicks (xinput mot->detail 4 5 6 7) are ignored.
+	switch (key) {
+	case OBS_KEY_MOUSE1:
+		ret = context->pressed[0] || context->button_pressed[0];
+		break;
+	case OBS_KEY_MOUSE2:
+		ret = context->pressed[2] || context->button_pressed[2];
+		break;
+	case OBS_KEY_MOUSE3:
+		ret = context->pressed[1] || context->button_pressed[1];
+		break;
+	case OBS_KEY_MOUSE4:
+		ret = context->pressed[7] || context->button_pressed[7];
+		break;
+	case OBS_KEY_MOUSE5:
+		ret = context->pressed[8] || context->button_pressed[8];
+		break;
+	case OBS_KEY_MOUSE6:
+		ret = context->pressed[9] || context->button_pressed[9];
+		break;
+	case OBS_KEY_MOUSE7:
+		ret = context->pressed[10] || context->button_pressed[10];
+		break;
+	case OBS_KEY_MOUSE8:
+		ret = context->pressed[11] || context->button_pressed[11];
+		break;
+	case OBS_KEY_MOUSE9:
+		ret = context->pressed[12] || context->button_pressed[12];
+		break;
+	case OBS_KEY_MOUSE10:
+		ret = context->pressed[13] || context->button_pressed[13];
+		break;
+	case OBS_KEY_MOUSE11:
+		ret = context->pressed[14] || context->button_pressed[14];
+		break;
+	case OBS_KEY_MOUSE12:
+		ret = context->pressed[15] || context->button_pressed[15];
+		break;
+	case OBS_KEY_MOUSE13:
+		ret = context->pressed[16] || context->button_pressed[16];
+		break;
+	case OBS_KEY_MOUSE14:
+		ret = context->pressed[17] || context->button_pressed[17];
+		break;
+	case OBS_KEY_MOUSE15:
+		ret = context->pressed[18] || context->button_pressed[18];
+		break;
+	case OBS_KEY_MOUSE16:
+		ret = context->pressed[19] || context->button_pressed[19];
+		break;
+	case OBS_KEY_MOUSE17:
+		ret = context->pressed[20] || context->button_pressed[20];
+		break;
+	case OBS_KEY_MOUSE18:
+		ret = context->pressed[21] || context->button_pressed[21];
+		break;
+	case OBS_KEY_MOUSE19:
+		ret = context->pressed[22] || context->button_pressed[22];
+		break;
+	case OBS_KEY_MOUSE20:
+		ret = context->pressed[23] || context->button_pressed[23];
+		break;
+	case OBS_KEY_MOUSE21:
+		ret = context->pressed[24] || context->button_pressed[24];
+		break;
+	case OBS_KEY_MOUSE22:
+		ret = context->pressed[25] || context->button_pressed[25];
+		break;
+	case OBS_KEY_MOUSE23:
+		ret = context->pressed[26] || context->button_pressed[26];
+		break;
+	case OBS_KEY_MOUSE24:
+		ret = context->pressed[27] || context->button_pressed[27];
+		break;
+	case OBS_KEY_MOUSE25:
+		ret = context->pressed[28] || context->button_pressed[28];
+		break;
+	case OBS_KEY_MOUSE26:
+		ret = context->pressed[29] || context->button_pressed[29];
+		break;
+	case OBS_KEY_MOUSE27:
+		ret = context->pressed[30] || context->button_pressed[30];
+		break;
+	case OBS_KEY_MOUSE28:
+		ret = context->pressed[31] || context->button_pressed[31];
+		break;
+	case OBS_KEY_MOUSE29:
+		ret = context->pressed[32] || context->button_pressed[32];
+		break;
+	default:
+		break;
+	}
 
 
-static bool mouse_button_pressed(xcb_connection_t *connection,
-		obs_hotkeys_platform_t *context, obs_key_t key)
-{
+	for (int i = 0; i != XINPUT_MOUSE_LEN; i++)
+		if (context->update[i])
+			context->button_pressed[i] = context->pressed[i];
+#else
 	xcb_generic_error_t *error = NULL;
 	xcb_generic_error_t *error = NULL;
 	xcb_query_pointer_cookie_t qpc;
 	xcb_query_pointer_cookie_t qpc;
 	xcb_query_pointer_reply_t *reply;
 	xcb_query_pointer_reply_t *reply;
-	bool ret = false;
 
 
 	qpc = xcb_query_pointer(connection, root_window(context, connection));
 	qpc = xcb_query_pointer(connection, root_window(context, connection));
 	reply = xcb_query_pointer_reply(connection, qpc, &error);
 	reply = xcb_query_pointer_reply(connection, qpc, &error);
@@ -818,6 +982,7 @@ static bool mouse_button_pressed(xcb_connection_t *connection,
 
 
 	free(reply);
 	free(reply);
 	free(error);
 	free(error);
+#endif
 	return ret;
 	return ret;
 }
 }
 
 

+ 1 - 0
libobs/obsconfig.h.in

@@ -18,6 +18,7 @@
 #define BUILD_CAPTIONS @BUILD_CAPTIONS@
 #define BUILD_CAPTIONS @BUILD_CAPTIONS@
 #define HAVE_DBUS @HAVE_DBUS@
 #define HAVE_DBUS @HAVE_DBUS@
 #define HAVE_PULSEAUDIO @HAVE_PULSEAUDIO@
 #define HAVE_PULSEAUDIO @HAVE_PULSEAUDIO@
+#define USE_XINPUT @USE_XINPUT@
 #define LIBOBS_IMAGEMAGICK_DIR_STYLE_6L 6
 #define LIBOBS_IMAGEMAGICK_DIR_STYLE_6L 6
 #define LIBOBS_IMAGEMAGICK_DIR_STYLE_7GE 7
 #define LIBOBS_IMAGEMAGICK_DIR_STYLE_7GE 7
 #define LIBOBS_IMAGEMAGICK_DIR_STYLE @LIBOBS_IMAGEMAGICK_DIR_STYLE@
 #define LIBOBS_IMAGEMAGICK_DIR_STYLE @LIBOBS_IMAGEMAGICK_DIR_STYLE@