Flutter Engine
The 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/json_message_codec.h"
10
11static constexpr char kChannelName[] = "flutter/keyevent";
12
13static constexpr char kKeyCodeKey[] = "keyCode";
14static constexpr char kKeyMapKey[] = "keymap";
15static constexpr char kScanCodeKey[] = "scanCode";
16static constexpr char kModifiersKey[] = "modifiers";
17static constexpr char kTypeKey[] = "type";
18static constexpr char kToolkitKey[] = "toolkit";
19static constexpr char kUnicodeScalarValues[] = "unicodeScalarValues";
20
21static constexpr char kLinuxKeyMap[] = "linux";
22static constexpr char kGLFWKey[] = "glfw";
23
24static constexpr char kKeyUp[] = "keyup";
25static constexpr char kKeyDown[] = "keydown";
26
27// Masks used for UTF-8 to UTF-32 conversion.
28static constexpr int kTwoByteMask = 0xC0;
29static constexpr int kThreeByteMask = 0xE0;
30static constexpr int kFourByteMask = 0xF0;
31
32namespace flutter {
33
34namespace {
35
36// Information about the UTF-8 encoded code point.
37struct 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.
46UTF8CodePointInfo 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.
71bool 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,
109 &flutter::JsonMessageCodec::GetInstance())) {}
110
112
113void KeyEventHandler::CharHook(GLFWwindow* window, unsigned int code_point) {}
114
116 int key,
117 int scancode,
118 int action,
119 int mods) {
120 // TODO(chrome-bot): Translate to a cross-platform key code system rather than
121 // passing the native key code.
122 // NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
123 rapidjson::Document event(rapidjson::kObjectType);
124 auto& allocator = event.GetAllocator();
125 event.AddMember(kKeyCodeKey, key, allocator);
126 event.AddMember(kKeyMapKey, kLinuxKeyMap, allocator);
127 event.AddMember(kScanCodeKey, scancode, allocator);
128 event.AddMember(kModifiersKey, mods, allocator);
129 event.AddMember(kToolkitKey, kGLFWKey, allocator);
130
131 uint32_t unicodeInt;
132 bool result = GetUTF32CodePointFromGLFWKey(key, scancode, &unicodeInt);
133 if (result) {
134 event.AddMember(kUnicodeScalarValues, unicodeInt, allocator);
135 }
136
137 switch (action) {
138 case GLFW_PRESS:
139 case GLFW_REPEAT:
140 event.AddMember(kTypeKey, kKeyDown, allocator);
141 break;
142 case GLFW_RELEASE:
143 event.AddMember(kTypeKey, kKeyUp, allocator);
144 break;
145 default:
146 std::cerr << "Unknown key event action: " << action << std::endl;
147 return;
148 }
149 channel_->Send(event);
150}
151
152} // namespace flutter
KeyEventHandler(flutter::BinaryMessenger *messenger)
void CharHook(GLFWwindow *window, unsigned int code_point) override
void KeyboardHook(GLFWwindow *window, int key, int scancode, int action, int mods) override
GLFWwindow * window
Definition: main.cc:45
FlKeyEvent * event
GAsyncResult * result
static constexpr char kScanCodeKey[]
static constexpr int kFourByteMask
static constexpr char kKeyMapKey[]
static constexpr char kToolkitKey[]
static constexpr char kTypeKey[]
static constexpr char kGLFWKey[]
static constexpr char kKeyDown[]
static constexpr char kLinuxKeyMap[]
static constexpr char kChannelName[]
static constexpr char kKeyUp[]
static constexpr char kModifiersKey[]
static constexpr int kTwoByteMask
int first_byte_mask
static constexpr int kThreeByteMask
static constexpr char kUnicodeScalarValues[]
static constexpr char kKeyCodeKey[]
size_t length
constexpr char kTypeKey[]
Definition: shell.cc:50
Definition: ref_ptr.h:256