Repository: flutter
Issue: FlutterEngineSendKeyEvent function didn't work in flutter embedder of glfw
Labels: a: text input,engine,e: embedder,a: desktop,P3,team-engine,triaged-engine

### Steps to reproduce

1. Uses the FlutterEmbedderGLFW demo
2. call glfwSetKeyCallback with a callback function, and send the key event with FlutterEngineSendKeyEvent

### Expected results

The key event should be sent and the text input should contains contents

### Actual results

The text input is empty

### Code sample

<details open><summary>Code sample</summary>

```cpp
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cassert>
#include <chrono>
#include <iostream>

#include <GLFW/glfw3.h>
#include <flutter_embedder.h>

// This value is calculated after the window is created.
static double g_pixelRatio = 1.0;
static const size_t kInitialWindowWidth = 800;
static const size_t kInitialWindowHeight = 600;
static constexpr FlutterViewId kImplicitViewId = 0;

static_assert(FLUTTER_ENGINE_VERSION == 1,
              "This Flutter Embedder was authored against the stable Flutter "
              "API at version 1. There has been a serious breakage in the "
              "API. Please read the ChangeLog and take appropriate action "
              "before updating this assertion");

void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window,
                                       FlutterPointerPhase phase,
                                       double x,
                                       double y) {
  FlutterPointerEvent event = {};
  event.struct_size = sizeof(event);
  event.phase = phase;
  event.x = x * g_pixelRatio;
  event.y = y * g_pixelRatio;
  event.timestamp =
      std::chrono::duration_cast<std::chrono::microseconds>(
          std::chrono::high_resolution_clock::now().time_since_epoch())
          .count();
  // This example only supports a single window, therefore we assume the pointer
  // event occurred in the only view, the implicit view.
  event.view_id = kImplicitViewId;
  FlutterEngineSendPointerEvent(
      reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)), &event,
      1);
}

void GLFWcursorPositionCallback(GLFWwindow* window, double x, double y) {
  GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kMove, x, y);
}

void GLFWmouseButtonCallback(GLFWwindow* window,
                             int key,
                             int action,
                             int mods) {
  if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS) {
    double x, y;
    glfwGetCursorPos(window, &x, &y);
    GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kDown, x, y);
    glfwSetCursorPosCallback(window, GLFWcursorPositionCallback);
  }

  if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_RELEASE) {
    double x, y;
    glfwGetCursorPos(window, &x, &y);
    GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kUp, x, y);
    glfwSetCursorPosCallback(window, nullptr);
  }
}

static void GLFWKeyCallback(GLFWwindow* window,
                            int key,
                            int scancode,
                            int action,
                            int mods) {
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
    glfwSetWindowShouldClose(window, GLFW_TRUE);
  }

  FlutterKeyEventType type;
  switch (action) {
    case 0:
      type = kFlutterKeyEventTypeUp;
      break;
    case 1:
      type = kFlutterKeyEventTypeDown;
      break;
    case 2:
      type = kFlutterKeyEventTypeRepeat;
      break;
  }

  FlutterKeyEvent event {};

  event.struct_size = sizeof(FlutterKeyEvent);
  event.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
          std::chrono::high_resolution_clock::now().time_since_epoch())
          .count();
  event.type = type;
  event.physical = scancode;
  event.logical = key;
  event.character = glfwGetKeyName(key, scancode);
  event.synthesized = true;
  event.device_type = kFlutterKeyEventDeviceTypeKeyboard;

  FlutterEngineResult r = FlutterEngineSendKeyEvent(
    reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)), 
    &event, 
    NULL, 
    NULL
  );
  std::cout << r << std::endl;
  std::cout << key << std::endl;
  std::cout << scancode << std::endl;
  std::cout << action << std::endl;
  std::cout << mods << std::endl;
  std::cout << "----------------------------------" << std::endl;
}

void GLFWwindowSizeCallback(GLFWwindow* window, int width, int height) {
  FlutterWindowMetricsEvent event = {};
  event.struct_size = sizeof(event);
  event.width = width * g_pixelRatio;
  event.height = height * g_pixelRatio;
  event.pixel_ratio = g_pixelRatio;
  event.view_id = kImplicitViewId;
  FlutterEngineSendWindowMetricsEvent(
      reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)),
      &event);
}

bool RunFlutter(GLFWwindow* window,
                const std::string& project_path,
                const std::string& icudtl_path) {
  FlutterRendererConfig config = {};
  config.type = kOpenGL;
  config.open_gl.struct_size = sizeof(config.open_gl);
  config.open_gl.make_current = [](void* userdata) -> bool {
    glfwMakeContextCurrent(static_cast<GLFWwindow*>(userdata));
    return true;
  };
  config.open_gl.clear_current = [](void*) -> bool {
    glfwMakeContextCurrent(nullptr);  // is this even a thing?
    return true;
  };
  config.open_gl.present = [](void* userdata) -> bool {
    glfwSwapBuffers(static_cast<GLFWwindow*>(userdata));
    return true;
  };
  config.open_gl.fbo_callback = [](void*) -> uint32_t {
    return 0;  // FBO0
  };
  config.open_gl.gl_proc_resolver = [](void*, const char* name) -> void* {
    return reinterpret_cast<void*>(glfwGetProcAddress(name));
  };

  // This directory is generated by `flutter build bundle`.
  std::string assets_path = project_path + "/build/flutter_assets";
  FlutterProjectArgs args = {
      .struct_size = sizeof(FlutterProjectArgs),
      .assets_path = assets_path.c_str(),
      .icu_data_path =
          icudtl_path.c_str(),  // Find this in your bin/cache directory.
  };
  FlutterEngine engine = nullptr;
  FlutterEngineResult result =
      FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config,  // renderer
                       &args, window, &engine);
  if (result != kSuccess || engine == nullptr) {
    std::cout << "Could not run the Flutter Engine." << std::endl;
    return false;
  }

  glfwSetWindowUserPointer(window, engine);
  GLFWwindowSizeCallback(window, kInitialWindowWidth, kInitialWindowHeight);

  return true;
}

void GLFW_ErrorCallback(int error, const char* description) {
  std::cout << "GLFW Error: (" << error << ") " << description << std::endl;
}

int main(int argc, const char* argv[]) {
  std::string project_path = "./demo";
#ifdef _WIN32
  std::string icudtl_path = "./data/windows/icudtl.dat";
#else
  std::string icudtl_path = "./data/linux/icudtl.dat";
#endif

  glfwSetErrorCallback(GLFW_ErrorCallback);

  int result = glfwInit();
  if (result != GLFW_TRUE) {
    std::cout << "Could not initialize GLFW." << std::endl;
    return EXIT_FAILURE;
  }

  glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
  glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);

  GLFWwindow* window = glfwCreateWindow(
      kInitialWindowWidth, kInitialWindowHeight, "Flutter", NULL, NULL);
  if (window == nullptr) {
    std::cout << "Could not create GLFW window." << std::endl;
    return EXIT_FAILURE;
  }

  int framebuffer_width, framebuffer_height;
  glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height);
  g_pixelRatio = framebuffer_width / kInitialWindowWidth;

  bool run_result = RunFlutter(window, project_path, icudtl_path);
  if (!run_result) {
    std::cout << "Could not run the Flutter engine." << std::endl;
    return EXIT_FAILURE;
  }

  glfwSetKeyCallback(window, GLFWKeyCallback);
  glfwSetWindowSizeCallback(window, GLFWwindowSizeCallback);
  glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);

  while (!glfwWindowShouldClose(window)) {
    glfwWaitEvents();
  }
  glfwDestroyWindow(window);
  glfwTerminate();

  return EXIT_SUCCESS;
}

```

