diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index f94069dd9..fbbcf12a2 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -597,6 +597,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; } @@ -628,6 +636,7 @@ Ref 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); @@ -660,7 +669,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 &p_event) { @@ -708,6 +717,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); @@ -716,12 +728,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; } //////////////////////////////////////// diff --git a/core/os/input_event.h b/core/os/input_event.h index f449f87cc..f7c88c58d 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -386,6 +386,7 @@ class InputEventMouseMotion : public InputEventMouse { float pressure; Vector2 relative; Vector2 speed; + bool pen_inverted; protected: static void _bind_methods(); @@ -397,6 +398,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; diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml index 7d068af3f..e9d3f0c1d 100644 --- a/doc/classes/InputEventMouseMotion.xml +++ b/doc/classes/InputEventMouseMotion.xml @@ -15,6 +15,10 @@ + + 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. + Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code]. diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index fd33b0b38..d8819ac71 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -73,6 +73,8 @@ public: NSTimeInterval last_warp = 0; bool ignore_warp = false; + bool last_pen_inverted = false; + Vector key_event_buffer; int key_event_pos; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 394f45c01..dc46feb41 100644 --- a/platform/osx/os_osx.mm +++ b/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()); @@ -3357,10 +3363,10 @@ void OS_OSX::force_process_input() { } void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { - // Prevent main loop from sleeping and redraw window during modal popup display. + // Prevent main loop from sleeping and redraw window during modal popup display. // Do not redraw when rendering is done from the separate thread, it will conflict with the OpenGL context updates. - if (get_singleton()->get_main_loop() && (get_singleton()->get_render_thread_mode() != RENDER_SEPARATE_THREAD) && !OS_OSX::singleton->is_resizing) { + if (get_singleton()->get_main_loop() && (get_singleton()->get_render_thread_mode() != RENDER_SEPARATE_THREAD) && !OS_OSX::singleton->is_resizing) { Main::force_redraw(); if (!Main::is_iterating()) { // Avoid cyclic loop. Main::iteration(); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 3050c4b8a..ce0a127b3 100644 --- a/platform/windows/os_windows.cpp +++ b/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 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) @@ -3800,8 +3809,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; @@ -3845,6 +3854,10 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { was_maximized = false; window_focused = true; + pen_inverted = false; + block_mm = false; + last_pen_inverted = false; + //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); if (wintab_lib) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 662d8981e..d16ae089b 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -70,10 +70,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; @@ -125,6 +128,7 @@ typedef struct tagORIENTATION { } ORIENTATION; typedef struct tagPACKET { + int pkStatus; int pkNormalPressure; int pkTangentPressure; ORIENTATION pkOrientation; @@ -146,6 +150,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 @@ -271,11 +283,13 @@ class OS_Windows : public OS { int min_pressure; int max_pressure; bool tilt_supported; - bool block_mm = false; + bool pen_inverted; + bool block_mm; int last_pressure_update; float last_pressure; Vector2 last_tilt; + bool last_pen_inverted; enum { KEY_EVENT_BUFFER_SIZE = 512 diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 36adae661..c722dec54 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -635,6 +635,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); @@ -644,7 +645,8 @@ 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; } @@ -713,6 +715,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); @@ -2525,7 +2528,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. @@ -2591,6 +2594,11 @@ void OS_X11::process_xevents() { values++; } + Map::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) { @@ -2935,6 +2943,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 :) diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index d7166ed11..1ee1cf3c4 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -132,11 +132,13 @@ class OS_X11 : public OS_Unix { Map pen_pressure_range; Map pen_tilt_x_range; Map pen_tilt_y_range; + Map pen_inverted_devices; XIEventMask all_event_mask; XIEventMask all_master_event_mask; Map state; double pressure; bool pressure_supported; + bool pen_inverted; Vector2 tilt; Vector2 mouse_pos_to_filter; Vector2 relative_motion;