浏览代码

[3.x, macOS, Windows, X11] Add stylus inverted/eraser support to InputEventMouseMotion event

Hansem Ro 3 年之前
父节点
当前提交
193d5c11f3

+ 15 - 1
core/os/input_event.cpp

@@ -590,6 +590,14 @@ float InputEventMouseMotion::get_pressure() const {
 	return pressure;
 }
 
+void InputEventMouseMotion::set_pen_inverted(bool p_inverted) {
+	pen_inverted = p_inverted;
+}
+
+bool InputEventMouseMotion::get_pen_inverted() const {
+	return pen_inverted;
+}
+
 void InputEventMouseMotion::set_relative(const Vector2 &p_relative) {
 	relative = p_relative;
 }
@@ -621,6 +629,7 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co
 
 	mm->set_position(l);
 	mm->set_pressure(get_pressure());
+	mm->set_pen_inverted(get_pen_inverted());
 	mm->set_tilt(get_tilt());
 	mm->set_global_position(g);
 
@@ -653,7 +662,7 @@ String InputEventMouseMotion::as_text() const {
 			button_mask_string = itos(get_button_mask());
 			break;
 	}
-	return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + "), pressure=(" + rtos(get_pressure()) + "), tilt=(" + String(get_tilt()) + ")";
+	return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + "), pressure=(" + rtos(get_pressure()) + "), tilt=(" + String(get_tilt()) + "), pen_inverted=(" + rtos(get_pen_inverted()) + ")";
 }
 
 bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
@@ -701,6 +710,9 @@ void InputEventMouseMotion::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMouseMotion::set_pressure);
 	ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMouseMotion::get_pressure);
 
+	ClassDB::bind_method(D_METHOD("set_pen_inverted", "pen_inverted"), &InputEventMouseMotion::set_pen_inverted);
+	ClassDB::bind_method(D_METHOD("get_pen_inverted"), &InputEventMouseMotion::get_pen_inverted);
+
 	ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventMouseMotion::set_relative);
 	ClassDB::bind_method(D_METHOD("get_relative"), &InputEventMouseMotion::get_relative);
 
@@ -709,12 +721,14 @@ void InputEventMouseMotion::_bind_methods() {
 
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure"), "set_pressure", "get_pressure");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pen_inverted"), "set_pen_inverted", "get_pen_inverted");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "speed"), "set_speed", "get_speed");
 }
 
 InputEventMouseMotion::InputEventMouseMotion() {
 	pressure = 0;
+	pen_inverted = false;
 }
 
 ////////////////////////////////////////

+ 4 - 0
core/os/input_event.h

@@ -387,6 +387,7 @@ class InputEventMouseMotion : public InputEventMouse {
 	float pressure;
 	Vector2 relative;
 	Vector2 speed;
+	bool pen_inverted;
 
 protected:
 	static void _bind_methods();
@@ -398,6 +399,9 @@ public:
 	void set_pressure(float p_pressure);
 	float get_pressure() const;
 
+	void set_pen_inverted(bool p_inverted);
+	bool get_pen_inverted() const;
+
 	void set_relative(const Vector2 &p_relative);
 	Vector2 get_relative() const;
 

+ 4 - 0
doc/classes/InputEventMouseMotion.xml

@@ -14,6 +14,10 @@
 	<methods>
 	</methods>
 	<members>
+		<member name="pen_inverted" type="bool" setter="set_pen_inverted" getter="get_pen_inverted" default="false">
+			Returns [code]true[/code] when using the eraser end of a stylus pen.
+			[b]Note:[/b] This property is implemented on Linux, macOS and Windows.
+		</member>
 		<member name="pressure" type="float" setter="set_pressure" getter="get_pressure" default="0.0">
 			Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code].
 		</member>

+ 2 - 0
platform/osx/os_osx.h

@@ -74,6 +74,8 @@ public:
 	NSTimeInterval last_warp = 0;
 	bool ignore_warp = false;
 
+	bool last_pen_inverted = false;
+
 	Vector<KeyEvent> key_event_buffer;
 	int key_event_pos;
 

+ 7 - 1
platform/osx/os_osx.mm

@@ -809,9 +809,15 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
 	const Vector2 pos = get_mouse_pos(mpos);
 	mm->set_position(pos);
 	mm->set_pressure([event pressure]);
