wayland_keyboard_delegate.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2018 The Chromium 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. #include "components/exo/wayland/wayland_keyboard_delegate.h"
  5. #include <cstring>
  6. #include <wayland-server-core.h>
  7. #include <wayland-server-protocol-core.h>
  8. #include "base/containers/flat_map.h"
  9. #include "base/memory/unsafe_shared_memory_region.h"
  10. #include "base/numerics/safe_conversions.h"
  11. #include "components/exo/wayland/serial_tracker.h"
  12. #include "ui/events/keycodes/dom/dom_code.h"
  13. #include "ui/events/keycodes/dom/keycode_converter.h"
  14. #if BUILDFLAG(USE_XKBCOMMON)
  15. #include <xkbcommon/xkbcommon.h>
  16. #endif
  17. namespace exo {
  18. namespace wayland {
  19. #if BUILDFLAG(USE_XKBCOMMON)
  20. WaylandKeyboardDelegate::WaylandKeyboardDelegate(wl_resource* keyboard_resource,
  21. SerialTracker* serial_tracker)
  22. : keyboard_resource_(keyboard_resource), serial_tracker_(serial_tracker) {}
  23. WaylandKeyboardDelegate::~WaylandKeyboardDelegate() = default;
  24. bool WaylandKeyboardDelegate::CanAcceptKeyboardEventsForSurface(
  25. Surface* surface) const {
  26. wl_resource* surface_resource = GetSurfaceResource(surface);
  27. // We can accept events for this surface if the client is the same as the
  28. // keyboard.
  29. return surface_resource &&
  30. wl_resource_get_client(surface_resource) == client();
  31. }
  32. void WaylandKeyboardDelegate::OnKeyboardEnter(
  33. Surface* surface,
  34. const base::flat_map<ui::DomCode, KeyState>& pressed_keys) {
  35. wl_resource* surface_resource = GetSurfaceResource(surface);
  36. DCHECK(surface_resource);
  37. wl_array keys;
  38. wl_array_init(&keys);
  39. for (const auto& entry : pressed_keys) {
  40. uint32_t* value =
  41. static_cast<uint32_t*>(wl_array_add(&keys, sizeof(uint32_t)));
  42. DCHECK(value);
  43. *value = ui::KeycodeConverter::DomCodeToEvdevCode(entry.second.code);
  44. }
  45. wl_keyboard_send_enter(
  46. keyboard_resource_,
  47. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  48. surface_resource, &keys);
  49. wl_array_release(&keys);
  50. wl_client_flush(client());
  51. }
  52. void WaylandKeyboardDelegate::OnKeyboardLeave(Surface* surface) {
  53. wl_resource* surface_resource = GetSurfaceResource(surface);
  54. DCHECK(surface_resource);
  55. wl_keyboard_send_leave(
  56. keyboard_resource_,
  57. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  58. surface_resource);
  59. wl_client_flush(client());
  60. }
  61. uint32_t WaylandKeyboardDelegate::OnKeyboardKey(base::TimeTicks time_stamp,
  62. ui::DomCode code,
  63. bool pressed) {
  64. uint32_t serial = serial_tracker_->MaybeNextKeySerial();
  65. serial_tracker_->ResetKeySerial();
  66. SendTimestamp(time_stamp);
  67. wl_keyboard_send_key(
  68. keyboard_resource_, serial, TimeTicksToMilliseconds(time_stamp),
  69. ui::KeycodeConverter::DomCodeToEvdevCode(code),
  70. pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED);
  71. // Unlike normal wayland clients, the X11 server tries to maintain its own
  72. // modifier state, which it updates based on key events. To prevent numlock
  73. // presses from allowing numpad keys to be interpreted as directions, we
  74. // re-send the modifier state after a numlock press.
  75. if (code == ui::DomCode::NUM_LOCK)
  76. SendKeyboardModifiers();
  77. wl_client_flush(client());
  78. return serial;
  79. }
  80. void WaylandKeyboardDelegate::OnKeyboardModifiers(
  81. const KeyboardModifiers& modifiers) {
  82. // Send the update only when they're different.
  83. if (current_modifiers_ == modifiers)
  84. return;
  85. current_modifiers_ = modifiers;
  86. SendKeyboardModifiers();
  87. }
  88. void WaylandKeyboardDelegate::OnKeyboardLayoutUpdated(
  89. base::StringPiece keymap) {
  90. // Sent the content of |keymap| with trailing '\0' termination via shared
  91. // memory.
  92. base::UnsafeSharedMemoryRegion shared_keymap_region =
  93. base::UnsafeSharedMemoryRegion::Create(keymap.size() + 1);
  94. base::WritableSharedMemoryMapping shared_keymap = shared_keymap_region.Map();
  95. base::subtle::PlatformSharedMemoryRegion platform_shared_keymap =
  96. base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
  97. std::move(shared_keymap_region));
  98. DCHECK(shared_keymap.IsValid());
  99. std::memcpy(shared_keymap.memory(), keymap.data(), keymap.size());
  100. static_cast<uint8_t*>(shared_keymap.memory())[keymap.size()] = '\0';
  101. wl_keyboard_send_keymap(keyboard_resource_, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
  102. platform_shared_keymap.GetPlatformHandle().fd,
  103. keymap.size() + 1);
  104. wl_client_flush(client());
  105. }
  106. void WaylandKeyboardDelegate::SendKeyboardModifiers() {
  107. wl_keyboard_send_modifiers(
  108. keyboard_resource_,
  109. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  110. current_modifiers_.depressed, current_modifiers_.locked,
  111. current_modifiers_.latched, current_modifiers_.group);
  112. wl_client_flush(client());
  113. }
  114. // Convert from ChromeOS's key repeat interval to Wayland's key repeat rate.
  115. // For example, an interval of 500ms is a rate of 1000/500 = 2 Hz.
  116. //
  117. // Known issue: A 2000ms interval is 0.5 Hz. This rounds to 1 Hz, which
  118. // is twice as fast. This is not fixable without Wayland spec changes.
  119. int32_t GetWaylandRepeatRate(bool enabled, base::TimeDelta interval) {
  120. DCHECK(interval.InMillisecondsF() > 0.0);
  121. int32_t rate;
  122. if (enabled) {
  123. // Most of ChromeOS's interval options divide perfectly into 1000,
  124. // but a few do need rounding.
  125. rate = base::ClampRound<int32_t>(interval.ToHz());
  126. // Avoid disabling key repeat if the interval is >2000ms.
  127. rate = std::max(1, rate);
  128. } else {
  129. // Disables key repeat, as documented in Wayland spec.
  130. rate = 0;
  131. }
  132. return rate;
  133. }
  134. // Expose GetWaylandRepeatRate() to tests.
  135. int32_t GetWaylandRepeatRateForTesting(bool enabled, base::TimeDelta interval) {
  136. return GetWaylandRepeatRate(enabled, interval);
  137. }
  138. void WaylandKeyboardDelegate::OnKeyRepeatSettingsChanged(
  139. bool enabled,
  140. base::TimeDelta delay,
  141. base::TimeDelta interval) {
  142. // delay may be zero, but not negative (per Wayland spec).
  143. DCHECK_GE(delay.InMilliseconds(), 0);
  144. uint32_t version = wl_resource_get_version(keyboard_resource_);
  145. if (version >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
  146. wl_keyboard_send_repeat_info(keyboard_resource_,
  147. GetWaylandRepeatRate(enabled, interval),
  148. static_cast<int32_t>(delay.InMilliseconds()));
  149. }
  150. }
  151. wl_client* WaylandKeyboardDelegate::client() const {
  152. return wl_resource_get_client(keyboard_resource_);
  153. }
  154. #endif // BUILDFLAG(USE_XKBCOMMON)
  155. } // namespace wayland
  156. } // namespace exo