Skip to content

Commit

Permalink
[glfw] Send the glfw key data to the framework. (flutter#9386)
Browse files Browse the repository at this point in the history
  • Loading branch information
franciscojma86 authored Aug 20, 2019
1 parent c43739b commit a79a31a
Showing 1 changed file with 93 additions and 2 deletions.
95 changes: 93 additions & 2 deletions shell/platform/glfw/key_event_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,95 @@ static constexpr char kChannelName[] = "flutter/keyevent";

static constexpr char kKeyCodeKey[] = "keyCode";
static constexpr char kKeyMapKey[] = "keymap";
static constexpr char kScanCodeKey[] = "scanCode";
static constexpr char kModifiersKey[] = "modifiers";
static constexpr char kTypeKey[] = "type";
static constexpr char kToolkitKey[] = "toolkit";
static constexpr char kUnicodeScalarValues[] = "unicodeScalarValues";

static constexpr char kLinuxKeyMap[] = "linux";
static constexpr char kGLFWKey[] = "glfw";

static constexpr char kAndroidKeyMap[] = "android";
static constexpr char kKeyUp[] = "keyup";
static constexpr char kKeyDown[] = "keydown";

// Masks used for UTF-8 to UTF-32 conversion.
static constexpr int kTwoByteMask = 0xC0;
static constexpr int kThreeByteMask = 0xE0;
static constexpr int kFourByteMask = 0xF0;

namespace flutter {

namespace {

// Information about the UTF-8 encoded code point.
struct UTF8CodePointInfo {
// The bit-mask that determines the length of the code point.
int first_byte_mask;
// The number of bytes of the code point.
size_t length;
};

// Creates a [UTF8CodePointInfo] from a given byte. [first_byte] must be the
// first byte in the code point.
UTF8CodePointInfo GetUTF8CodePointInfo(int first_byte) {
UTF8CodePointInfo byte_info;

// The order matters. Otherwise, it is possible that comparing against i.e.
// kThreeByteMask and kFourByteMask could be both true.
if ((first_byte & kFourByteMask) == kFourByteMask) {
byte_info.first_byte_mask = 0x07;
byte_info.length = 4;
} else if ((first_byte & kThreeByteMask) == kThreeByteMask) {
byte_info.first_byte_mask = 0x0F;
byte_info.length = 3;
} else if ((first_byte & kTwoByteMask) == kTwoByteMask) {
byte_info.first_byte_mask = 0x1F;
byte_info.length = 2;
} else {
byte_info.first_byte_mask = 0xFF;
byte_info.length = 1;
}
return byte_info;
}

// Queries GLFW for the printable key name given a [key] and [scan_code] and
// converts it to UTF-32. The Flutter framework accepts only one code point,
// therefore, only the first code point will be used. There is unlikely to be
// more than one, but there is no guarantee that it won't happen.
bool GetUTF32CodePointFromGLFWKey(int key,
int scan_code,
uint32_t* code_point) {
// Get the name of the printable key, encoded as UTF-8.
// There's a known issue with glfwGetKeyName, where users with multiple
// layouts configured on their machines, will not always return the right
// value. See: https://github.com/glfw/glfw/issues/1462
const char* utf8 = glfwGetKeyName(key, scan_code);
if (utf8 == nullptr) {
return false;
}
// The first byte determines the length of the whole code point.
const auto byte_info = GetUTF8CodePointInfo(utf8[0]);
// Tracks how many bits the current byte should shift to the left.
int shift = byte_info.length - 1;

const int complement_mask = 0x3F;
uint32_t result = 0;

size_t current_byte_index = 0;
while (current_byte_index < byte_info.length) {
const int current_byte = utf8[current_byte_index];
const int mask =
current_byte_index == 0 ? byte_info.first_byte_mask : complement_mask;
current_byte_index++;
const int bits_to_shift = 6 * shift--;
result += (current_byte & mask) << bits_to_shift;
}
*code_point = result;
return true;
}
} // namespace

KeyEventHandler::KeyEventHandler(flutter::BinaryMessenger* messenger)
: channel_(
std::make_unique<flutter::BasicMessageChannel<rapidjson::Document>>(
Expand All @@ -41,10 +122,20 @@ void KeyEventHandler::KeyboardHook(GLFWwindow* window,
rapidjson::Document event(rapidjson::kObjectType);
auto& allocator = event.GetAllocator();
event.AddMember(kKeyCodeKey, key, allocator);
event.AddMember(kKeyMapKey, kAndroidKeyMap, allocator);
event.AddMember(kKeyMapKey, kLinuxKeyMap, allocator);
event.AddMember(kScanCodeKey, scancode, allocator);
event.AddMember(kModifiersKey, mods, allocator);
event.AddMember(kToolkitKey, kGLFWKey, allocator);

uint32_t unicodeInt;
bool result = GetUTF32CodePointFromGLFWKey(key, scancode, &unicodeInt);
if (result) {
event.AddMember(kUnicodeScalarValues, unicodeInt, allocator);
}

switch (action) {
case GLFW_PRESS:
case GLFW_REPEAT:
event.AddMember(kTypeKey, kKeyDown, allocator);
break;
case GLFW_RELEASE:
Expand Down

0 comments on commit a79a31a

Please sign in to comment.