#include "flutter_window.h" #include #include #include #include #include #include #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} static void HandleInjectInput(const flutter::EncodableMap& args) { auto typeIt = args.find(flutter::EncodableValue("type")); if (typeIt == args.end()) return; std::string type = std::get(typeIt->second); int screenW = GetSystemMetrics(SM_CXSCREEN); int screenH = GetSystemMetrics(SM_CYSCREEN); if (type == "move") { double nx = std::get(args.at(flutter::EncodableValue("x"))); double ny = std::get(args.at(flutter::EncodableValue("y"))); INPUT input = {}; input.type = INPUT_MOUSE; input.mi.dx = (LONG)(nx * 65535); input.mi.dy = (LONG)(ny * 65535); input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; SendInput(1, &input, sizeof(INPUT)); } else if (type == "click") { double nx = std::get(args.at(flutter::EncodableValue("x"))); double ny = std::get(args.at(flutter::EncodableValue("y"))); int btn = 0; auto btnIt = args.find(flutter::EncodableValue("button")); if (btnIt != args.end()) btn = std::get(btnIt->second); // move first INPUT moveInput = {}; moveInput.type = INPUT_MOUSE; moveInput.mi.dx = (LONG)(nx * 65535); moveInput.mi.dy = (LONG)(ny * 65535); moveInput.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; SendInput(1, &moveInput, sizeof(INPUT)); INPUT clickInput[2] = {}; clickInput[0].type = INPUT_MOUSE; clickInput[1].type = INPUT_MOUSE; if (btn == 1) { clickInput[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; clickInput[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP; } else { clickInput[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; clickInput[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; } SendInput(2, clickInput, sizeof(INPUT)); } else if (type == "keydown" || type == "keyup") { auto keyIt = args.find(flutter::EncodableValue("keyCode")); if (keyIt == args.end()) return; // Flutter logical key IDs dont map 1:1 to VKs — use low byte as rough VK int logicalKey = std::get(keyIt->second); WORD vk = (WORD)(logicalKey & 0xFF); INPUT keyInput = {}; keyInput.type = INPUT_KEYBOARD; keyInput.ki.wVk = vk; if (type == "keyup") keyInput.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &keyInput, sizeof(INPUT)); } } bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); // register input injection channel auto channel = std::make_shared>( flutter_controller_->engine()->messenger(), "com.pulsar/input", &flutter::StandardMethodCodec::GetInstance() ); channel->SetMethodCallHandler( [](const flutter::MethodCall& call, std::unique_ptr> result) { if (call.method_name() == "injectInput") { if (const auto* args = std::get_if(call.arguments())) { HandleInjectInput(*args); } result->Success(); } else { result->NotImplemented(); } }); SetChildContent(flutter_controller_->view()->GetNativeWindow()); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); flutter_controller_->ForceRedraw(); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { 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); }