-	if ([event subtype] == NSEventSubtypeTabletPoint) {
+	NSEventSubtype subtype = [event subtype];
+	if (subtype == NSEventSubtypeTabletPoint) {
 		const NSPoint p = [event tilt];
 		mm->set_tilt(Vector2(p.x, p.y));
+		mm->set_pen_inverted(OS_OSX::singleton->last_pen_inverted);
+	} else if (subtype == NSEventSubtypeTabletProximity) {
+		// Check if using the eraser end of pen only on proximity event.
+		OS_OSX::singleton->last_pen_inverted = [event pointingDeviceType] == NSPointingDeviceTypeEraser;
+		mm->set_pen_inverted(OS_OSX::singleton->last_pen_inverted);
 	}
 	mm->set_global_position(pos);
 	mm->set_speed(OS_OSX::singleton->input->get_last_mouse_speed());

+ 13 - 4
platform/windows/os_windows.cpp

@@ -490,6 +490,8 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 						last_tilt = Vector2();
 					}
 
+					last_pen_inverted = packet.pkStatus & TPS_INVERT;
+
 					POINT coords;
 					GetCursorPos(&coords);
 					ScreenToClient(hWnd, &coords);
@@ -504,6 +506,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 					mm->set_shift(GetKeyState(VK_SHIFT) < 0);
 					mm->set_alt(alt_mem);
 
+					mm->set_pen_inverted(last_pen_inverted);
 					mm->set_pressure(last_pressure);
 					mm->set_tilt(last_tilt);
 
@@ -631,6 +634,8 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 			Ref<InputEventMouseMotion> mm;
 			mm.instance();
 
+			mm->set_pen_inverted(pen_info.penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER));
+
 			if (pen_info.penMask & PEN_MASK_PRESSURE) {
 				mm->set_pressure((float)pen_info.pressure / 1024);
 			} else {
@@ -742,14 +747,17 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 				} else {
 					last_tilt = Vector2();
 					last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f;
+					last_pen_inverted = false;
 				}
 			} else {
 				last_tilt = Vector2();
 				last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f;
+				last_pen_inverted = false;
 			}
 
 			mm->set_pressure(last_pressure);
 			mm->set_tilt(last_tilt);
+			mm->set_pen_inverted(last_pen_inverted);
 
 			mm->set_button_mask(last_button_state);
 
