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