Flutter Engine
key_event_handler.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/shell/platform/glfw/key_event_handler.h"
6 
7 #include <iostream>
8 
9 #include "flutter/shell/platform/common/cpp/json_message_codec.h"
10 
11 static constexpr char kChannelName[] = "flutter/keyevent";
12 
13 static constexpr char kKeyCodeKey[] = "keyCode";
14 static constexpr char kKeyMapKey[] = "keymap";
15 static constexpr char kScanCodeKey[] = "scanCode";
16 static constexpr char kModifiersKey[] = "modifiers";
17 static constexpr char kTypeKey[] = "type";
18 static constexpr char kToolkitKey[] = "toolkit";
19 static constexpr char kUnicodeScalarValues[] = "unicodeScalarValues";
20 
21 static constexpr char kLinuxKeyMap[] = "linux";
22 static constexpr char kGLFWKey[] = "glfw";
23 
24 static constexpr char kKeyUp[] = "keyup";
25 static constexpr char kKeyDown[] = "keydown";
26 
27 // Masks used for UTF-8 to UTF-32 conversion.
28 static constexpr int kTwoByteMask = 0xC0;
29 static constexpr int kThreeByteMask = 0xE0;
30 static constexpr int kFourByteMask = 0xF0;
31 
32 namespace flutter {
33 
34 namespace {
35 
36 // Information about the UTF-8 encoded code point.
37 struct UTF8CodePointInfo {
38  // The bit-mask that determines the length of the code point.
40  // The number of bytes of the code point.
41  size_t length;
42 };
43 
44 // Creates a [UTF8CodePointInfo] from a given byte. [first_byte] must be the
45 // first byte in the code point.
46 UTF8CodePointInfo GetUTF8CodePointInfo(int first_byte) {
47  UTF8CodePointInfo byte_info;
48 
49  // The order matters. Otherwise, it is possible that comparing against i.e.
50  // kThreeByteMask and kFourByteMask could be both true.
51  if ((first_byte & kFourByteMask) == kFourByteMask) {
52  byte_info.first_byte_mask = 0x07;
53  byte_info.length = 4;
54  } else if ((first_byte & kThreeByteMask) == kThreeByteMask) {
55  byte_info.first_byte_mask = 0x0F;
56  byte_info.length = 3;
57  } else if ((first_byte & kTwoByteMask) == kTwoByteMask) {
58  byte_info.first_byte_mask = 0x1F;
59  byte_info.length = 2;
60  } else {
61  byte_info.first_byte_mask = 0xFF;
62  byte_info.length = 1;
63  }
64  return byte_info;
65 }
66 
67 // Queries GLFW for the printable key name given a [key] and [scan_code] and
68 // converts it to UTF-32. The Flutter framework accepts only one code point,
69 // therefore, only the first code point will be used. There is unlikely to be
70 // more than one, but there is no guarantee that it won't happen.
71 bool GetUTF32CodePointFromGLFWKey(int key,
72  int scan_code,
73  uint32_t* code_point) {
74  // Get the name of the printable key, encoded as UTF-8.
75  // There's a known issue with glfwGetKeyName, where users with multiple
76  // layouts configured on their machines, will not always return the right
77  // value. See: https://github.com/glfw/glfw/issues/1462
78  const char* utf8 = glfwGetKeyName(key, scan_code);
79  if (utf8 == nullptr) {
80  return false;
81  }
82  // The first byte determines the length of the whole code point.
83  const auto byte_info = GetUTF8CodePointInfo(utf8[0]);
84  // Tracks how many bits the current byte should shift to the left.
85  int shift = byte_info.length - 1;
86 
87  const int complement_mask = 0x3F;
88  uint32_t result = 0;
89 
90  size_t current_byte_index = 0;
91  while (current_byte_index < byte_info.length) {
92  const int current_byte = utf8[current_byte_index];
93  const int mask =
94  current_byte_index == 0 ? byte_info.first_byte_mask : complement_mask;
95  current_byte_index++;
96  const int bits_to_shift = 6 * shift--;
97  result += (current_byte & mask) << bits_to_shift;
98  }
99  *code_point = result;
100  return true;
101 }
102 } // namespace
103 
105  : channel_(
106  std::make_unique<flutter::BasicMessageChannel<rapidjson::Document>>(
107  messenger,
108  kChannelName,
109  &flutter::JsonMessageCodec::GetInstance())) {}
110 
112 
113 void KeyEventHandler::CharHook(GLFWwindow* window, unsigned int code_point) {}
114 
115 void KeyEventHandler::KeyboardHook(GLFWwindow* window,
116  int key,
117  int scancode,
118  int action,
119  int mods) {
120  // TODO: Translate to a cross-platform key code system rather than passing
121  // the native key code.
122  rapidjson::Document event(rapidjson::kObjectType);
123  auto& allocator = event.GetAllocator();
124  event.AddMember(kKeyCodeKey, key, allocator);
125  event.AddMember(kKeyMapKey, kLinuxKeyMap, allocator);
126  event.AddMember(kScanCodeKey, scancode, allocator);
127  event.AddMember(kModifiersKey, mods, allocator);
128  event.AddMember(kToolkitKey, kGLFWKey, allocator);
129 
130  uint32_t unicodeInt;
131  bool result = GetUTF32CodePointFromGLFWKey(key, scancode, &unicodeInt);
132  if (result) {
133  event.AddMember(kUnicodeScalarValues, unicodeInt, allocator);
134  }
135 
136  switch (action) {
137  case GLFW_PRESS:
138  case GLFW_REPEAT:
139  event.AddMember(kTypeKey, kKeyDown, allocator);
140  break;
141  case GLFW_RELEASE:
142  event.AddMember(kTypeKey, kKeyUp, allocator);
143  break;
144  default:
145  std::cerr << "Unknown key event action: " << action << std::endl;
146  return;
147  }
148  channel_->Send(event);
149 }
150 
151 } // namespace flutter
static constexpr char kLinuxKeyMap[]
void CharHook(GLFWwindow *window, unsigned int code_point) override
static constexpr char kScanCodeKey[]
static constexpr int kFourByteMask
static constexpr char kKeyMapKey[]
static constexpr char kKeyCodeKey[]
Definition: ref_ptr.h:252
static constexpr char kUnicodeScalarValues[]
static constexpr char kToolkitKey[]
SemanticsAction action
size_t length
GdkEventButton * event
Definition: fl_view.cc:62
int first_byte_mask
static constexpr char kChannelName[]
static constexpr char kTypeKey[]
void KeyboardHook(GLFWwindow *window, int key, int scancode, int action, int mods) override
static constexpr int kThreeByteMask
static constexpr char kKeyDown[]
static constexpr int kTwoByteMask
static constexpr char kModifiersKey[]
KeyEventHandler(flutter::BinaryMessenger *messenger)
static constexpr char kGLFWKey[]
constexpr char kTypeKey[]
Definition: shell.cc:39
static constexpr char kKeyUp[]