</details>


### Screenshots or Video

<details open>
<summary>Screenshots / Video demonstration</summary>


https://github.com/user-attachments/assets/bcf2dc69-ebde-4fc3-bc72-759de4c7cf4f

</details>


### Logs

<details open><summary>Logs</summary>

```console
```

</details>


### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
[✓] Flutter (Channel stable, 3.24.2, on Arch Linux 6.10.9-zen1-2-zen, locale zh_CN.UTF-8)
    • Flutter version 3.24.2 on channel stable at /home/coder2/flutter/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 4cf269e36d (9 天前), 2024-09-03 14:30:00 -0700
    • Engine revision a6bd3f1de1
    • Dart version 3.5.2
    • DevTools version 2.37.2

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/to/linux-android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.


[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Linux toolchain - develop for Linux desktop
    • clang version 18.1.8
    • cmake version 3.30.3
    • ninja version 1.12.1
    • pkg-config version 2.1.1

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/to/linux-android-setup for detailed instructions).

[✓] IntelliJ IDEA Community Edition (version 2024.1)
    • IntelliJ at /home/coder2/idea-IC-241.14494.240
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[!] Proxy Configuration
    • HTTP_PROXY is set
    ! NO_PROXY is not set

[✓] Connected device (1 available)
    • Linux (desktop) • linux • linux-x64 • Arch Linux 6.10.9-zen1-2-zen

[✓] Network resources
    • All expected network resources are available.

(The demo is used for embedding into Minecraft, so I didn't install the android and chrome toolchains)
```

</details>