Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API for raw touch events (updated) #24610

Open
wants to merge 35 commits into
base: master
Choose a base branch
from

Conversation

dsa-t
Copy link
Contributor

@dsa-t dsa-t commented Jun 13, 2024

Rebased version of #649

Tested with wxGTK on Linux Mint/X11 and with wxMSW on Windows 11 with a touch panel.

Includes wxMSW patch from https://groups.google.com/g/wx-dev/c/JdeuH95_bGQ/m/tcJCXMZUDgAJ

Copy link
Contributor

@vadz vadz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bringing this up to date!

Globally this looks good to me and I'd definitely like to merge it for 3.3.0. I can address the minor comments I left myself, but if you could please do it, it would be even better, of course. I'd just like to ask you to use "fixup" commits (done by git commit --fixup) instead of force-pushing your changes, as this makes seeing what exactly has been changed more difficult.

The only relatively important question I see here concerns wxTouchEventBase: I'm just not sure if we really need it at all. It does save a tiny amount of duplication, but I don't think anybody is actually going to use it, i.e. handle gesture and raw touch events as objects of this class. Maybe we should remove it and just add position to wxMultiTouchEvent itself too?

Thanks again!

interface/wx/window.h Outdated Show resolved Hide resolved
samples/touchtest/touchtest.cpp Outdated Show resolved Hide resolved
samples/touchtest/touchtest.cpp Outdated Show resolved Hide resolved
samples/touchtest/touchtest.cpp Outdated Show resolved Hide resolved
Comment on lines 114 to 126
wxMenu *file_menu = new wxMenu;

file_menu->Append(wxID_EXIT);

wxMenuBar *menu_bar = new wxMenuBar;

menu_bar->Append(file_menu, wxT("&File"));
SetMenuBar(menu_bar);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks rather useless and could be just removed IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turned out to be useful to check if the pos is relative to the client rect, not the window rect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe some options can be added later to the menu.

event.SetSequenceId(wxTouchSequenceId(gdk_event->sequence));
event.SetPrimary(gdk_event->emulating_pointer);

win->GTKProcessEvent(event);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct to ignore its return value here?

Copy link
Contributor Author

@dsa-t dsa-t Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we still call wxEmulateLeftDownEvent/wxEmulateMotionEvent/wxEmulateLeftUpEvent, even if the touch event was handled?

Note that MSW sends synthesized mouse events regardless, so it would be consistent with MSW.

break;

HandleTouch(wParam, lParam);
// Let DefWindowProc handle the touch events too
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to explain why do we need it to always have them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of processed doesn't appear to have any effect here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no good reason to not use the usual logic, I'd stick to it. I.e. just do

processed = HandleTouch(wParam, lParam);

src/msw/window.cpp Outdated Show resolved Hide resolved
event.SetPosition(pos);
event.SetSequenceId(wxTouchSequenceId(wxUIntToPtr(info[i].dwID + 1)));
event.SetPrimary( (info[i].dwFlags & TOUCHEVENTF_PRIMARY) != 0 );
HandleWindowEvent(event);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we remember if any of the events were processed and only return true in this case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems to be still relevant.

src/osx/cocoa/window.mm Show resolved Hide resolved
@vadz vadz added this to the 3.3.0 milestone Jun 15, 2024
@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 15, 2024

Maybe we should remove it and just add position to wxMultiTouchEvent itself too?

Makes sense to me.

@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 16, 2024

While a finger is held for too long on MSW, activating the "right mouse buton" gesture, the OS doesn't synthesizing mouse down/move events.

So might need to add a IsSynthesized method to mouse events.
The IsPrimary call does not help in this case.

Also in Qt, the primary touch point detection is not available.

@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 16, 2024

