| // 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 "flutter/shell/platform/windows/keyboard_key_channel_handler.h" |
| |
| #include <windows.h> |
| |
| #include "flutter/fml/logging.h" |
| #include "flutter/shell/platform/common/json_message_codec.h" |
| #include "flutter/shell/platform/windows/keyboard_utils.h" |
| |
| namespace flutter { |
| |
| namespace { |
| |
| static constexpr char kChannelName[] = "flutter/keyevent"; |
| |
| static constexpr char kKeyCodeKey[] = "keyCode"; |
| static constexpr char kScanCodeKey[] = "scanCode"; |
| static constexpr char kCharacterCodePointKey[] = "characterCodePoint"; |
| static constexpr char kModifiersKey[] = "modifiers"; |
| static constexpr char kKeyMapKey[] = "keymap"; |
| static constexpr char kTypeKey[] = "type"; |
| static constexpr char kHandledKey[] = "handled"; |
| |
| static constexpr char kWindowsKeyMap[] = "windows"; |
| static constexpr char kKeyUp[] = "keyup"; |
| static constexpr char kKeyDown[] = "keydown"; |
| |
| // The maximum number of pending events to keep before |
| // emitting a warning on the console about unhandled events. |
| static constexpr int kMaxPendingEvents = 1000; |
| |
| // The bit for a scancode indicating the key is extended. |
| // |
| // Win32 defines some keys to be "extended", such as ShiftRight, which shares |
| // the same scancode as its non-extended counterpart, such as ShiftLeft. In |
| // Chromium's scancode table, from which Flutter's physical key list is |
| // derived, these keys are marked with this bit. See |
| // https://chromium.googlesource.com/codesearch/chromium/src/+/refs/heads/main/ui/events/keycodes/dom/dom_code_data.inc |
| static constexpr int kScancodeExtended = 0xe000; |
| |
| // Re-definition of the modifiers for compatibility with the Flutter framework. |
| // These have to be in sync with the framework's RawKeyEventDataWindows |
| // modifiers definition. |
| // https://github.com/flutter/flutter/blob/19ff596979e407c484a32f4071420fca4f4c885f/packages/flutter/lib/src/services/raw_keyboard_windows.dart#L203 |
| static constexpr int kShift = 1 << 0; |
| static constexpr int kShiftLeft = 1 << 1; |
| static constexpr int kShiftRight = 1 << 2; |
| static constexpr int kControl = 1 << 3; |
| static constexpr int kControlLeft = 1 << 4; |
| static constexpr int kControlRight = 1 << 5; |
| static constexpr int kAlt = 1 << 6; |
| static constexpr int kAltLeft = 1 << 7; |
| static constexpr int kAltRight = 1 << 8; |
| static constexpr int kWinLeft = 1 << 9; |
| static constexpr int kWinRight = 1 << 10; |
| static constexpr int kCapsLock = 1 << 11; |
| static constexpr int kNumLock = 1 << 12; |
| static constexpr int kScrollLock = 1 << 13; |
| |
| /// Calls GetKeyState() an all modifier keys and packs the result in an int, |
| /// with the re-defined values declared above for compatibility with the Flutter |
| /// framework. |
| int GetModsForKeyState() { |
| int mods = 0; |
| |
| if (GetKeyState(VK_SHIFT) < 0) |
| mods |= kShift; |
| if (GetKeyState(VK_LSHIFT) < 0) |
| mods |= kShiftLeft; |
| if (GetKeyState(VK_RSHIFT) < 0) |
| mods |= kShiftRight; |
| if (GetKeyState(VK_CONTROL) < 0) |
| mods |= kControl; |
| if (GetKeyState(VK_LCONTROL) < 0) |
| mods |= kControlLeft; |
| if (GetKeyState(VK_RCONTROL) < 0) |
| mods |= kControlRight; |
| if (GetKeyState(VK_MENU) < 0) |
| mods |= kAlt; |
| if (GetKeyState(VK_LMENU) < 0) |
| mods |= kAltLeft; |
| if (GetKeyState(VK_RMENU) < 0) |
| mods |= kAltRight; |
| if (GetKeyState(VK_LWIN) < 0) |
| mods |= kWinLeft; |
| if (GetKeyState(VK_RWIN) < 0) |
| mods |= kWinRight; |
| if (GetKeyState(VK_CAPITAL) < 0) |
| mods |= kCapsLock; |
| if (GetKeyState(VK_NUMLOCK) < 0) |
| mods |= kNumLock; |
| if (GetKeyState(VK_SCROLL) < 0) |
| mods |= kScrollLock; |
| return mods; |
| } |
| |
| } // namespace |
| |
| KeyboardKeyChannelHandler::KeyboardKeyChannelHandler( |
| flutter::BinaryMessenger* messenger) |
| : channel_( |
| std::make_unique<flutter::BasicMessageChannel<rapidjson::Document>>( |
| messenger, |
| kChannelName, |
| &flutter::JsonMessageCodec::GetInstance())) {} |
| |
| KeyboardKeyChannelHandler::~KeyboardKeyChannelHandler() = default; |
| |
| void KeyboardKeyChannelHandler::SyncModifiersIfNeeded(int modifiers_state) { |
| // Do nothing |
| } |
| |
| void KeyboardKeyChannelHandler::KeyboardHook( |
| int key, |
| int scancode, |
| int action, |
| char32_t character, |
| bool extended, |
| bool was_down, |
| std::function<void(bool)> callback) { |
| // TODO: Translate to a cross-platform key code system rather than passing |
| // the native key code. |
| rapidjson::Document event(rapidjson::kObjectType); |
| auto& allocator = event.GetAllocator(); |
| event.AddMember(kKeyCodeKey, key, allocator); |
| event.AddMember(kScanCodeKey, scancode | (extended ? kScancodeExtended : 0), |
| allocator); |
| event.AddMember(kCharacterCodePointKey, UndeadChar(character), allocator); |
| event.AddMember(kKeyMapKey, kWindowsKeyMap, allocator); |
| event.AddMember(kModifiersKey, GetModsForKeyState(), allocator); |
| |
| switch (action) { |
| case WM_SYSKEYDOWN: |
| case WM_KEYDOWN: |
| event.AddMember(kTypeKey, kKeyDown, allocator); |
| break; |
| case WM_SYSKEYUP: |
| case WM_KEYUP: |
| event.AddMember(kTypeKey, kKeyUp, allocator); |
| break; |
| default: |
| FML_LOG(WARNING) << "Unknown key event action: " << action; |
| callback(false); |
| return; |
| } |
| channel_->Send(event, [callback = std::move(callback)](const uint8_t* reply, |
| size_t reply_size) { |
| auto decoded = flutter::JsonMessageCodec::GetInstance().DecodeMessage( |
| reply, reply_size); |
| bool handled = decoded ? (*decoded)[kHandledKey].GetBool() : false; |
| callback(handled); |
| }); |
| } |
| |
| } // namespace flutter |