[PATCH libinput 14/24] tablet: handle button events

Carlos Garnacho carlosg at gnome.org
Mon Apr 21 10:11:23 PDT 2014


This works for stylus tap and primary/secondary button, and pad
buttons.

Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
---
 src/evdev-tablet.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/evdev-tablet.h |   3 ++
 2 files changed, 107 insertions(+)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index fcd3396..0682563 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -30,6 +30,11 @@
 #define tablet_unset_status(tablet,s) (tablet->status &= ~(s));
 #define tablet_has_status(tablet,s) (!!(tablet->status & s))
 
+#define tablet_get_enabled_buttons(tablet,field) \
+	(tablet->state.field & ~(tablet->prev_state.field))
+#define tablet_get_disabled_buttons(tablet,field) \
+	(tablet->prev_state.field & ~(tablet->state.field))
+
 static void
 tablet_process_absolute(struct tablet_dispatch *tablet,
 			struct evdev_device *device,
@@ -68,6 +73,31 @@ tablet_update_tool(struct tablet_dispatch *tablet,
 }
 
 static void
+tablet_update_button(struct tablet_dispatch *tablet,
+		     uint32_t evcode,
+		     uint32_t enable)
+{
+	uint32_t button, *flags;
+
+	/* XXX: This really depends on the expected buttons fitting in the mask */
+	if (evcode >= BTN_MISC && evcode <= BTN_TASK) {
+		flags = &tablet->state.pad_buttons;
+		button = evcode - BTN_MISC;
+	} else if (evcode >= BTN_TOUCH && evcode <= BTN_STYLUS2) {
+		flags = &tablet->state.stylus_buttons;
+		button = evcode - BTN_TOUCH;
+	} else {
+		log_info("Unhandled button 0x%x\n", evcode);
+		return;
+	}
+
+	if (enable)
+		(*flags) |= 1 << button;
+	else
+		(*flags) &= ~(1 << button);
+}
+
+static void
 tablet_process_key(struct tablet_dispatch *tablet,
 		   struct evdev_device *device,
 		   struct input_event *e,
@@ -85,7 +115,18 @@ tablet_process_key(struct tablet_dispatch *tablet,
 		/* These codes have an equivalent libinput_tool value */
 		tablet_update_tool(tablet, e->code, e->value);
 		break;
+	case BTN_TOUCH:
+		if (e->value) {
+			tablet_set_status(tablet, TABLET_HAS_CONTACT);
+		} else {
+			tablet_unset_status(tablet, TABLET_HAS_CONTACT);
+		}
+
+		/* Fall through */
+	case BTN_STYLUS:
+	case BTN_STYLUS2:
 	default:
+		tablet_update_button(tablet, e->code, e->value);
 		break;
 	}
 }
@@ -131,6 +172,67 @@ tablet_check_notify_tool(struct tablet_dispatch *tablet,
 }
 
 static void
+tablet_notify_button_mask(struct tablet_dispatch *tablet,
+			  struct evdev_device *device,
+			  uint32_t time,
+			  uint32_t buttons,
+			  uint32_t button_base,
+			  enum libinput_pointer_button_state state)
+{
+	struct libinput_device *base = &device->base;
+	int32_t num_button = 0;
+
+	while (buttons) {
+		int enabled;
+
+		num_button++;
+		enabled = (buttons & 1);
+		buttons >>= 1;
+
+		if (!enabled)
+			continue;
+
+		pointer_notify_button(base,
+				      time,
+				      num_button + button_base - 1,
+				      state);
+	}
+}
+
+static void
+tablet_notify_buttons(struct tablet_dispatch *tablet,
+		      struct evdev_device *device,
+		      uint32_t time,
+		      uint32_t post_check)
+{
+	enum libinput_pointer_button_state state;
+	int32_t pad_buttons, stylus_buttons;
+
+	if (tablet->state.pad_buttons == tablet->prev_state.pad_buttons &&
+	    tablet->state.stylus_buttons == tablet->prev_state.stylus_buttons)
+		return;
+
+	if (post_check) {
+		/* Only notify button releases */
+		state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED;
+		pad_buttons = tablet_get_disabled_buttons(tablet, pad_buttons);
+		stylus_buttons =
+			tablet_get_disabled_buttons(tablet, stylus_buttons);
+	} else {
+		/* Only notify button presses */
+		state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED;
+		pad_buttons = tablet_get_enabled_buttons(tablet, pad_buttons);
+		stylus_buttons =
+			tablet_get_enabled_buttons(tablet, stylus_buttons);
+	}
+
+	tablet_notify_button_mask(
+		tablet, device, time, pad_buttons, BTN_MISC, state);
+	tablet_notify_button_mask(
+		tablet, device, time, stylus_buttons, BTN_TOUCH, state);
+}
+
+static void
 tablet_flush(struct tablet_dispatch *tablet,
 	     struct evdev_device *device,
 	     uint32_t time)
@@ -140,6 +242,7 @@ tablet_flush(struct tablet_dispatch *tablet,
 
 	/* pre-update notifications */
 	tablet_check_notify_tool(tablet, device, time, 0);
+	tablet_notify_buttons(tablet, device, time, 0);
 
 	if (tablet->state.tool != LIBINPUT_TOOL_NONE) {
 		if (tablet_has_status(tablet, TABLET_UPDATED)) {
@@ -153,6 +256,7 @@ tablet_flush(struct tablet_dispatch *tablet,
 	}
 
 	/* post-update notifications */
+	tablet_notify_buttons(tablet, device, time, 1);
 	tablet_check_notify_tool(tablet, device, time, 1);
 
 	/* replace previous state */
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 7b7b066..d81c878 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -30,9 +30,12 @@ enum tablet_status {
 	TABLET_NONE = 0,
 	TABLET_UPDATED = 1 << 0,
 	TABLET_INTERACTED = 1 << 1,
+	TABLET_HAS_CONTACT = 1 << 2,
 };
 
 struct device_state {
+	uint32_t pad_buttons; /* bitmask of evcode - BTN_MISC */
+	uint32_t stylus_buttons; /* bitmask of evcode - BTN_TOUCH */
 	enum libinput_tool tool;
 	int32_t tool_serial;
 };
-- 
1.9.0



More information about the wayland-devel mailing list