-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Allow stylus support on windows #165323
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
base: master
Are you sure you want to change the base?
Allow stylus support on windows #165323
Conversation
|
Looks like we can also identify hovering, I will work on this next |
|
Dont know why mac and linux ci fails, but my changes doesnt break any windows test so it looks good. Now i need to add my own tests |
|
Hey @CodeDoctorDE welcome! Thanks for contributing! It looks like this never entered the review queue since it was marked a draft. Is this still something you would like to work on? |
|
Hello, oh yeah, but it currently has some problems I need to fix |
|
Hello again @CodeDoctorDE, this came back around to stale PR triage. :) |
|
Hello, |
|
Quite alright! Thanks for letting us know. I am going to close this for now to remove it from our review queue and CI tasks. Feel free to reopen when you are ready to return to it. Thanks! |
|
Hello, I finished my changes but I don't have the option to reopen it. |
|
An existing Git SHA, To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with |
by @Demohstens Adds six unittests for different pointer events. Added methods to WindowsProcTable for Pointer functions to allow for overloading in tests. Ensured all unittest pass Co-authored-by: Demohstens <[email protected]>
7446780 to
f649c11
Compare
|
PR can be reviewed, not sure why mac fais |
It is passing. Tree status would be green on its own |
| auto that = static_cast<FlutterWindow*>(cs->lpCreateParams); | ||
| that->window_handle_ = window; | ||
| that->text_input_manager_->SetWindowHandle(window); | ||
| RegisterTouchWindow(window, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you confirm that multi-touch gestures like pinching on a trackpad still works after this change?
(This line was added by flutter/engine#27863 for multi-touch support, I'd like to double-check we're not regressing that behavior with this new implementation!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing this line disables WM_GESTURE & WM_TOUCH messages. The first is not handled and the latter is replaced by the new implementation so this should not impact the trackpad at all. Local tests seem to confirm this but i'm not entirely confident they cover all cases. This might have been necessary for supporting windows 7 and older as WM_POINTER* were not supported before that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah gotcha, thanks for the details!
cc @jnschulze in case you have any concerns since you added this back in: flutter/engine#27863
| } else if (message == WM_POINTERUPDATE) { | ||
| // POINTER_FLAG_INCONTACT indicates the stylus is touching the screen | ||
| // When not set, it means the stylus is hovering | ||
| OnPointerMove(x, y, device_kind, touch_id, rotation, pressure, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these non-obvious default values, could you add a comment like /*argument_name=*/ to make these a little more obvious? For example:
| OnPointerMove(x, y, device_kind, touch_id, rotation, pressure, 0); | |
| OnPointerMove(x, y, device_kind, touch_id, rotation, pressure, /* modifiers_state=*/0); |
|
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces stylus support on Windows by migrating from WM_TOUCH to the more modern WM_POINTER* APIs. This is a significant improvement, allowing for the capture of additional input data like pressure and rotation. The changes are well-structured, touching the embedder API, the Windows-specific implementation, and adding a comprehensive suite of unit tests for the new functionality. The overall approach is solid. I have a few suggestions to enhance code clarity and maintainability.
| case WM_POINTERDOWN: | ||
| case WM_POINTERUPDATE: | ||
| case WM_POINTERUP: | ||
| case WM_POINTERLEAVE: { | ||
| xPos = GET_X_LPARAM(lparam); | ||
| yPos = GET_Y_LPARAM(lparam); | ||
| auto x = static_cast<double>(xPos); | ||
| auto y = static_cast<double>(yPos); | ||
| auto pointerId = GET_POINTERID_WPARAM(wparam); | ||
| POINTER_INFO pointerInfo; | ||
| if (windows_proc_table_->GetPointerInfo(pointerId, &pointerInfo)) { | ||
| UINT32 pressure = 0; | ||
| UINT32 rotation = 0; | ||
| if (pointerInfo.pointerType == PT_PEN) { | ||
| POINTER_PEN_INFO penInfo; | ||
| if (windows_proc_table_->GetPointerPenInfo(pointerId, &penInfo)) { | ||
| pressure = penInfo.pressure; | ||
| rotation = penInfo.rotation; | ||
| } | ||
| } | ||
| CloseTouchInputHandle(touch_input_handle); | ||
| auto touch_id = touch_id_generator_.GetGeneratedId(pointerId); | ||
| FlutterPointerDeviceKind device_kind = kFlutterPointerDeviceKindMouse; | ||
| switch (pointerInfo.pointerType) { | ||
| case PT_TOUCH: | ||
| device_kind = kFlutterPointerDeviceKindTouch; | ||
| break; | ||
| case PT_PEN: | ||
| device_kind = kFlutterPointerDeviceKindStylus; | ||
| break; | ||
| case PT_MOUSE: | ||
| device_kind = kFlutterPointerDeviceKindMouse; | ||
| break; | ||
| } | ||
| if (message == WM_POINTERDOWN) { | ||
| OnPointerDown(x, y, device_kind, touch_id, WM_LBUTTONDOWN, rotation, | ||
| pressure); | ||
| } else if (message == WM_POINTERUPDATE) { | ||
| // POINTER_FLAG_INCONTACT indicates the stylus is touching the screen | ||
| // When not set, it means the stylus is hovering | ||
| OnPointerMove(x, y, device_kind, touch_id, rotation, pressure, 0); | ||
| } else if (message == WM_POINTERUP) { | ||
| OnPointerUp(x, y, device_kind, touch_id, WM_LBUTTONUP); | ||
| // keep tracking the pointer (especially important for stylus) | ||
| // This allows a stylus to "hover" over the window | ||
| } else if (message == WM_POINTERLEAVE) { | ||
| OnPointerLeave(x, y, device_kind, touch_id); | ||
| touch_id_generator_.ReleaseNumber(pointerId); | ||
| } | ||
| } | ||
| return 0; | ||
| break; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block for handling pointer messages is quite large and adds significant complexity to the HandleMessage method. To improve readability and maintainability, consider extracting this logic into a new private helper method, for example HandlePointerMessage(UINT const message, WPARAM const wparam, LPARAM const lparam).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I think this is fine as-is. If you want to split this up, I'd consider adding a ToPointerDataKind helper function for mapping from win32 pointer input types to Flutter's pointer device kinds.
| // Test that the mock is working by calling it directly | ||
| POINTER_INFO test_pointer_info = {}; | ||
| BOOL result = mock_proc_table->GetPointerInfo(1, &test_pointer_info); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| LRESULT message_result = | ||
| win32window.InjectWindowMessage(WM_POINTERDOWN, wparam, lparam); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
engine/src/flutter/shell/platform/windows/flutter_windows_view.cc
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/windows/flutter_windows_view.cc
Outdated
Show resolved
Hide resolved
* Added kMaxPenPressure constant * Added cmath as dependancy to windows
|
I'll be on vacation for the next 10 days and won't be able to review. Apologies for the delay! |
|
I'm having some issues with my setup and am unable to build the engine on my laptop atm. I will get to your comments, @loic-sharma, next week when I'm home! |
trackpad device type
|
@Demohstens please feel free to ping me when this is ready for another review :) |
|
Should be ready @loic-sharma - I totally forgot to mention you, sorry! If someone has a pen with rotation capabilities it'd be great to test that property. The tests don't account for the transformation as they intercept the function before it's sent to the framework and my pen does not support rotation :/ |
| auto state = GetOrCreatePointerState(device_kind, device_id); | ||
| state->buttons |= flutter_button; | ||
| state->rotation = rotation; | ||
| state->pressure = pressure; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we reset these values in OnPointerUp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a month ago I looked at it, but I think it could also be useful to get the last value that is captured instead of just having a default value.
engine/src/flutter/shell/platform/windows/flutter_windows_view.cc
Outdated
Show resolved
Hide resolved
|
Sorry for the late update, the start of the semester held me up. It’s ready now! |
90f0db5 to
27dbb44
Compare
|
cc @mattkae |
mattkae
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments, but nothing huge on my side. I have no hardware to test though, so I'll have to trust 😄
engine/src/flutter/shell/platform/windows/flutter_windows_view.cc
Outdated
Show resolved
Hide resolved
mattkae
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice tests 😄 I just have one final piece of feedback here
Co-authored-by: Matthew Kosarek <[email protected]>
mattkae
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am perfectly happy with this, thanks for putting in so much work on testing 🎉
@loic-sharma Would you have anything to add? I cannot test on my end unfortunately
|
The tests that failed look like infra problems. I reran them! |
|
FYI it looks like you have a formatting issue: https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8695098116792788577/+/u/test:_test:_Check_formatting/stdout |
This is my attempt for adding support for stylus on windows.
It's work in progress! I post it here to indicate that I'm working on it and that the same work is not done twice
I'm working on the
flutter_window.cppfile. Maybe I need to touch some other code to allow additional information like pressure, rotation and more.Would fix #102836 and #65248
There should be no breaking change other than stylus would be reported as
stylusinstead oftouch.Tested with flutter master on my test project:

https://github.com/CodeDoctorDE/flutter-input-demo
Tests are currently not there, I will add them next.
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.