text: #include "flutter/shell/platform/windows/win32_flutter_window.h"
  
  #include <chrono>
  
  namespace flutter {
  
  // the Windows DPI system is based on this
  // constant for machines running at 100% scaling.
  constexpr int base_dpi = 96;
  
  Win32FlutterWindow::Win32FlutterWindow() {
    surface_manager = std::make_unique<AngleSurfaceManager>();
  }
  
  Win32FlutterWindow::Win32FlutterWindow(const char* title,
                                         const int x,
                                         const int y,
                                         const int width,
                                         const int height) noexcept
      : Win32FlutterWindow() {
    Win32Window::Initialize(title, x, y, width, height);
  }
  
  Win32FlutterWindow::~Win32FlutterWindow() {
    DestroyRenderSurface();
  }
  
  FlutterDesktopWindowControllerRef Win32FlutterWindow::CreateWin32FlutterWindow(
      const char* title,
      const int x,
      const int y,
      const int width,
      const int height) {
    auto state = std::make_unique<FlutterDesktopWindowControllerState>();
    state->window = std::make_unique<flutter::Win32FlutterWindow>(title, 10, 10,
                                                                  width, height);
  
    // a window wrapper for the state block, distinct from the
    // window_wrapper handed to plugin_registrar.
    state->window_wrapper = std::make_unique<FlutterDesktopWindow>();
    state->window_wrapper->window = state->window.get();
    return state.release();
  }
  
  void Win32FlutterWindow::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) {
    engine_ = eng;
  
    auto messenger = std::make_unique<FlutterDesktopMessenger>();
    message_dispatcher_ =
        std::make_unique<flutter::IncomingMessageDispatcher>(messenger.get());
    messenger->engine = engine_;
    messenger->dispatcher = message_dispatcher_.get();
  
    window_wrapper_ = std::make_unique<FlutterDesktopWindow>();
    window_wrapper_->window = this;
  
    plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
    plugin_registrar_->messenger = std::move(messenger);
    plugin_registrar_->window = window_wrapper_.get();
  
    internal_plugin_registrar_ =
        std::make_unique<flutter::PluginRegistrar>(plugin_registrar_.get());
  
    // Set up the keyboard handlers.
    auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
    keyboard_hook_handlers_.push_back(
        std::make_unique<flutter::KeyEventHandler>(internal_plugin_messenger));
    keyboard_hook_handlers_.push_back(
        std::make_unique<flutter::TextInputPlugin>(internal_plugin_messenger));
    platform_handler_ = std::make_unique<flutter::PlatformHandler>(
        internal_plugin_messenger, this);
  
    auto state = std::make_unique<FlutterDesktopWindowControllerState>();
    state->engine = engine_;
  
    process_events_ = true;
  }
  
  FlutterDesktopPluginRegistrarRef Win32FlutterWindow::GetRegistrar() {
    return plugin_registrar_.get();
  }
  
  // Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage.
  static FlutterDesktopMessage ConvertToDesktopMessage(
      const FlutterPlatformMessage& engine_message) {
    FlutterDesktopMessage message = {};
    message.struct_size = sizeof(message);
    message.channel = engine_message.channel;
    message.message = engine_message.message;
    message.message_size = engine_message.message_size;
    message.response_handle = engine_message.response_handle;
    return message;
  }
  
  // The Flutter Engine calls out to this function when new platform messages
  // are available.
  void Win32FlutterWindow::HandlePlatformMessage(
      const FlutterPlatformMessage* engine_message) {
    if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) {
      std::cerr << "Invalid message size received. Expected: "
                << sizeof(FlutterPlatformMessage) << " but received "
                << engine_message->struct_size << std::endl;
      return;
    }
  
    auto message = ConvertToDesktopMessage(*engine_message);
  
    message_dispatcher_->HandleMessage(
        message, [this] { this->process_events_ = false; },
        [this] { this->process_events_ = true; });
  }
  
  void Win32FlutterWindow::OnDpiScale(unsigned int dpi){};
  
  // When DesktopWindow notifies that a WM_Size message has come in
  // lets FlutterEngine know about the new size.
  void Win32FlutterWindow::OnResize(unsigned int width, unsigned int height) {
    SendWindowMetrics();
  }
  
  void Win32FlutterWindow::OnPointerMove(double x, double y) {
    if (process_events_) {
      SendPointerMove(x, y);
    }
  }
  
  void Win32FlutterWindow::OnPointerDown(double x, double y) {
    if (process_events_) {
      SendPointerDown(x, y);
    }
  }
  
  void Win32FlutterWindow::OnPointerUp(double x, double y) {
    if (process_events_) {
      SendPointerUp(x, y);
    }
  }
  
  void Win32FlutterWindow::OnChar(unsigned int code_point) {
    if (process_events_) {
      SendChar(code_point);
    }
  }
  
  void Win32FlutterWindow::OnKey(int key, int scancode, int action, int mods) {
    if (process_events_) {
      SendKey(key, scancode, action, 0);
    }
  }
  
  void Win32FlutterWindow::OnScroll(double delta_x, double delta_y) {
    if (process_events_) {
      SendScroll(delta_x, delta_y);
    }
  }
  
  void Win32FlutterWindow::OnClose() {
    messageloop_running_ = false;
  }
  
  void Win32FlutterWindow::FlutterMessageLoop() {
    MSG message;
  
    messageloop_running_ = true;
  
    // TODO: need either non-blocking meesage loop or custom dispatch
    // implementation per  https://github.com/flutter/flutter/issues/36420
    while (GetMessage(&message, nullptr, 0, 0) && messageloop_running_) {
      TranslateMessage(&message);
      DispatchMessage(&message);
      __FlutterEngineFlushPendingTasksNow();
    }
  }
  
  // Sends new size information to FlutterEngine.
  void Win32FlutterWindow::SendWindowMetrics() {
    if (engine_ == nullptr) {
      return;
    }
  
    FlutterWindowMetricsEvent event = {};
    event.struct_size = sizeof(event);
    event.width = GetCurrentWidth();
    event.height = GetCurrentHeight();
    event.pixel_ratio = static_cast<double>(GetCurrentDPI()) / base_dpi;
    auto result = FlutterEngineSendWindowMetricsEvent(engine_, &event);
  }
  
  // Updates |event_data| with the current location of the mouse cursor.
  void Win32FlutterWindow::SetEventLocationFromCursorPosition(
      FlutterPointerEvent* event_data) {
    POINT point;
    GetCursorPos(&point);
  
    ScreenToClient(GetWindowHandle(), &point);
  
    event_data->x = point.x;
    event_data->y = point.y;
  }
  
  // Set's |event_data|'s phase to either kMove or kHover depending on the current
  // primary mouse button state.
  void Win32FlutterWindow::SetEventPhaseFromCursorButtonState(
      FlutterPointerEvent* event_data) {
    event_data->phase = pointer_is_down_ ? FlutterPointerPhase::kMove
                                         : FlutterPointerPhase::kHover;
  }
  
  void Win32FlutterWindow::SendPointerMove(double x, double y) {
    FlutterPointerEvent event = {};
    event.x = x;
    event.y = y;
    SetEventPhaseFromCursorButtonState(&event);
    SendPointerEventWithData(event);
  }
  
  void Win32FlutterWindow::SendPointerDown(double x, double y) {
    pointer_is_down_ = true;
    FlutterPointerEvent event = {};
    event.phase = FlutterPointerPhase::kDown;
    event.x = x;
    event.y = y;
    SendPointerEventWithData(event);
  }
  
  void Win32FlutterWindow::SendPointerUp(double x, double y) {
    pointer_is_down_ = false;
    FlutterPointerEvent event = {};
    event.phase = FlutterPointerPhase::kUp;
    event.x = x;
    event.y = y;
    SendPointerEventWithData(event);
  }
  
  void Win32FlutterWindow::SendChar(unsigned int code_point) {
    for (const auto& handler : keyboard_hook_handlers_) {
      handler->CharHook(this, code_point);
    }
  }
  
  void Win32FlutterWindow::SendKey(int key, int scancode, int action, int mods) {
    for (const auto& handler : keyboard_hook_handlers_) {
      handler->KeyboardHook(this, key, scancode, action, mods);
    }
  }
  
  void Win32FlutterWindow::SendScroll(double delta_x, double delta_y) {
    FlutterPointerEvent event = {};
    SetEventLocationFromCursorPosition(&event);
    SetEventPhaseFromCursorButtonState(&event);
    event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
    // TODO: See if this can be queried from the OS; this value is chosen
    // arbitrarily to get something that feels reasonable.
    const int kScrollOffsetMultiplier = 20;
    event.scroll_delta_x = delta_x * kScrollOffsetMultiplier;
    event.scroll_delta_y = delta_y * kScrollOffsetMultiplier;
    SendPointerEventWithData(event);
  }
  
  void Win32FlutterWindow::SendPointerEventWithData(
      const FlutterPointerEvent& event_data) {
    // If sending anything other than an add, and the pointer isn't already added,
    // synthesize an add to satisfy Flutter's expectations about events.
    if (!pointer_currently_added_ &&
        event_data.phase != FlutterPointerPhase::kAdd) {
      FlutterPointerEvent event = {};
      event.phase = FlutterPointerPhase::kAdd;
      event.x = event_data.x;
      event.y = event_data.y;
      SendPointerEventWithData(event);
    }
    // Don't double-add (e.g., if events are delivered out of order, so an add has
    // already been synthesized).
    if (pointer_currently_added_ &&
        event_data.phase == FlutterPointerPhase::kAdd) {
      return;
    }
  
    FlutterPointerEvent event = event_data;
    // Set metadata that's always the same regardless of the event.
    event.struct_size = sizeof(event);
    event.timestamp =
        std::chrono::duration_cast<std::chrono::microseconds>(
            std::chrono::high_resolution_clock::now().time_since_epoch())
            .count();
  
    // Windows passes all input in either physical pixels (Per-monitor, System
    // DPI) or pre-scaled to match bitmap scaling of output where process is
    // running in DPI unaware more.  In either case, no need to manually scale
    // input here.  For more information see DPIHelper.
    event.scroll_delta_x;
    event.scroll_delta_y;
  
    FlutterEngineSendPointerEvent(engine_, &event, 1);
  
    if (event_data.phase == FlutterPointerPhase::kAdd) {
      pointer_currently_added_ = true;
    } else if (event_data.phase == FlutterPointerPhase::kRemove) {
      pointer_currently_added_ = false;
    }
  }
  
  bool Win32FlutterWindow::MakeCurrent() {
    return surface_manager->MakeCurrent(render_surface);
  }
  
  bool Win32FlutterWindow::ClearContext() {
    return surface_manager->MakeCurrent(nullptr);
  }
  
  bool Win32FlutterWindow::SwapBuffers() {
    return surface_manager->SwapBuffers(render_surface);
  }
  
  void Win32FlutterWindow::CreateRenderSurface() {
    if (surface_manager && render_surface == EGL_NO_SURFACE) {
      render_surface = surface_manager->CreateSurface(GetWindowHandle());
    }
  }
  
  void Win32FlutterWindow::DestroyRenderSurface() {
    if (surface_manager) {
      surface_manager->DestroySurface(render_surface);
    }
    render_surface = EGL_NO_SURFACE;
  }
  
  }  // namespace flutter