5#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
12#include "flutter/fml/logging.h"
13#include "flutter/shell/platform/windows/keyboard_utils.h"
22constexpr size_t kCharacterCacheSize = 8;
24constexpr SHORT kStateMaskToggled = 0x01;
25constexpr SHORT kStateMaskPressed = 0x80;
27const char* empty_character =
"";
33char _GetBit(
char32_t ch,
size_t start,
size_t end) {
34 return (ch >> end) & ((1 << (
start -
end)) - 1);
40 FML_DCHECK(0 <= ch && ch <= 0x10FFFF) <<
"Character out of range";
43 }
else if (ch <= 0x07FF) {
44 result.push_back(0b11000000 + _GetBit(ch, 11, 6));
45 result.push_back(0b10000000 + _GetBit(ch, 6, 0));
46 }
else if (ch <= 0xFFFF) {
47 result.push_back(0b11100000 + _GetBit(ch, 16, 12));
48 result.push_back(0b10000000 + _GetBit(ch, 12, 6));
49 result.push_back(0b10000000 + _GetBit(ch, 6, 0));
51 result.push_back(0b11110000 + _GetBit(ch, 21, 18));
52 result.push_back(0b10000000 + _GetBit(ch, 18, 12));
53 result.push_back(0b10000000 + _GetBit(ch, 12, 6));
54 result.push_back(0b10000000 + _GetBit(ch, 6, 0));
63 : perform_send_event_(send_event),
64 get_key_state_(get_key_state),
66 InitCriticalKeys(map_virtual_key_to_scan_code);
72 return (codeUnit <= 0x7f && codeUnit >= 0x20) ||
73 (codeUnit <= 0xff && codeUnit >= 0x80);
81 constexpr uint64_t lower_a = 0x61;
82 constexpr uint64_t upper_a = 0x41;
83 constexpr uint64_t upper_z = 0x5a;
85 constexpr uint64_t lower_a_grave = 0xe0;
86 constexpr uint64_t upper_a_grave = 0xc0;
87 constexpr uint64_t upper_thorn = 0xde;
88 constexpr uint64_t division = 0xf7;
91 if (n >= upper_a && n <= upper_z) {
92 return n - upper_a + lower_a;
96 if (n >= upper_a_grave && n <= upper_thorn && n != division) {
97 return n - upper_a_grave + lower_a_grave;
107 return (windowsScanCode & 0xff) | (
extended ? 0xe000 : 0);
110uint64_t KeyboardKeyEmbedderHandler::ApplyPlaneToId(uint64_t
id,
112 return (
id & valueMask) | plane;
115uint64_t KeyboardKeyEmbedderHandler::GetPhysicalKey(
int scancode,
118 auto resultIt = windowsToPhysicalMap_.find(chromiumScancode);
119 if (resultIt != windowsToPhysicalMap_.end())
120 return resultIt->second;
121 return ApplyPlaneToId(
scancode, windowsPlane);
124uint64_t KeyboardKeyEmbedderHandler::GetLogicalKey(
int key,
127 if (
key == VK_PROCESSKEY) {
128 return VK_PROCESSKEY;
136 if (numpadIter != scanCodeToLogicalMap_.cend())
137 return numpadIter->second;
140 auto logicalIt = windowsToLogicalMap_.find(
key);
141 if (logicalIt != windowsToLogicalMap_.cend())
142 return logicalIt->second;
146 return ApplyPlaneToId(
toLower(
key), unicodePlane);
149 return ApplyPlaneToId(
toLower(
key), windowsPlane);
152void KeyboardKeyEmbedderHandler::KeyboardHookImpl(
165 auto last_logical_record_iter = pressingRecords_.find(physical_key);
166 bool had_record = last_logical_record_iter != pressingRecords_.end();
167 uint64_t last_logical_record =
168 had_record ? last_logical_record_iter->second : 0;
174 uint64_t sequence_logical_key =
175 had_record ? last_logical_record : logical_key;
177 if (sequence_logical_key == VK_PROCESSKEY) {
186 const bool is_event_down =
action == WM_KEYDOWN ||
action == WM_SYSKEYDOWN;
188 bool event_key_can_be_repeat =
true;
189 UpdateLastSeenCriticalKey(
key, physical_key, sequence_logical_key);
201 SynchronizeCriticalToggledStates(
key, is_event_down,
202 &event_key_can_be_repeat);
209 SynchronizeCriticalPressedStates(
key, physical_key, is_event_down,
210 event_key_can_be_repeat);
214 last_logical_record_iter = pressingRecords_.find(physical_key);
215 had_record = last_logical_record_iter != pressingRecords_.end();
216 last_logical_record = had_record ? last_logical_record_iter->second : 0;
221 char character_bytes[kCharacterCacheSize];
224 uint64_t eventual_logical_record;
225 uint64_t result_logical_key;
233 ConvertUtf32ToUtf8_(character_bytes,
character);
234 eventual_logical_record = last_logical_record;
235 result_logical_key = last_logical_record;
248 ConvertUtf32ToUtf8_(character_bytes,
character);
249 eventual_logical_record = logical_key;
250 result_logical_key = logical_key;
253 if (last_logical_record == 0) {
264 character_bytes[0] =
'\0';
265 eventual_logical_record = 0;
266 result_logical_key = last_logical_record;
270 if (eventual_logical_record != 0) {
271 pressingRecords_[physical_key] = eventual_logical_record;
273 auto record_iter = pressingRecords_.find(physical_key);
277 if (record_iter != pressingRecords_.end()) {
278 pressingRecords_.erase(record_iter);
286 .timestamp =
static_cast<double>(
287 std::chrono::duration_cast<std::chrono::microseconds>(
288 std::chrono::high_resolution_clock::now().time_since_epoch())
291 .physical = physical_key,
292 .logical = result_logical_key,
294 .synthesized =
false,
298 uint64_t response_id = response_id_;
299 PendingResponse pending{
302 uint64_t response_id) {
303 auto found = pending_responses_.find(response_id);
304 if (found != pending_responses_.end()) {
305 pending_responses_.erase(found);
309 .response_id = response_id,
311 auto pending_ptr = std::make_unique<PendingResponse>(std::move(pending));
312 pending_responses_[response_id] = std::move(pending_ptr);
313 SendEvent(key_data, KeyboardKeyEmbedderHandler::HandleResponse,
314 reinterpret_cast<void*
>(pending_responses_[response_id].
get()));
321 SynchronizeCriticalPressedStates(
key, physical_key, is_event_down,
322 event_key_can_be_repeat);
333 sent_any_events =
false;
336 if (!sent_any_events) {
339 .timestamp =
static_cast<double>(
340 std::chrono::duration_cast<std::chrono::microseconds>(
341 std::chrono::high_resolution_clock::now().time_since_epoch())
347 .synthesized =
false,
349 SendEvent(empty_event,
nullptr,
nullptr);
354 return pressingRecords_;
357void KeyboardKeyEmbedderHandler::UpdateLastSeenCriticalKey(
359 uint64_t physical_key,
360 uint64_t logical_key) {
361 auto found = critical_keys_.find(virtual_key);
362 if (found != critical_keys_.end()) {
363 found->second.physical_key = physical_key;
364 found->second.logical_key = logical_key;
368void KeyboardKeyEmbedderHandler::SynchronizeCriticalToggledStates(
369 int event_virtual_key,
371 bool* event_key_can_be_repeat) {
374 for (
auto& kv : critical_keys_) {
375 UINT virtual_key = kv.first;
376 CriticalKey& key_info = kv.second;
377 if (key_info.physical_key == 0) {
384 if (key_info.check_toggled) {
385 const bool target_is_pressed =
386 pressingRecords_.find(key_info.physical_key) !=
387 pressingRecords_.end();
394 const bool true_toggled = get_key_state_(virtual_key) & kStateMaskToggled;
395 bool pre_event_toggled = true_toggled;
398 if (virtual_key == event_virtual_key && !target_is_pressed &&
400 pre_event_toggled = !pre_event_toggled;
402 if (key_info.toggled_on != pre_event_toggled) {
404 if (target_is_pressed) {
405 SendEvent(SynthesizeSimpleEvent(
407 key_info.logical_key, empty_character),
411 pressingRecords_[key_info.physical_key] = key_info.logical_key;
413 key_info.physical_key,
414 key_info.logical_key, empty_character),
416 *event_key_can_be_repeat =
false;
418 key_info.toggled_on = true_toggled;
423void KeyboardKeyEmbedderHandler::SynchronizeCriticalPressedStates(
424 int event_virtual_key,
425 int event_physical_key,
427 bool event_key_can_be_repeat) {
439 for (
auto& kv : critical_keys_) {
440 UINT virtual_key = kv.first;
441 CriticalKey& key_info = kv.second;
442 if (key_info.physical_key == 0) {
447 if (key_info.check_pressed) {
448 SHORT true_pressed = get_key_state_(virtual_key) & kStateMaskPressed;
449 auto pressing_record_iter = pressingRecords_.find(key_info.physical_key);
450 bool now_pressed = pressing_record_iter != pressingRecords_.end();
451 bool pre_event_pressed = true_pressed;
463 if (virtual_key == event_virtual_key) {
464 if (event_key_can_be_repeat) {
467 pre_event_pressed =
false;
479 if (event_physical_key == key_info.physical_key) {
483 if (now_pressed != pre_event_pressed) {
485 pressingRecords_.erase(pressing_record_iter);
487 pressingRecords_[key_info.physical_key] = key_info.logical_key;
489 const char* empty_character =
"";
491 SynthesizeSimpleEvent(
493 key_info.physical_key, key_info.logical_key, empty_character),
502 const uint64_t physical_shift_left =
504 const uint64_t physical_shift_right =
506 const uint64_t logical_shift_left =
508 const uint64_t physical_control_left =
510 const uint64_t physical_control_right =
512 const uint64_t logical_control_left =
515 bool shift_pressed = (modifiers_state &
kShift) != 0;
516 SynthesizeIfNeeded(physical_shift_left, physical_shift_right,
517 logical_shift_left, shift_pressed);
518 bool control_pressed = (modifiers_state &
kControl) != 0;
519 SynthesizeIfNeeded(physical_control_left, physical_control_right,
520 logical_control_left, control_pressed);
523void KeyboardKeyEmbedderHandler::SynthesizeIfNeeded(uint64_t physical_left,
524 uint64_t physical_right,
525 uint64_t logical_left,
527 auto pressing_record_iter_left = pressingRecords_.find(physical_left);
528 bool left_pressed = pressing_record_iter_left != pressingRecords_.end();
529 auto pressing_record_iter_right = pressingRecords_.find(physical_right);
530 bool right_pressed = pressing_record_iter_right != pressingRecords_.end();
531 bool already_pressed = left_pressed || right_pressed;
532 bool synthesize_down = is_pressed && !already_pressed;
533 bool synthesize_up = !is_pressed && already_pressed;
535 if (synthesize_down) {
536 SendSynthesizeDownEvent(physical_left, logical_left);
539 if (synthesize_up && left_pressed) {
540 uint64_t known_logical = pressing_record_iter_left->second;
541 SendSynthesizeUpEvent(physical_left, known_logical);
544 if (synthesize_up && right_pressed) {
545 uint64_t known_logical = pressing_record_iter_right->second;
546 SendSynthesizeUpEvent(physical_right, known_logical);
550void KeyboardKeyEmbedderHandler::SendSynthesizeDownEvent(uint64_t physical,
555 pressingRecords_[physical] = logical;
558void KeyboardKeyEmbedderHandler::SendSynthesizeUpEvent(uint64_t physical,
563 pressingRecords_.erase(physical);
566void KeyboardKeyEmbedderHandler::HandleResponse(
bool handled,
void*
user_data) {
567 PendingResponse* pending =
reinterpret_cast<PendingResponse*
>(
user_data);
568 auto callback = std::move(pending->callback);
569 callback(handled, pending->response_id);
572void KeyboardKeyEmbedderHandler::InitCriticalKeys(
573 MapVirtualKeyToScanCode map_virtual_key_to_scan_code) {
574 auto createCheckedKey = [
this, &map_virtual_key_to_scan_code](
577 bool check_toggled) -> CriticalKey {
578 UINT scan_code = map_virtual_key_to_scan_code(virtual_key,
extended);
580 .physical_key = GetPhysicalKey(scan_code,
extended),
581 .logical_key = GetLogicalKey(virtual_key,
extended, scan_code),
582 .check_pressed = check_pressed || check_toggled,
583 .check_toggled = check_toggled,
584 .toggled_on = check_toggled
585 ? !!(get_key_state_(virtual_key) & kStateMaskToggled)
590 critical_keys_.emplace(VK_LSHIFT,
591 createCheckedKey(VK_LSHIFT,
false,
true,
false));
592 critical_keys_.emplace(VK_RSHIFT,
593 createCheckedKey(VK_RSHIFT,
false,
true,
false));
594 critical_keys_.emplace(VK_LCONTROL,
595 createCheckedKey(VK_LCONTROL,
false,
true,
false));
596 critical_keys_.emplace(VK_RCONTROL,
597 createCheckedKey(VK_RCONTROL,
true,
true,
false));
598 critical_keys_.emplace(VK_LMENU,
599 createCheckedKey(VK_LMENU,
false,
true,
false));
600 critical_keys_.emplace(VK_RMENU,
601 createCheckedKey(VK_RMENU,
true,
true,
false));
602 critical_keys_.emplace(VK_LWIN, createCheckedKey(VK_LWIN,
true,
true,
false));
603 critical_keys_.emplace(VK_RWIN, createCheckedKey(VK_RWIN,
true,
true,
false));
604 critical_keys_.emplace(VK_CAPITAL,
605 createCheckedKey(VK_CAPITAL,
false,
true,
true));
606 critical_keys_.emplace(VK_SCROLL,
607 createCheckedKey(VK_SCROLL,
false,
true,
true));
608 critical_keys_.emplace(VK_NUMLOCK,
609 createCheckedKey(VK_NUMLOCK,
true,
true,
true));
612void KeyboardKeyEmbedderHandler::ConvertUtf32ToUtf8_(
char*
out,
char32_t ch) {
618 strcpy_s(
out, kCharacterCacheSize,
result.c_str());
628 .timestamp =
static_cast<double>(
629 std::chrono::duration_cast<std::chrono::microseconds>(
630 std::chrono::high_resolution_clock::now().time_since_epoch())
633 .physical = physical,
643 sent_any_events =
true;
std::function< void(const FlutterKeyEvent &, FlutterKeyEventCallback, void *)> SendEventHandler
virtual ~KeyboardKeyEmbedderHandler()
void KeyboardHook(int key, int scancode, int action, char32_t character, bool extended, bool was_down, std::function< void(bool)> callback) override
std::function< SHORT(UINT, bool)> MapVirtualKeyToScanCode
std::map< uint64_t, uint64_t > GetPressedState() override
void SyncModifiersIfNeeded(int modifiers_state) override
KeyboardKeyEmbedderHandler(SendEventHandler send_event, GetKeyStateHandler get_key_state, MapVirtualKeyToScanCode map_vk_to_scan)
std::function< SHORT(int)> GetKeyStateHandler
void(* FlutterKeyEventCallback)(bool, void *)
@ kFlutterKeyEventTypeDown
@ kFlutterKeyEventTypeRepeat
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_DCHECK(condition)
Dart_NativeFunction function
constexpr int kKeyCodeShiftLeft
constexpr int kScanCodeShiftRight
constexpr int kScanCodeShiftLeft
constexpr int kScanCodeControlRight
std::string ConvertChar32ToUtf8(char32_t ch)
static uint16_t normalizeScancode(int windowsScanCode, bool extended)
static uint64_t toLower(uint64_t n)
static bool isEasciiPrintable(int codeUnit)
constexpr int kScanCodeControlLeft
constexpr int kKeyCodeControlLeft
uint32_t UndeadChar(uint32_t ch)
const myers::Point & get(const myers::Segment &)
size_t struct_size
The size of this struct. Must be sizeof(FlutterKeyEvent).