Also in Qt, a nomousefromtouch windows platform parameter can be passed to skip these synthesized events at Qt level
(see https://doc.qt.io/qt-6/qguiapplication.html#platform-specific-arguments)

@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 17, 2024

On my GTK system, the mouse pointer emulation code from #2539 doesn't seem to be needed.

If I return false from touch_callback, GTK sends the mouse events by itself.
If I return true, GTK doesn't send any emulated mouse events.

Current touch_callback has a void return type.

Could it be that the void function return value evaluated to something other than false in #19265?

@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 17, 2024

Another question is if the user app has handled the touch event, should we still emit mouse events synthesized by the OS or block them?

@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 17, 2024

It might be simplest to emit the synthesized mouse events anyway.

@dsa-t
Copy link
Contributor Author

dsa-t commented Jun 17, 2024

If we return false in touch_callback, the event order is interesting:

OnMouseMove leftdown 0 pos 224 439

touch_callback Emulating 1 widget 0x555555859120 dev 0x555555634820 dev 0 

OnMouseMove leftdown 1 pos 224 439
OnMouseDown leftdown 1 pos 224 439

touch_callback Emulating 1 widget 0x555555859120 dev 0x555555634820 dev 0 

OnMouseUp leftdown 0 pos 224 439

There's a OnMouseMove with LeftIsDown() == true coming before OnMouseDown.

@vadz
Copy link
Contributor

vadz commented Jul 6, 2024

@dsa-t Do you plan to make more changes here?

@dsa-t
Copy link
Contributor Author

dsa-t commented Jul 7, 2024

Another questions are:

  • Should we use floating point for precise positioning on high-DPI screens?
  • Maybe get rid of wxTouchSequenceId and use int, like Qt does?

@vadz
Copy link
Contributor

vadz commented Jul 7, 2024

* Should we use floating point for precise positioning on high-DPI screens?

What do the different OS provide to us, i.e. what type of coordinates they use?

* Maybe get rid of `wxTouchSequenceId` and use `int`, like [Qt does](https://doc.qt.io/qt-6/qeventpoint.html#id-prop)?

I'm always in favour of using opaque types if possible. I'm still not sure what exactly is wxTouchSequenceId for, i.e. how will it be used, but it doesn't seem like it should be just a plain integer.

@dsa-t
Copy link
Contributor Author

dsa-t commented Jul 7, 2024

What do the different OS provide to us, i.e. what type of coordinates they use?

Logical pixels == DIPs on wxQt, so it would be most noticable on smartphones.

I'm still not sure what exactly is wxTouchSequenceId for, i.e. how will it be used, but it doesn't seem like it should be just a plain integer.

It's an arbitrary value to identify touch points. On wxMSW it's something like:

0x0000000000003763
0x0000000000003764
0x0000000000003765
0x0000000000003766
0x0000000000003767
0x0000000000003768
0x0000000000003769
0x000000000000376a
0x000000000000376b
0x000000000000376c

on wxQt on Windows it's something like:

0x0000000002000001
0x0000000002000002
0x0000000002000003
0x0000000002000004
0x0000000002000005
0x0000000002000006
0x0000000002000007
0x0000000002000008
0x0000000002000009
0x000000000200000a

On wxGTK, it's a GdkEventSequence* (https://docs.gtk.org/gdk3/struct.EventTouch.html), but it's value is usually not a real pointer - it acts as an int.

@vadz
Copy link
Contributor

vadz commented Jul 7, 2024

What do the different OS provide to us, i.e. what type of coordinates they use?

Logical pixels == DIPs on wxQt, so it would be most noticable on smartphones.

Sorry, what I meant was whether it was integer or floating point?

I'm still not sure what exactly is wxTouchSequenceId for, i.e. how will it be used, but it doesn't seem like it should be just a plain integer.

It's an arbitrary value to identify touch points.

Thanks for the explanation and the examples. If we really can't do anything with it, except comparing them, presumably, it should remain opaque and allow doing just this (and copying).

@dsa-t
Copy link
Contributor Author

dsa-t commented Jul 7, 2024

Sorry, what I meant was whether it was integer or floating point?

on GTK, it's

  gdouble x;
  gdouble y;

on Qt, it's qreal aka double in QPointF:

QPointF TouchPoint::screenPos() const

on OSX, it's also a floating point type what wx rounds to int:

https://developer.apple.com/documentation/appkit/nstouch/1534031-normalizedposition?language=objc

@vadz
Copy link
Contributor

vadz commented Jul 7, 2024

In this case I agree that we should use doubles in wx API too.

@dsa-t
Copy link
Contributor Author

dsa-t commented Jul 14, 2024

Changed position type to wxPoint2DDouble.
The way ScreenToClient is used is not great.
Should ScreenToClient be implemented for floatinig point separately, and is there other suggestions?

CI Error in Cirrus CI / FreeBSD wxGTK 3 seems unrelated.

@dsa-t
Copy link
Contributor Author

dsa-t commented Jul 14, 2024

wxMouseEvent positions are floating point in GTK, Qt and OSX.
Should wx also use floating point types for these?

Copy link
Contributor

@vadz vadz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates, I think this is pretty close to being merged, but I'd like to understand why do we need to pass the extra argument everywhere in the MSW code instead of just getting it when needed. Do we really have to complicate things like this?

class wxTouchSequenceId : public wxItemId<void*>
{
public:
wxTouchSequenceId() : wxItemId<void*>() { }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but why not

Suggested change
wxTouchSequenceId() : wxItemId<void*>() { }
wxTouchSequenceId() = default;

?

explicit wxTouchSequenceId(void* pItem) : wxItemId<void*>(pItem) { }
};

class WXDLLIMPEXP_CORE wxMultiTouchEvent : public wxEvent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit surprised that this class is not associated with (e.g. by inheriting from it) wxKeyboardState. Couldn't we have special handling for some touch events when Control (or Shift or whatever) is pressed etc?

Comment on lines +297 to +298
inline wxPoint GetFloor() const;
inline wxPoint GetRounded() const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be added to interface/wx/geometry.h too (which is quite empty, but still not completely useless, I guess...).

@@ -61,10 +61,10 @@ class wxWidgetCocoaNativeKeyDownSuspender
public:
// stops sending keydown events for text inserted into this widget
explicit wxWidgetCocoaNativeKeyDownSuspender(wxWidgetCocoaImpl *target);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be really great to avoid mixing whitespace-only and significant changes. Please configure your editor/IDE to avoid automatically stripping existing whitespace on save.

@@ -368,10 +368,10 @@ class WXDLLIMPEXP_CORE wxWindowMSW : public wxWindowBase

bool HandleDropFiles(WXWPARAM wParam);

bool HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags);
bool HandleMouseMove(int x, int y, WXUINT flags);
bool HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags, WXLPARAM extraInfo);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit annoying to pass this extraInfo everywhere, can't we just call ::GetMessageExtraInfo() when it's needed?