@@ -1478,8 +1486,8 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
 	if ((get_current_tablet_driver() == "wintab") && wintab_available) {
 		wintab_WTInfo(WTI_DEFSYSCTX, 0, &wtlc);
 		wtlc.lcOptions |= CXO_MESSAGES;
-		wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
-		wtlc.lcMoveMask = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
+		wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
+		wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
 		wtlc.lcPktMode = 0;
 		wtlc.lcOutOrgX = 0;
 		wtlc.lcOutExtX = wtlc.lcInExtX;
@@ -1507,6 +1515,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
 	last_pressure = 0;
 	last_pressure_update = 0;
 	last_tilt = Vector2();
+	last_pen_inverted = false;
 
 #if defined(OPENGL_ENABLED)
 
@@ -3823,8 +3832,8 @@ void OS_Windows::set_current_tablet_driver(const String &p_driver) {
 			if ((p_driver == "wintab") && wintab_available) {
 				wintab_WTInfo(WTI_DEFSYSCTX, 0, &wtlc);
 				wtlc.lcOptions |= CXO_MESSAGES;
-				wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
-				wtlc.lcMoveMask = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
+				wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
+				wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
 				wtlc.lcPktMode = 0;
 				wtlc.lcOutOrgX = 0;
 				wtlc.lcOutExtX = wtlc.lcInExtX;

+ 14 - 0
platform/windows/os_windows.h

@@ -71,10 +71,13 @@
 #define DVC_ROTATION 18
 
 #define CXO_MESSAGES 0x0004
+#define PK_STATUS 0x0002
 #define PK_NORMAL_PRESSURE 0x0400
 #define PK_TANGENT_PRESSURE 0x0800
 #define PK_ORIENTATION 0x1000
 
+#define TPS_INVERT 0x0010 /* 1.1 */
+
 typedef struct tagLOGCONTEXTW {
 	WCHAR lcName[40];
 	UINT lcOptions;
@@ -126,6 +129,7 @@ typedef struct tagORIENTATION {
 } ORIENTATION;
 
 typedef struct tagPACKET {
+	int pkStatus;
 	int pkNormalPressure;
 	int pkTangentPressure;
 	ORIENTATION pkOrientation;
@@ -147,6 +151,14 @@ typedef UINT32 POINTER_FLAGS;
 typedef UINT32 PEN_FLAGS;
 typedef UINT32 PEN_MASK;
 
+#ifndef PEN_FLAG_INVERTED
+#define PEN_FLAG_INVERTED 0x00000002
+#endif
+
+#ifndef PEN_FLAG_ERASER
+#define PEN_FLAG_ERASER 0x00000004
+#endif
+
 #ifndef PEN_MASK_PRESSURE
 #define PEN_MASK_PRESSURE 0x00000001
 #endif
@@ -272,11 +284,13 @@ class OS_Windows : public OS {
 	int min_pressure;
 	int max_pressure;
 	bool tilt_supported;
+	bool pen_inverted = false;
 	bool block_mm = false;
 
 	int last_pressure_update;
 	float last_pressure;
 	Vector2 last_tilt;
+	bool last_pen_inverted = false;
 
 	enum {
 		KEY_EVENT_BUFFER_SIZE = 512

+ 10 - 2
platform/x11/os_x11.cpp

@@ -660,6 +660,7 @@ bool OS_X11::refresh_device_info() {
 
 	xi.absolute_devices.clear();
 	xi.touch_devices.clear();
+	xi.pen_inverted_devices.clear();
 
 	int dev_count;
 	XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
@@ -669,7 +670,7 @@ bool OS_X11::refresh_device_info() {
 		if (!dev->enabled) {
 			continue;
 		}
-		if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave)) {
+		if (!(dev->use == XISlavePointer || dev->use == XIFloatingSlave)) {
 			continue;
 		}
 
@@ -738,6 +739,7 @@ bool OS_X11::refresh_device_info() {
 		xi.pen_pressure_range[dev->deviceid] = Vector2(pressure_min, pressure_max);
 		xi.pen_tilt_x_range[dev->deviceid] = Vector2(tilt_x_min, tilt_x_max);
 		xi.pen_tilt_y_range[dev->deviceid] = Vector2(tilt_y_min, tilt_y_max);
+		xi.pen_inverted_devices[dev->deviceid] = (bool)strstr(dev->name, "eraser");
 	}
 
 	XIFreeDeviceInfo(info);
@@ -2513,7 +2515,7 @@ void OS_X11::process_xevents() {
 					} break;
 					case XI_RawMotion: {
 						XIRawEvent *raw_event = (XIRawEvent *)event_data;
-						int device_id = raw_event->deviceid;
+						int device_id = raw_event->sourceid;
 
 						// Determine the axis used (called valuators in XInput for some forsaken reason)
 						//  Mask is a bitmask indicating which axes are involved.
@@ -2579,6 +2581,11 @@ void OS_X11::process_xevents() {
 							values++;
 						}
 
+						Map<int, bool>::Element *pen_inverted = xi.pen_inverted_devices.find(device_id);
+						if (pen_inverted) {
+							xi.pen_inverted = pen_inverted->value();
+						}
+
 						// https://bugs.freedesktop.org/show_bug.cgi?id=71609
 						// http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html
 						if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) {
@@ -2922,6 +2929,7 @@ void OS_X11::process_xevents() {
 				} else {
 					mm->set_pressure((get_mouse_button_state() & (1 << (BUTTON_LEFT - 1))) ? 1.0f : 0.0f);
 				}
+				mm->set_pen_inverted(xi.pen_inverted);
 				mm->set_tilt(xi.tilt);
 
 				// Make the absolute position integral so it doesn't look _too_ weird :)

+ 2 - 0
platform/x11/os_x11.h

@@ -133,11 +133,13 @@ class OS_X11 : public OS_Unix {
 		Map<int, Vector2> pen_pressure_range;
 		Map<int, Vector2> pen_tilt_x_range;
 		Map<int, Vector2> pen_tilt_y_range;
+		Map<int, bool> pen_inverted_devices;
 		XIEventMask all_event_mask;
 		XIEventMask all_master_event_mask;
 		Map<int, Vector2> state;
 		double pressure;
 		bool pressure_supported;
+		bool pen_inverted;
 		Vector2 tilt;
 		Vector2 mouse_pos_to_filter;
 		Vector2 relative_motion;