1 // Copyright 2016 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 
5 #include "ui/ozone/platform/wayland/host/wayland_keyboard.h"
6 
7 #include <utility>
8 
9 #include "base/files/scoped_file.h"
10 #include "base/memory/unsafe_shared_memory_region.h"
11 #include "base/unguessable_token.h"
12 #include "ui/base/buildflags.h"
13 #include "ui/events/base_event_utils.h"
14 #include "ui/events/event.h"
15 #include "ui/events/keycodes/dom/dom_code.h"
16 #include "ui/events/keycodes/dom/keycode_converter.h"
17 #include "ui/events/keycodes/keyboard_code_conversion.h"
18 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
19 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
20 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
21 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
22 #include "ui/ozone/platform/wayland/host/wayland_window.h"
23 
24 #if BUILDFLAG(USE_XKBCOMMON)
25 #include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
26 #endif
27 
28 namespace ui {
29 
30 // static
31 const wl_callback_listener WaylandKeyboard::callback_listener_ = {
32     WaylandKeyboard::SyncCallback,
33 };
34 
WaylandKeyboard(wl_keyboard * keyboard,KeyboardLayoutEngine * layout_engine,const EventDispatchCallback & callback)35 WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard,
36                                  KeyboardLayoutEngine* layout_engine,
37                                  const EventDispatchCallback& callback)
38     : obj_(keyboard),
39       callback_(callback),
40       auto_repeat_handler_(this),
41 #if BUILDFLAG(USE_XKBCOMMON)
42       layout_engine_(static_cast<XkbKeyboardLayoutEngine*>(layout_engine)) {
43 #else
44       layout_engine_(layout_engine) {
45 #endif
46   static const wl_keyboard_listener listener = {
47       &WaylandKeyboard::Keymap,    &WaylandKeyboard::Enter,
48       &WaylandKeyboard::Leave,     &WaylandKeyboard::Key,
49       &WaylandKeyboard::Modifiers, &WaylandKeyboard::RepeatInfo,
50   };
51 
52   wl_keyboard_add_listener(obj_.get(), &listener, this);
53 
54   // TODO(tonikitoo): Default auto-repeat to ON here?
55 }
56 
57 WaylandKeyboard::~WaylandKeyboard() {}
58 
59 void WaylandKeyboard::Keymap(void* data,
60                              wl_keyboard* obj,
61                              uint32_t format,
62                              int32_t keymap_fd,
63                              uint32_t size) {
64   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
65   DCHECK(keyboard);
66 
67   base::ScopedFD fd(keymap_fd);
68   auto length = size - 1;
69   auto shmen = base::subtle::PlatformSharedMemoryRegion::Take(
70       std::move(fd), base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
71       length, base::UnguessableToken::Create());
72   auto mapped_memory =
73       base::UnsafeSharedMemoryRegion::Deserialize(std::move(shmen)).Map();
74   const char* keymap = mapped_memory.GetMemoryAs<char>();
75 
76   if (!keymap || format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
77     return;
78 
79   bool success = keyboard->layout_engine_->SetCurrentLayoutFromBuffer(
80       keymap, mapped_memory.size());
81   DCHECK(success) << "Failed to set the XKB keyboard mapping.";
82 }
83 
84 void WaylandKeyboard::Enter(void* data,
85                             wl_keyboard* obj,
86                             uint32_t serial,
87                             wl_surface* surface,
88                             wl_array* keys) {
89   // wl_surface might have been destroyed by this time.
90   if (surface)
91     WaylandWindow::FromSurface(surface)->set_keyboard_focus(true);
92 }
93 
94 void WaylandKeyboard::Leave(void* data,
95                             wl_keyboard* obj,
96                             uint32_t serial,
97                             wl_surface* surface) {
98   // wl_surface might have been destroyed by this time.
99   if (surface)
100     WaylandWindow::FromSurface(surface)->set_keyboard_focus(false);
101 
102   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
103   DCHECK(keyboard);
104 
105   // Upon window focus lose, reset the key repeat timers.
106   keyboard->auto_repeat_handler_.StopKeyRepeat();
107 }
108 
109 void WaylandKeyboard::Key(void* data,
110                           wl_keyboard* obj,
111                           uint32_t serial,
112                           uint32_t time,
113                           uint32_t key,
114                           uint32_t state) {
115   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
116   DCHECK(keyboard);
117 
118   keyboard->connection_->set_serial(serial);
119 
120   bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED;
121   int device_id = keyboard->obj_.id();
122 
123   keyboard->auto_repeat_handler_.UpdateKeyRepeat(
124       key, down, false /*suppress_auto_repeat*/, device_id);
125 
126   // TODO(tonikitoo,msisov): Handler 'repeat' parameter below.
127   keyboard->DispatchKey(key, down, false /*repeat*/, EventTimeForNow(),
128                         device_id, EF_NONE);
129 }
130 
131 void WaylandKeyboard::Modifiers(void* data,
132                                 wl_keyboard* obj,
133                                 uint32_t serial,
134                                 uint32_t depressed,
135                                 uint32_t latched,
136                                 uint32_t locked,
137                                 uint32_t group) {
138 #if BUILDFLAG(USE_XKBCOMMON)
139   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
140   DCHECK(keyboard);
141 
142   keyboard->modifiers_ = keyboard->layout_engine_->UpdateModifiers(
143       depressed, latched, locked, group);
144 #endif
145 }
146 
147 void WaylandKeyboard::RepeatInfo(void* data,
148                                  wl_keyboard* obj,
149                                  int32_t rate,
150                                  int32_t delay) {
151   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
152   DCHECK(keyboard);
153 
154   keyboard->auto_repeat_handler_.SetAutoRepeatRate(
155       base::TimeDelta::FromMilliseconds(delay),
156       base::TimeDelta::FromMilliseconds(rate));
157 }
158 
159 void WaylandKeyboard::FlushInput(base::OnceClosure closure) {
160   if (sync_callback_)
161     return;
162 
163   auto_repeat_closure_ = std::move(closure);
164 
165   // wl_display_sync gives a chance for any key "up" events to arrive.
166   // With a well behaved wayland compositor this should ensure we never
167   // get spurious repeats.
168   sync_callback_.reset(wl_display_sync(connection_->display()));
169   wl_callback_add_listener(sync_callback_.get(), &callback_listener_, this);
170   connection_->ScheduleFlush();
171 }
172 
173 void WaylandKeyboard::DispatchKey(uint32_t key,
174                                   bool down,
175                                   bool repeat,
176                                   base::TimeTicks timestamp,
177                                   int device_id,
178                                   int flags) {
179   DomCode dom_code =
180       KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key));
181   if (dom_code == ui::DomCode::NONE)
182     return;
183 
184   DomKey dom_key;
185   KeyboardCode key_code;
186   if (!layout_engine_->Lookup(dom_code, modifiers_, &dom_key, &key_code))
187     return;
188 
189   if (!repeat) {
190     int flag = ModifierDomKeyToEventFlag(dom_key);
191     UpdateModifier(flag, down);
192   }
193 
194   ui::KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code,
195                      dom_code, modifiers_, dom_key, timestamp);
196   event.set_source_device_id(device_id);
197   callback_.Run(&event);
198 }
199 
200 void WaylandKeyboard::SyncCallback(void* data,
201                                    struct wl_callback* cb,
202                                    uint32_t time) {
203   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
204   DCHECK(keyboard);
205 
206   std::move(keyboard->auto_repeat_closure_).Run();
207   DCHECK(keyboard->auto_repeat_closure_.is_null());
208   keyboard->sync_callback_.reset();
209 }
210 
211 void WaylandKeyboard::UpdateModifier(int modifier, bool down) {
212   if (modifier == EF_NONE)
213     return;
214 
215   // TODO(nickdiego): ChromeOS-specific keyboard remapping logic.
216   // Remove this once it is properly guarded under OS_CHROMEOS.
217   //
218   // Currently EF_MOD3_DOWN means that the CapsLock key is currently down,
219   // and EF_CAPS_LOCK_ON means the caps lock state is enabled (and the
220   // key may or may not be down, but usually isn't). There does need to
221   // to be two different flags, since the physical CapsLock key is subject
222   // to remapping, but the caps lock state (which can be triggered in a
223   // variety of ways) is not.
224   if (modifier == EF_CAPS_LOCK_ON)
225     modifier = (modifier & ~EF_CAPS_LOCK_ON) | EF_MOD3_DOWN;
226   modifiers_ = down ? (modifiers_ | modifier) : (modifiers_ & ~modifier);
227 }
228 
229 }  // namespace ui
230