diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index 4e20694..e173a6a 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -29,6 +29,32 @@ LRESULT CALLBACK FlutterChildSubclassProc(HWND hwnd, UINT message, return DefSubclassProc(hwnd, message, wparam, lparam); } +// Turn off the OS-drawn pen visual feedback (the "Windows Ink" tap ripple, the +// press-and-hold right-click ring, barrel feedback, and flicks) so the pen +// draws instantly with no ugly OS animation under the nib. The tablet input +// service reads these flags from a window property; set it on whichever window +// receives the pointer input. Flag values are from the Windows pen/tablet docs +// (not declared in the public SDK headers). +void DisablePenVisualFeedback(HWND hwnd) { + if (!hwnd) { + return; + } + constexpr ULONG_PTR kDisablePressAndHold = 0x00000001; + constexpr ULONG_PTR kDisablePenTapFeedback = 0x00000008; + constexpr ULONG_PTR kDisablePenBarrelFeedback = 0x00000010; + constexpr ULONG_PTR kDisableTouchUIForceOn = 0x00000100; + constexpr ULONG_PTR kDisableTouchUIForceOff = 0x00000200; + constexpr ULONG_PTR kDisableFlicks = 0x00010000; + const ULONG_PTR flags = kDisablePressAndHold | kDisablePenTapFeedback | + kDisablePenBarrelFeedback | kDisableTouchUIForceOn | + kDisableTouchUIForceOff | kDisableFlicks; + const ATOM atom = ::GlobalAddAtomW(L"MicrosoftTabletPenServiceProperty"); + if (atom != 0) { + ::SetPropW(hwnd, MAKEINTATOM(atom), reinterpret_cast(flags)); + ::GlobalDeleteAtom(atom); + } +} + } // namespace FlutterWindow::FlutterWindow(const flutter::DartProject& project) @@ -64,6 +90,11 @@ bool FlutterWindow::OnCreate() { SetWindowSubclass(flutter_child, FlutterChildSubclassProc, kPenSubclassId, 0); } + // Kill the OS pen tap/press-and-hold visual feedback on both the top-level + // window and the Flutter child (the one that actually gets the pointer input). + DisablePenVisualFeedback(GetHandle()); + DisablePenVisualFeedback(flutter_child); + flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); });