#include "flutter_window.h" #include #include #include "flutter/generated_plugin_registrant.h" #include "ocr_channel.h" #include "pen_channel.h" // SetWindowSubclass / DefSubclassProc / RemoveWindowSubclass live in comctl32. #pragma comment(lib, "comctl32.lib") namespace { // Id for the pen observer subclass installed on the Flutter child view window. constexpr UINT_PTR kPenSubclassId = 1; // Subclass proc on the FLUTTER CHILD window. WM_POINTER messages are delivered // to the window under the pointer — that is the Flutter view's child HWND, not // the top-level window — so this is where the pen's barrel/eraser/tilt actually // arrive. We observe (non-consuming) and pass every message straight through to // Flutter's own handler via DefSubclassProc, so input behavior is unchanged. LRESULT CALLBACK FlutterChildSubclassProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, UINT_PTR /*subclass_id*/, DWORD_PTR /*ref_data*/) { ObservePenMessage(message, wparam, lparam); return DefSubclassProc(hwnd, message, wparam, lparam); } } // namespace FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); RegisterOcrChannel(flutter_controller_->engine()); RegisterPenChannel(flutter_controller_->engine()); HWND flutter_child = flutter_controller_->view()->GetNativeWindow(); SetChildContent(flutter_child); // Observe WM_POINTER on the Flutter child window (where pen messages land) so // the pen barrel/eraser/inverted flags + tilt reach the badnote/pen channel. if (flutter_child) { SetWindowSubclass(flutter_child, FlutterChildSubclassProc, kPenSubclassId, 0); } flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); // Flutter can complete the first frame before the "show window" callback is // registered. The following call ensures a frame is pending to ensure the // window is shown. It is a no-op if the first frame hasn't completed yet. flutter_controller_->ForceRedraw(); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { HWND flutter_child = flutter_controller_->view()->GetNativeWindow(); if (flutter_child) { RemoveWindowSubclass(flutter_child, FlutterChildSubclassProc, kPenSubclassId); } flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Observe pen messages before Flutter consumes WM_POINTER events. ObservePenMessage(message, wparam, lparam); // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); }