It's nice to consistently pass just the WPARAM/LPARAM to HandleXXX() functions.

@@ -2809,7 +2809,7 @@ bool wxTextCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
int x = GET_X_LPARAM(msgf->lParam),
y = GET_Y_LPARAM(msgf->lParam);

HandleMouseEvent(msg, x, y, flags);
HandleMouseEvent(msg, x, y, flags, ::GetMessageExtraInfo());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes could be avoided if we called ::GetMessageExtraInfo() in HandleMouseEvent() itself too.

@@ -28,6 +28,7 @@
#include "wx/private/bmpbndl.h"

#include "wx/evtloop.h"
#include "wx/vector.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just use <vector> on master.

@@ -236,6 +236,27 @@ class GestureFuncs
return ms_pfnSetGestureConfig;
}

typedef BOOL (WINAPI *RegisterTouchWindow_t)(HWND,ULONG);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we shouldn't need to load these functions dynamically any longer, they're all available since Windows 7 and we don't support anything earlier (or even it) any longer. If you prefer, we can keep this code as is for this PR, but we could (and should) just remove all this dynamic loading stuff later.

break;

HandleTouch(wParam, lParam);
// Let DefWindowProc handle the touch events too
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no good reason to not use the usual logic, I'd stick to it. I.e. just do

processed = HandleTouch(wParam, lParam);

event.SetPosition(pos);
event.SetSequenceId(wxTouchSequenceId(wxUIntToPtr(info[i].dwID + 1)));
event.SetPrimary( (info[i].dwFlags & TOUCHEVENTF_PRIMARY) != 0 );
HandleWindowEvent(event);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems to be still relevant.

@vadz
Copy link
Contributor

vadz commented Jul 16, 2024

wxMouseEvent positions are floating point in GTK, Qt and OSX. Should wx also use floating point types for these?

I guess we could add wxPoint2DDouble m_pos to wxMouseState but we'd still have to keep m_x and m_y for compatibility and ensure they're always synchronized and I'm not sure if it's worth the complexity — considering how (im)precise the mouse/gestures are, it probably doesn't make much difference in practice unless you use a high-precision tablet. Do you notice any problems due to rounding when testing this?

The way ScreenToClient is used is not great.
Should ScreenToClient be implemented for floatinig point separately

Yes, I think it could be nice to add an overload using doubles.

CI Error in Cirrus CI / FreeBSD wxGTK 3 seems unrelated.

Yes, it was already fixed in master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants