blob: e50b924ccdbe45a2c9500650e05ce9cfae08251a [file] [log] [blame]
David Padlipsky5eaaade2023-07-21 22:39:381// Copyright 2023 The Chromium Authors
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 "ash/events/peripheral_customization_event_rewriter.h"
6
David Padlipskyb7896da2023-10-25 19:45:467#include <linux/input.h>
David Padlipskya0e5e022024-02-10 00:08:038#include <iterator>
David Padlipskycc7c2de2023-08-23 17:16:549#include <memory>
David Padlipsky3472a1e2024-02-16 19:12:4010#include <optional>
David Padlipskycc7c2de2023-08-23 17:16:5411
David Padlipskyf8730952023-09-01 19:38:2712#include "ash/accelerators/accelerator_controller_impl.h"
David Padlipsky5eaaade2023-07-21 22:39:3813#include "ash/constants/ash_features.h"
David Padlipsky3472a1e2024-02-16 19:12:4014#include "ash/events/event_rewriter_controller_impl.h"
David Padlipsky5b39dc02024-01-03 20:36:4815#include "ash/public/cpp/accelerators_util.h"
David Padlipsky3b55bb12023-09-05 22:24:5716#include "ash/public/mojom/input_device_settings.mojom-forward.h"
David Padlipskyb5a52cd12023-08-08 21:45:1917#include "ash/public/mojom/input_device_settings.mojom-shared.h"
18#include "ash/public/mojom/input_device_settings.mojom.h"
David Padlipskyf8730952023-09-01 19:38:2719#include "ash/shell.h"
David Padlipskyf9728f272023-09-06 16:50:3620#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
David Padlipsky5eaaade2023-07-21 22:39:3821#include "base/check.h"
David Padlipskya0e5e022024-02-10 00:08:0322#include "base/check_op.h"
David Padlipskyd664e672023-10-25 21:32:1523#include "base/containers/fixed_flat_map.h"
David Padlipskya0e5e022024-02-10 00:08:0324#include "base/containers/span.h"
David Padlipskyb5a52cd12023-08-08 21:45:1925#include "base/notreached.h"
David Padlipskycc7c2de2023-08-23 17:16:5426#include "base/ranges/algorithm.h"
David Padlipsky3472a1e2024-02-16 19:12:4027#include "base/strings/string_util.h"
Jimmyb36a8772023-11-10 19:41:3928#include "ui/base/ui_base_features.h"
David Padlipskyd664e672023-10-25 21:32:1529#include "ui/display/screen.h"
David Padlipsky3472a1e2024-02-16 19:12:4030#include "ui/events/ash/mojom/modifier_key.mojom-shared.h"
David Padlipskyb5a52cd12023-08-08 21:45:1931#include "ui/events/event.h"
32#include "ui/events/event_constants.h"
33#include "ui/events/event_dispatcher.h"
David Padlipskyd664e672023-10-25 21:32:1534#include "ui/events/event_utils.h"
David Padlipskycc7c2de2023-08-23 17:16:5435#include "ui/events/keycodes/dom/dom_code.h"
36#include "ui/events/keycodes/dom/dom_key.h"
37#include "ui/events/keycodes/keyboard_codes_posix.h"
David Padlipskyb7896da2023-10-25 19:45:4638#include "ui/events/ozone/evdev/mouse_button_property.h"
David Padlipsky5b39dc02024-01-03 20:36:4839#include "ui/events/ozone/layout/keyboard_layout_engine.h"
40#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
David Padlipskyb5a52cd12023-08-08 21:45:1941#include "ui/events/types/event_type.h"
David Padlipskyd664e672023-10-25 21:32:1542#include "ui/gfx/geometry/point_f.h"
David Padlipsky5eaaade2023-07-21 22:39:3843
44namespace ash {
45
David Padlipskyb5a52cd12023-08-08 21:45:1946namespace {
47
David Padlipskya0e5e022024-02-10 00:08:0348using RemappingActionResult =
49 PeripheralCustomizationEventRewriter::RemappingActionResult;
50
David Padlipskyb5a52cd12023-08-08 21:45:1951constexpr int kMouseRemappableFlags = ui::EF_BACK_MOUSE_BUTTON |
52 ui::EF_FORWARD_MOUSE_BUTTON |
53 ui::EF_MIDDLE_MOUSE_BUTTON;
54
55constexpr int kGraphicsTabletRemappableFlags =
56 ui::EF_RIGHT_MOUSE_BUTTON | ui::EF_BACK_MOUSE_BUTTON |
57 ui::EF_FORWARD_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON;
58
David Padlipskyd664e672023-10-25 21:32:1559constexpr auto kStaticActionToMouseButtonFlag =
60 base::MakeFixedFlatMap<mojom::StaticShortcutAction, ui::EventFlags>({
61 {mojom::StaticShortcutAction::kLeftClick, ui::EF_LEFT_MOUSE_BUTTON},
62 {mojom::StaticShortcutAction::kRightClick, ui::EF_RIGHT_MOUSE_BUTTON},
63 {mojom::StaticShortcutAction::kMiddleClick, ui::EF_MIDDLE_MOUSE_BUTTON},
64 });
65
David Padlipsky74935f592024-02-02 00:24:4166constexpr std::string_view ToMetricsString(
YuhanYang92cbe1592023-12-05 02:13:2967 PeripheralCustomizationEventRewriter::PeripheralCustomizationMetricsType
68 peripheral_kind) {
69 switch (peripheral_kind) {
70 case PeripheralCustomizationEventRewriter::
71 PeripheralCustomizationMetricsType::kMouse:
David Padlipsky74935f592024-02-02 00:24:4172 return "Mouse";
YuhanYang92cbe1592023-12-05 02:13:2973 case PeripheralCustomizationEventRewriter::
74 PeripheralCustomizationMetricsType::kGraphicsTablet:
David Padlipsky74935f592024-02-02 00:24:4175 return "GraphicsTablet";
YuhanYang92cbe1592023-12-05 02:13:2976 case PeripheralCustomizationEventRewriter::
77 PeripheralCustomizationMetricsType::kGraphicsTabletPen:
David Padlipsky74935f592024-02-02 00:24:4178 return "GraphicsTabletPen";
YuhanYang92cbe1592023-12-05 02:13:2979 }
80}
81
Danny Wangd388f6b2023-09-29 00:06:5082mojom::KeyEvent GetStaticShortcutAction(mojom::StaticShortcutAction action) {
Danny Wang6bdb5582023-09-18 21:27:2983 mojom::KeyEvent key_event;
84 switch (action) {
Danny Wang75a9a86f2023-09-29 21:00:3085 case mojom::StaticShortcutAction::kDisable:
David Padlipskyd664e672023-10-25 21:32:1586 case mojom::StaticShortcutAction::kLeftClick:
87 case mojom::StaticShortcutAction::kRightClick:
88 case mojom::StaticShortcutAction::kMiddleClick:
Danny Wang75a9a86f2023-09-29 21:00:3089 NOTREACHED_NORETURN();
Danny Wangd388f6b2023-09-29 00:06:5090 case mojom::StaticShortcutAction::kCopy:
Danny Wang6bdb5582023-09-18 21:27:2991 key_event = mojom::KeyEvent(
92 ui::VKEY_C, static_cast<int>(ui::DomCode::US_C),
93 static_cast<int>(ui::DomKey::Constant<'c'>::Character),
David Padlipskyfc60da892023-10-27 00:14:3194 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang6bdb5582023-09-18 21:27:2995 break;
Danny Wangd388f6b2023-09-29 00:06:5096 case mojom::StaticShortcutAction::kPaste:
Danny Wang6bdb5582023-09-18 21:27:2997 key_event = mojom::KeyEvent(
98 ui::VKEY_V, static_cast<int>(ui::DomCode::US_V),
99 static_cast<int>(ui::DomKey::Constant<'v'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31100 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang6bdb5582023-09-18 21:27:29101 break;
Danny Wang0dfd3b02023-10-19 01:36:02102 case mojom::StaticShortcutAction::kUndo:
103 key_event = mojom::KeyEvent(
104 ui::VKEY_Z, static_cast<int>(ui::DomCode::US_Z),
105 static_cast<int>(ui::DomKey::Constant<'z'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31106 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02107 break;
108 case mojom::StaticShortcutAction::kRedo:
109 key_event = mojom::KeyEvent(
110 ui::VKEY_Z, static_cast<int>(ui::DomCode::US_Z),
111 static_cast<int>(ui::DomKey::Constant<'z'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31112 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02113 break;
114 case mojom::StaticShortcutAction::kZoomIn:
115 key_event = mojom::KeyEvent(
116 ui::VKEY_OEM_PLUS, static_cast<int>(ui::DomCode::EQUAL),
117 static_cast<int>(ui::DomKey::Constant<'='>::Character),
David Padlipskyfc60da892023-10-27 00:14:31118 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02119 break;
120 case mojom::StaticShortcutAction::kZoomOut:
121 key_event = mojom::KeyEvent(
122 ui::VKEY_OEM_MINUS, static_cast<int>(ui::DomCode::MINUS),
123 static_cast<int>(ui::DomKey::Constant<'-'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31124 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02125 break;
126 case mojom::StaticShortcutAction::kPreviousPage:
David Padlipskyfc60da892023-10-27 00:14:31127 key_event = mojom::KeyEvent(ui::VKEY_BROWSER_BACK,
128 static_cast<int>(ui::DomCode::BROWSER_BACK),
129 static_cast<int>(ui::DomKey::BROWSER_BACK),
130 ui::EF_NONE, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02131 break;
132 case mojom::StaticShortcutAction::kNextPage:
David Padlipskyfc60da892023-10-27 00:14:31133 key_event =
134 mojom::KeyEvent(ui::VKEY_BROWSER_FORWARD,
135 static_cast<int>(ui::DomCode::BROWSER_FORWARD),
136 static_cast<int>(ui::DomKey::BROWSER_FORWARD),
137 ui::EF_NONE, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02138 break;
Danny Wang6bdb5582023-09-18 21:27:29139 }
140 return key_event;
141}
142
David Padlipsky3394af92023-10-27 21:30:50143int ConvertKeyCodeToFlags(ui::KeyboardCode key_code) {
144 switch (key_code) {
145 case ui::VKEY_LWIN:
146 case ui::VKEY_RWIN:
147 return ui::EF_COMMAND_DOWN;
148 case ui::VKEY_CONTROL:
David Padlipsky5b39dc02024-01-03 20:36:48149 case ui::VKEY_RCONTROL:
David Padlipsky3394af92023-10-27 21:30:50150 return ui::EF_CONTROL_DOWN;
151 case ui::VKEY_SHIFT:
152 case ui::VKEY_LSHIFT:
153 case ui::VKEY_RSHIFT:
154 return ui::EF_SHIFT_DOWN;
155 case ui::VKEY_MENU:
156 case ui::VKEY_RMENU:
157 return ui::EF_ALT_DOWN;
158 default:
159 return ui::EF_NONE;
160 }
161}
162
David Padlipsky3472a1e2024-02-16 19:12:40163int ConvertModifierKeyToFlags(ui::mojom::ModifierKey modifier_key) {
164 switch (modifier_key) {
165 case ui::mojom::ModifierKey::kMeta:
166 return ui::EF_COMMAND_DOWN;
167 case ui::mojom::ModifierKey::kControl:
168 return ui::EF_CONTROL_DOWN;
169 case ui::mojom::ModifierKey::kAlt:
170 return ui::EF_ALT_DOWN;
171 case ui::mojom::ModifierKey::kEscape:
172 case ui::mojom::ModifierKey::kBackspace:
173 case ui::mojom::ModifierKey::kAssistant:
174 case ui::mojom::ModifierKey::kCapsLock:
175 case ui::mojom::ModifierKey::kVoid:
176 case ui::mojom::ModifierKey::kIsoLevel5ShiftMod3:
177 return ui::EF_NONE;
178 }
179}
180
David Padlipskyfe51c1162024-02-10 02:00:18181bool AreScrollWheelEventRewritesAllowed(
182 mojom::CustomizationRestriction customization_restriction) {
183 switch (customization_restriction) {
184 case mojom::CustomizationRestriction::kDisallowCustomizations:
185 case mojom::CustomizationRestriction::kDisableKeyEventRewrites:
186 case mojom::CustomizationRestriction::kAllowAlphabetKeyEventRewrites:
187 case mojom::CustomizationRestriction::
188 kAllowAlphabetOrNumberKeyEventRewrites:
David Padlipsky07842e92024-02-13 01:18:46189 case mojom::CustomizationRestriction::kAllowTabEventRewrites:
David Padlipskyfe51c1162024-02-10 02:00:18190 return false;
191 case mojom::CustomizationRestriction::kAllowHorizontalScrollWheelRewrites:
192 case mojom::CustomizationRestriction::kAllowCustomizations:
193 return true;
194 }
195}
196
David Padlipskya0e5e022024-02-10 00:08:03197template <typename Iterator>
198std::vector<std::unique_ptr<ui::Event>> RewriteModifiers(
199 const ui::Event& event,
200 uint32_t modifiers_to_press,
201 uint32_t modifiers_already_pressed,
202 bool pressed,
203 Iterator begin,
204 Iterator end) {
205 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
206
207 // Keeps track of the modifier flags that must be applied to the next
208 // rewritten event. For key presses, this should start at
209 // `0` and go to `modifiers_to_press`. For releases, it should do the opposite
210 // as we start will all modifiers down.
211 uint32_t modifiers_pressed = pressed ? 0u : modifiers_to_press;
212
213 for (auto iter = begin; iter != end; iter++) {
214 if (!(iter->flag & modifiers_to_press)) {
215 continue;
216 }
217
218 if (pressed) {
219 modifiers_pressed += iter->flag;
220 } else {
221 modifiers_pressed -= iter->flag;
222 }
223
224 const ui::EventType pressed_or_released_type =
225 pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
226 auto rewritten_modifier_event = std::make_unique<ui::KeyEvent>(
227 pressed_or_released_type, iter->key_code, iter->dom_code,
228 modifiers_pressed | modifiers_already_pressed, event.time_stamp());
229 rewritten_modifier_event->set_source_device_id(event.source_device_id());
230 rewritten_events.push_back(std::move(rewritten_modifier_event));
231 }
232
233 // Verify our modifier rewriting worked as expected.
234 if (pressed) {
235 CHECK_EQ(modifiers_to_press, modifiers_pressed);
236 } else {
237 CHECK_EQ(0u, modifiers_pressed);
238 }
239
240 return rewritten_events;
241}
242
243std::vector<std::unique_ptr<ui::Event>> GenerateFullKeyEventSequence(
244 const ui::Event& event,
245 uint32_t modifiers_to_press,
246 uint32_t modifiers_already_pressed,
247 bool pressed,
248 std::unique_ptr<ui::Event> rewritten_event) {
249 static constexpr struct {
250 ui::KeyboardCode key_code;
251 ui::DomCode dom_code;
252 ui::EventFlags flag;
253 } kModifiers[] = {
254 {ui::VKEY_LWIN, ui::DomCode::META_LEFT, ui::EF_COMMAND_DOWN},
255 {ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::EF_CONTROL_DOWN},
256 {ui::VKEY_MENU, ui::DomCode::ALT_LEFT, ui::EF_ALT_DOWN},
257 {ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT, ui::EF_SHIFT_DOWN},
258 };
259 static constexpr auto kModifierSpan = base::make_span(kModifiers);
260
261 CHECK(rewritten_event);
262 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
263
264 if (pressed) {
265 // If it is a key press, we rewrite the modifiers in forward order and then
266 // add the main rewritten event after the press events.
267 rewritten_events =
268 RewriteModifiers(event, modifiers_to_press, modifiers_already_pressed,
269 pressed, kModifierSpan.begin(), kModifierSpan.end());
270 rewritten_events.push_back(std::move(rewritten_event));
271 } else {
272 // For key releases, we add the main rewritten event first and then append
273 // the rewritten modifiers after. The modifiers must be rewritten in reverse
274 // order from the `kModifiers` array.
275 rewritten_events.push_back(std::move(rewritten_event));
276 auto modifier_events =
277 RewriteModifiers(event, modifiers_to_press, modifiers_already_pressed,
278 pressed, kModifierSpan.rbegin(), kModifierSpan.rend());
279 rewritten_events.insert(rewritten_events.end(),
280 std::make_move_iterator(modifier_events.begin()),
281 std::make_move_iterator(modifier_events.end()));
282 }
283
284 return rewritten_events;
285}
286
287std::vector<std::unique_ptr<ui::Event>> RewriteEventToKeyEvents(
Danny Wang6bdb5582023-09-18 21:27:29288 const ui::Event& event,
David Padlipskyfe51c1162024-02-10 02:00:18289 const mojom::KeyEvent& key_event,
David Padlipsky3472a1e2024-02-16 19:12:40290 int flags_to_release,
David Padlipskyfe51c1162024-02-10 02:00:18291 bool key_press) {
292 const ui::EventType event_type =
293 key_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
David Padlipskya0e5e022024-02-10 00:08:03294 const uint32_t modifier_key_flag = ConvertKeyCodeToFlags(key_event.vkey);
295
296 // `other_modifiers_to_apply` symbolizes the flags that are not handled by
297 // `modifier_key_flag` or flags that are already included in the event. The
298 // flags remaining in `other_modifiers_to_apply` are the modifiers we must
299 // write events for in addition to the main key event.
David Padlipsky3472a1e2024-02-16 19:12:40300
301 // On release events, we should release the flags passed in instead of our
302 // computed set of flags in case some modifiers were released since we
303 // originally pressed them down.
304
305 // Mouse wheel is an exception here since presses and releases happen
306 // atomically. Therefore always release every key you originally pressed.
David Padlipskya0e5e022024-02-10 00:08:03307 const uint32_t other_modifiers_to_apply =
David Padlipsky3472a1e2024-02-16 19:12:40308 (key_press || event.type() == ui::ET_MOUSEWHEEL)
309 ? (key_event.modifiers & ~event.flags() & ~modifier_key_flag)
310 : (flags_to_release & ~event.flags() & ~modifier_key_flag);
David Padlipskya0e5e022024-02-10 00:08:03311
312 uint32_t applied_modifier_key_flag = modifier_key_flag;
David Padlipsky3394af92023-10-27 21:30:50313 // Do not apply modifier flags when the key is a modifier and it is a release
314 // event. Modifier keys do not apply their flag on release.
315 if (event_type == ui::ET_KEY_RELEASED &&
David Padlipskya0e5e022024-02-10 00:08:03316 key_event.modifiers == modifier_key_flag) {
317 applied_modifier_key_flag = ui::EF_NONE;
David Padlipsky3394af92023-10-27 21:30:50318 }
David Padlipskyfe51c1162024-02-10 02:00:18319
Danny Wang6bdb5582023-09-18 21:27:29320 auto rewritten_event = std::make_unique<ui::KeyEvent>(
321 event_type, key_event.vkey, static_cast<ui::DomCode>(key_event.dom_code),
David Padlipskya0e5e022024-02-10 00:08:03322 applied_modifier_key_flag | other_modifiers_to_apply | event.flags(),
Danny Wang6bdb5582023-09-18 21:27:29323 static_cast<ui::DomKey>(key_event.dom_key), event.time_stamp());
324 rewritten_event->set_source_device_id(event.source_device_id());
David Padlipskya0e5e022024-02-10 00:08:03325
326 return GenerateFullKeyEventSequence(
327 event, other_modifiers_to_apply, event.flags(),
328 /*pressed=*/event_type == ui::ET_KEY_PRESSED, std::move(rewritten_event));
Danny Wang6bdb5582023-09-18 21:27:29329}
330
David Padlipskyfe51c1162024-02-10 02:00:18331std::vector<std::unique_ptr<ui::Event>> RewriteEventToKeyEvents(
332 const ui::Event& event,
David Padlipsky3472a1e2024-02-16 19:12:40333 const mojom::KeyEvent& key_event,
334 int flags_to_release) {
David Padlipskyfe51c1162024-02-10 02:00:18335 // If the original event is a mouse scroll event, we must generate both a
336 // press and release from the single event.
337 const bool should_press_and_release = event.type() == ui::ET_MOUSEWHEEL;
338
339 const bool key_press = should_press_and_release ||
340 event.type() == ui::ET_MOUSE_PRESSED ||
341 event.type() == ui::ET_KEY_PRESSED;
342 std::vector<std::unique_ptr<ui::Event>> rewritten_events =
David Padlipsky3472a1e2024-02-16 19:12:40343 RewriteEventToKeyEvents(event, key_event, flags_to_release, key_press);
David Padlipskyfe51c1162024-02-10 02:00:18344
345 if (should_press_and_release) {
346 std::vector<std::unique_ptr<ui::Event>> release_rewritten_events =
David Padlipsky3472a1e2024-02-16 19:12:40347 RewriteEventToKeyEvents(event, key_event, flags_to_release, false);
David Padlipskyfe51c1162024-02-10 02:00:18348 rewritten_events.reserve(rewritten_events.size() +
349 release_rewritten_events.size());
350 rewritten_events.insert(
351 rewritten_events.end(),
352 std::make_move_iterator(release_rewritten_events.begin()),
353 std::make_move_iterator(release_rewritten_events.end()));
354 }
355 return rewritten_events;
356}
357
358std::vector<std::unique_ptr<ui::Event>> RewriteEventToMouseButtonEvents(
David Padlipskyd664e672023-10-25 21:32:15359 const ui::Event& event,
360 mojom::StaticShortcutAction action) {
David Padlipskyfe51c1162024-02-10 02:00:18361 // If the original event is a mouse scroll event, we must generate both a
362 // press and release from the single event.
363 const bool should_press_and_release = event.type() == ui::ET_MOUSEWHEEL;
364
365 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
366
David Padlipskyd664e672023-10-25 21:32:15367 auto* flag_iter = kStaticActionToMouseButtonFlag.find(action);
368 CHECK(flag_iter != kStaticActionToMouseButtonFlag.end());
369 const int characteristic_flag = flag_iter->second;
370
371 auto* screen = display::Screen::GetScreen();
372 CHECK(screen);
David Padlipsky3394af92023-10-27 21:30:50373 auto display = screen->GetDisplayNearestPoint(screen->GetCursorScreenPoint());
374 const gfx::PointF location =
375 gfx::ScalePoint(gfx::PointF(screen->GetCursorScreenPoint() -
376 display.bounds().origin().OffsetFromOrigin()),
377 display.device_scale_factor());
David Padlipskyd664e672023-10-25 21:32:15378
David Padlipskyfe51c1162024-02-10 02:00:18379 const ui::EventType type =
380 (should_press_and_release || event.type() == ui::ET_MOUSE_PRESSED ||
381 event.type() == ui::ET_KEY_PRESSED)
382 ? ui::ET_MOUSE_PRESSED
383 : ui::ET_MOUSE_RELEASED;
384 rewritten_events.push_back(std::make_unique<ui::MouseEvent>(
David Padlipskyd664e672023-10-25 21:32:15385 type, location, location, event.time_stamp(),
David Padlipskyfe51c1162024-02-10 02:00:18386 event.flags() | characteristic_flag, characteristic_flag));
387 rewritten_events.back()->set_source_device_id(event.source_device_id());
388
389 if (should_press_and_release) {
390 rewritten_events.push_back(std::make_unique<ui::MouseEvent>(
391 ui::ET_MOUSE_RELEASED, location, location, event.time_stamp(),
392 event.flags() | characteristic_flag, characteristic_flag));
393 rewritten_events.back()->set_source_device_id(event.source_device_id());
394 }
395
396 return rewritten_events;
David Padlipskyd664e672023-10-25 21:32:15397}
398
David Padlipskyb5a52cd12023-08-08 21:45:19399bool IsMouseButtonEvent(const ui::MouseEvent& mouse_event) {
400 return mouse_event.type() == ui::ET_MOUSE_PRESSED ||
401 mouse_event.type() == ui::ET_MOUSE_RELEASED;
402}
403
404bool IsMouseRemappableButton(int flags) {
405 return (flags & kMouseRemappableFlags) != 0;
406}
407
408bool IsGraphicsTabletRemappableButton(int flags) {
409 return (flags & kGraphicsTabletRemappableFlags) != 0;
410}
411
412int GetRemappableMouseEventFlags(
413 PeripheralCustomizationEventRewriter::DeviceType device_type) {
414 switch (device_type) {
415 case PeripheralCustomizationEventRewriter::DeviceType::kMouse:
416 return kMouseRemappableFlags;
417 case PeripheralCustomizationEventRewriter::DeviceType::kGraphicsTablet:
418 return kGraphicsTabletRemappableFlags;
419 }
420}
421
David Padlipskyb7896da2023-10-25 19:45:46422mojom::ButtonPtr GetButtonFromMouseEvent(const ui::MouseEvent& mouse_event) {
423 switch (mouse_event.changed_button_flags()) {
David Padlipskyb5a52cd12023-08-08 21:45:19424 case ui::EF_LEFT_MOUSE_BUTTON:
425 return mojom::Button::NewCustomizableButton(
426 mojom::CustomizableButton::kLeft);
427 case ui::EF_RIGHT_MOUSE_BUTTON:
428 return mojom::Button::NewCustomizableButton(
429 mojom::CustomizableButton::kRight);
430 case ui::EF_MIDDLE_MOUSE_BUTTON:
431 return mojom::Button::NewCustomizableButton(
432 mojom::CustomizableButton::kMiddle);
433 case ui::EF_FORWARD_MOUSE_BUTTON:
David Padlipskyb7896da2023-10-25 19:45:46434 case ui::EF_BACK_MOUSE_BUTTON:
435 break;
436 }
437
438 CHECK(mouse_event.changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON ||
439 mouse_event.changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON);
440 auto linux_key_code = ui::GetForwardBackMouseButtonProperty(mouse_event);
441 if (!linux_key_code) {
442 return (mouse_event.changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
443 ? mojom::Button::NewCustomizableButton(
444 mojom::CustomizableButton::kForward)
445 : mojom::Button::NewCustomizableButton(
446 mojom::CustomizableButton::kBack);
447 }
448
449 switch (*linux_key_code) {
450 case BTN_FORWARD:
David Padlipskyb5a52cd12023-08-08 21:45:19451 return mojom::Button::NewCustomizableButton(
452 mojom::CustomizableButton::kForward);
David Padlipskyb7896da2023-10-25 19:45:46453 case BTN_BACK:
David Padlipskyb5a52cd12023-08-08 21:45:19454 return mojom::Button::NewCustomizableButton(
455 mojom::CustomizableButton::kBack);
David Padlipskyb7896da2023-10-25 19:45:46456 case BTN_SIDE:
457 return mojom::Button::NewCustomizableButton(
458 mojom::CustomizableButton::kSide);
459 case BTN_EXTRA:
460 return mojom::Button::NewCustomizableButton(
461 mojom::CustomizableButton::kExtra);
David Padlipskyb5a52cd12023-08-08 21:45:19462 }
David Padlipskyb7896da2023-10-25 19:45:46463
David Padlipskyb5a52cd12023-08-08 21:45:19464 NOTREACHED_NORETURN();
465}
466
David Padlipskyfe51c1162024-02-10 02:00:18467// Returns the customizable button for the scroll wheel event. Will return null
468// if the scroll event is not a horizontal scroll event.
469mojom::ButtonPtr GetButtonFromMouseWheelEvent(
470 const ui::MouseWheelEvent& mouse_wheel_event) {
471 if (mouse_wheel_event.x_offset() == 0) {
472 return nullptr;
473 }
474
475 if (mouse_wheel_event.x_offset() > 0) {
476 return mojom::Button::NewCustomizableButton(
477 mojom::CustomizableButton::kScrollRight);
478 }
479
480 return mojom::Button::NewCustomizableButton(
481 mojom::CustomizableButton::kScrollLeft);
482}
483
David Padlipskycc7c2de2023-08-23 17:16:54484int ConvertButtonToFlags(const mojom::Button& button) {
485 if (button.is_customizable_button()) {
486 switch (button.get_customizable_button()) {
487 case mojom::CustomizableButton::kLeft:
488 return ui::EF_LEFT_MOUSE_BUTTON;
489 case mojom::CustomizableButton::kRight:
490 return ui::EF_RIGHT_MOUSE_BUTTON;
491 case mojom::CustomizableButton::kMiddle:
492 return ui::EF_MIDDLE_MOUSE_BUTTON;
493 case mojom::CustomizableButton::kForward:
David Padlipskycc7c2de2023-08-23 17:16:54494 case mojom::CustomizableButton::kExtra:
495 return ui::EF_FORWARD_MOUSE_BUTTON;
David Padlipskyb7896da2023-10-25 19:45:46496 case mojom::CustomizableButton::kBack:
David Padlipskycc7c2de2023-08-23 17:16:54497 case mojom::CustomizableButton::kSide:
498 return ui::EF_BACK_MOUSE_BUTTON;
David Padlipskyfe51c1162024-02-10 02:00:18499 case mojom::CustomizableButton::kScrollLeft:
500 case mojom::CustomizableButton::kScrollRight:
501 return ui::EF_NONE;
David Padlipskycc7c2de2023-08-23 17:16:54502 }
503 }
504
505 if (button.is_vkey()) {
David Padlipsky3b55bb12023-09-05 22:24:57506 return ConvertKeyCodeToFlags(button.get_vkey());
David Padlipskycc7c2de2023-08-23 17:16:54507 }
508
509 return ui::EF_NONE;
510}
511
David Padlipsky3472a1e2024-02-16 19:12:40512std::optional<ui::mojom::ModifierKey> ConvertDomCodeToModifierKey(
513 ui::DomCode code) {
514 switch (code) {
515 case ui::DomCode::META_LEFT:
516 case ui::DomCode::META_RIGHT:
517 return ui::mojom::ModifierKey::kMeta;
518 case ui::DomCode::CONTROL_LEFT:
519 case ui::DomCode::CONTROL_RIGHT:
520 return ui::mojom::ModifierKey::kControl;
521 case ui::DomCode::ALT_LEFT:
522 case ui::DomCode::ALT_RIGHT:
523 return ui::mojom::ModifierKey::kAlt;
524 case ui::DomCode::CAPS_LOCK:
525 return ui::mojom::ModifierKey::kCapsLock;
526 case ui::DomCode::BACKSPACE:
527 return ui::mojom::ModifierKey::kBackspace;
528 case ui::DomCode::LAUNCH_ASSISTANT:
529 return ui::mojom::ModifierKey::kAssistant;
530 case ui::DomCode::ESCAPE:
531 return ui::mojom::ModifierKey::kEscape;
532 default:
533 return std::nullopt;
534 }
535}
536
YuhanYang92cbe1592023-12-05 02:13:29537std::optional<PeripheralCustomizationEventRewriter::RemappingActionResult>
538GetRemappingActionFromMouseSettings(const mojom::Button& button,
539 const mojom::MouseSettings& settings) {
David Padlipskyf9728f272023-09-06 16:50:36540 const auto button_remapping_iter = base::ranges::find(
541 settings.button_remappings, button,
542 [](const mojom::ButtonRemappingPtr& entry) { return *entry->button; });
543 if (button_remapping_iter != settings.button_remappings.end()) {
David Padlipsky1eb6f0ae2024-01-08 18:49:21544 const mojom::ButtonRemapping& button_remapping = *(*button_remapping_iter);
545 if (!button_remapping.remapping_action) {
546 return std::nullopt;
547 }
548
YuhanYang92cbe1592023-12-05 02:13:29549 auto result = PeripheralCustomizationEventRewriter::RemappingActionResult(
David Padlipsky1eb6f0ae2024-01-08 18:49:21550 *button_remapping.remapping_action,
YuhanYang92cbe1592023-12-05 02:13:29551 PeripheralCustomizationEventRewriter::
552 PeripheralCustomizationMetricsType::kMouse);
David Padlipsky1eb6f0ae2024-01-08 18:49:21553 return result;
David Padlipskyf9728f272023-09-06 16:50:36554 }
555
David Padlipsky1eb6f0ae2024-01-08 18:49:21556 return std::nullopt;
David Padlipskyf9728f272023-09-06 16:50:36557}
558
YuhanYang92cbe1592023-12-05 02:13:29559std::optional<PeripheralCustomizationEventRewriter::RemappingActionResult>
560GetRemappingActionFromGraphicsTabletSettings(
David Padlipskyf9728f272023-09-06 16:50:36561 const mojom::Button& button,
562 const mojom::GraphicsTabletSettings& settings) {
563 const auto pen_button_remapping_iter = base::ranges::find(
564 settings.pen_button_remappings, button,
565 [](const mojom::ButtonRemappingPtr& entry) { return *entry->button; });
566 if (pen_button_remapping_iter != settings.pen_button_remappings.end()) {
David Padlipsky1eb6f0ae2024-01-08 18:49:21567 const mojom::ButtonRemapping& button_remapping =
568 *(*pen_button_remapping_iter);
569 if (!button_remapping.remapping_action) {
570 return std::nullopt;
571 }
572
YuhanYang92cbe1592023-12-05 02:13:29573 auto pen_action =
574 PeripheralCustomizationEventRewriter::RemappingActionResult(
David Padlipsky1eb6f0ae2024-01-08 18:49:21575 *button_remapping.remapping_action,
YuhanYang92cbe1592023-12-05 02:13:29576 PeripheralCustomizationEventRewriter::
577 PeripheralCustomizationMetricsType::kGraphicsTabletPen);
578 return std::move(pen_action);
David Padlipskyf9728f272023-09-06 16:50:36579 }
580
581 const auto tablet_button_remapping_iter = base::ranges::find(
582 settings.tablet_button_remappings, button,
583 [](const mojom::ButtonRemappingPtr& entry) { return *entry->button; });
584 if (tablet_button_remapping_iter != settings.tablet_button_remappings.end()) {
David Padlipsky1eb6f0ae2024-01-08 18:49:21585 const mojom::ButtonRemapping& button_remapping =
586 *(*tablet_button_remapping_iter);
587 if (!button_remapping.remapping_action) {
588 return std::nullopt;
589 }
590
YuhanYang92cbe1592023-12-05 02:13:29591 auto tablet_action =
592 PeripheralCustomizationEventRewriter::RemappingActionResult(
David Padlipsky1eb6f0ae2024-01-08 18:49:21593 *button_remapping.remapping_action,
YuhanYang92cbe1592023-12-05 02:13:29594 PeripheralCustomizationEventRewriter::
595 PeripheralCustomizationMetricsType::kGraphicsTablet);
596 return std::move(tablet_action);
David Padlipskyf9728f272023-09-06 16:50:36597 }
598
David Padlipsky1eb6f0ae2024-01-08 18:49:21599 return std::nullopt;
David Padlipskyf9728f272023-09-06 16:50:36600}
601
602int GetRemappedModifiersFromMouseSettings(
603 const mojom::MouseSettings& settings) {
604 int modifiers = 0;
605 for (const auto& button_remapping : settings.button_remappings) {
David Padlipskyd664e672023-10-25 21:32:15606 if (button_remapping->remapping_action) {
607 modifiers |= ConvertButtonToFlags(*button_remapping->button);
608 }
David Padlipskyf9728f272023-09-06 16:50:36609 }
610 return modifiers;
611}
612
613int GetRemappedModifiersFromGraphicsTabletSettings(
614 const mojom::GraphicsTabletSettings& settings) {
615 int modifiers = 0;
616 for (const auto& button_remapping : settings.pen_button_remappings) {
617 modifiers |= ConvertButtonToFlags(*button_remapping->button);
618 }
619 for (const auto& button_remapping : settings.tablet_button_remappings) {
620 modifiers |= ConvertButtonToFlags(*button_remapping->button);
621 }
622 return modifiers;
623}
624
Danny Wanga917f0c2023-12-21 00:05:50625// Verify if the keyboard code is an alphabet letter.
626bool IsAlphaKeyboardCode(ui::KeyboardCode key_code) {
627 return key_code >= ui::VKEY_A && key_code <= ui::VKEY_Z;
628}
629
630// Verify if the keyboard code is a number.
631bool IsNumberKeyboardCode(ui::KeyboardCode key_code) {
632 return key_code >= ui::VKEY_0 && key_code <= ui::VKEY_9;
633}
634
David Padlipskyb5a52cd12023-08-08 21:45:19635} // namespace
636
David Padlipsky3b55bb12023-09-05 22:24:57637// Compares the `DeviceIdButton` struct based on first the device id, and then
638// the button stored within the `DeviceIdButton` struct.
639bool operator<(
640 const PeripheralCustomizationEventRewriter::DeviceIdButton& left,
641 const PeripheralCustomizationEventRewriter::DeviceIdButton& right) {
642 if (right.device_id != left.device_id) {
643 return left.device_id < right.device_id;
644 }
645
646 // If both are VKeys, compare them.
647 if (left.button->is_vkey() && right.button->is_vkey()) {
648 return left.button->get_vkey() < right.button->get_vkey();
649 }
650
651 // If both are customizable buttons, compare them.
652 if (left.button->is_customizable_button() &&
653 right.button->is_customizable_button()) {
654 return left.button->get_customizable_button() <
655 right.button->get_customizable_button();
656 }
657
658 // Otherwise, return true if the lhs is a VKey as they mismatch and VKeys
659 // should be considered less than customizable buttons.
660 return left.button->is_vkey();
661}
662
663PeripheralCustomizationEventRewriter::DeviceIdButton::DeviceIdButton(
664 int device_id,
665 mojom::ButtonPtr button)
666 : device_id(device_id), button(std::move(button)) {}
667
668PeripheralCustomizationEventRewriter::DeviceIdButton::DeviceIdButton(
669 DeviceIdButton&& device_id_button)
670 : device_id(device_id_button.device_id),
671 button(std::move(device_id_button.button)) {}
672
673PeripheralCustomizationEventRewriter::DeviceIdButton::~DeviceIdButton() =
674 default;
675
676PeripheralCustomizationEventRewriter::DeviceIdButton&
677PeripheralCustomizationEventRewriter::DeviceIdButton::operator=(
678 PeripheralCustomizationEventRewriter::DeviceIdButton&& device_id_button) =
679 default;
680
YuhanYang92cbe1592023-12-05 02:13:29681PeripheralCustomizationEventRewriter::RemappingActionResult::
682 RemappingActionResult(mojom::RemappingAction& remapping_action,
683 PeripheralCustomizationMetricsType peripheral_kind)
684 : remapping_action(remapping_action), peripheral_kind(peripheral_kind) {}
685
686PeripheralCustomizationEventRewriter::RemappingActionResult::
687 RemappingActionResult(RemappingActionResult&& result)
688 : remapping_action(std::move(result.remapping_action)),
689 peripheral_kind(result.peripheral_kind) {}
690
691PeripheralCustomizationEventRewriter::RemappingActionResult::
692 ~RemappingActionResult() = default;
693
David Padlipskyf9728f272023-09-06 16:50:36694PeripheralCustomizationEventRewriter::PeripheralCustomizationEventRewriter(
695 InputDeviceSettingsController* input_device_settings_controller)
YuhanYang92cbe1592023-12-05 02:13:29696 : input_device_settings_controller_(input_device_settings_controller) {
697 metrics_manager_ = std::make_unique<InputDeviceSettingsMetricsManager>();
698}
699
David Padlipsky5eaaade2023-07-21 22:39:38700PeripheralCustomizationEventRewriter::~PeripheralCustomizationEventRewriter() =
701 default;
702
Arthur Sonzognia98e4432023-11-28 18:15:01703std::optional<PeripheralCustomizationEventRewriter::DeviceType>
David Padlipskyeedcbfe2023-08-08 23:58:36704PeripheralCustomizationEventRewriter::GetDeviceTypeToObserve(int device_id) {
705 if (mice_to_observe_.contains(device_id)) {
706 return DeviceType::kMouse;
707 }
708 if (graphics_tablets_to_observe_.contains(device_id)) {
709 return DeviceType::kGraphicsTablet;
710 }
Arthur Sonzognia98e4432023-11-28 18:15:01711 return std::nullopt;
David Padlipskyeedcbfe2023-08-08 23:58:36712}
713
Danny Wang50d45182023-10-05 17:55:45714void PeripheralCustomizationEventRewriter::StartObservingMouse(
715 int device_id,
Danny Wang6bc788e2023-12-08 23:08:02716 mojom::CustomizationRestriction customization_restriction) {
717 mice_to_observe_.insert_or_assign(device_id, customization_restriction);
David Padlipskyb5a52cd12023-08-08 21:45:19718}
719
720void PeripheralCustomizationEventRewriter::StartObservingGraphicsTablet(
Danny Wangf2ecf152023-12-08 23:13:22721 int device_id,
722 mojom::CustomizationRestriction customization_restriction) {
723 graphics_tablets_to_observe_.insert_or_assign(device_id,
724 customization_restriction);
David Padlipskyb5a52cd12023-08-08 21:45:19725}
726
727void PeripheralCustomizationEventRewriter::StopObserving() {
728 graphics_tablets_to_observe_.clear();
729 mice_to_observe_.clear();
730}
731
David Padlipskyfe51c1162024-02-10 02:00:18732bool PeripheralCustomizationEventRewriter::NotifyMouseWheelEventObserving(
733 const ui::MouseWheelEvent& mouse_wheel_event,
734 DeviceType device_type) {
735 const auto customization_restriction_iter =
736 mice_to_observe_.find(mouse_wheel_event.source_device_id());
737 if (customization_restriction_iter == mice_to_observe_.end()) {
738 return false;
739 }
740
741 auto customization_restriction = customization_restriction_iter->second;
742 if (!AreScrollWheelEventRewritesAllowed(customization_restriction)) {
743 return false;
744 }
745
746 const mojom::ButtonPtr button =
747 GetButtonFromMouseWheelEvent(mouse_wheel_event);
748 if (!button) {
749 return false;
750 }
751
752 switch (device_type) {
753 case DeviceType::kMouse:
754 input_device_settings_controller_->OnMouseButtonPressed(
755 mouse_wheel_event.source_device_id(), *button);
756 break;
757 case DeviceType::kGraphicsTablet:
758 input_device_settings_controller_->OnGraphicsTabletButtonPressed(
759 mouse_wheel_event.source_device_id(), *button);
760 break;
761 }
762
763 return true;
764}
765
David Padlipskyb5a52cd12023-08-08 21:45:19766bool PeripheralCustomizationEventRewriter::NotifyMouseEventObserving(
767 const ui::MouseEvent& mouse_event,
768 DeviceType device_type) {
769 if (!IsMouseButtonEvent(mouse_event)) {
770 return false;
771 }
772
773 // Make sure the button is remappable for the current `device_type`.
774 switch (device_type) {
775 case DeviceType::kMouse:
776 if (!IsMouseRemappableButton(mouse_event.changed_button_flags())) {
777 return false;
778 }
779 break;
780 case DeviceType::kGraphicsTablet:
781 if (!IsGraphicsTabletRemappableButton(
782 mouse_event.changed_button_flags())) {
783 return false;
784 }
785 break;
786 }
787
788 if (mouse_event.type() != ui::ET_MOUSE_PRESSED) {
789 return true;
790 }
791
David Padlipskyb7896da2023-10-25 19:45:46792 const auto button = GetButtonFromMouseEvent(mouse_event);
David Padlipskyc16dd522023-09-08 21:18:22793 switch (device_type) {
794 case DeviceType::kMouse:
795 input_device_settings_controller_->OnMouseButtonPressed(
796 mouse_event.source_device_id(), *button);
797 break;
798 case DeviceType::kGraphicsTablet:
799 input_device_settings_controller_->OnGraphicsTabletButtonPressed(
800 mouse_event.source_device_id(), *button);
801 break;
David Padlipskyb5a52cd12023-08-08 21:45:19802 }
803
804 return true;
805}
806
Danny Wangab5c8a362023-12-15 22:34:18807bool PeripheralCustomizationEventRewriter::IsButtonCustomizable(
808 const ui::KeyEvent& key_event) {
809 const auto iter = mice_to_observe_.find(key_event.source_device_id());
810 if (iter == mice_to_observe().end()) {
811 return false;
812 }
813 const auto customization_restriction = iter->second;
814 // There are several cases for the customization restriction:
815 // 1. If restriction is kAllowCustomizations, mice are allowed to observe
816 // key events.
817 // 2. If restriction is kAllowAlphabetKeyEventRewrites, mice are allowed to
818 // observe only alphabet letters key event.
Danny Wange2a701872023-12-15 23:13:47819 // 3. If restriction is kAllowAlphabetOrNumberKeyEventRewrites, mice are
820 // allowed to observe alphabet letters or number key event.
821 // 4. Mice are not allowed to observe key event in other cases.
Danny Wangab5c8a362023-12-15 22:34:18822 switch (customization_restriction) {
823 case mojom::CustomizationRestriction::kAllowCustomizations:
824 return true;
825 case mojom::CustomizationRestriction::kAllowAlphabetKeyEventRewrites:
826 return IsAlphaKeyboardCode(key_event.key_code());
Danny Wange2a701872023-12-15 23:13:47827 case mojom::CustomizationRestriction::
828 kAllowAlphabetOrNumberKeyEventRewrites:
829 return IsAlphaKeyboardCode(key_event.key_code()) ||
Danny Wanga917f0c2023-12-21 00:05:50830 IsNumberKeyboardCode(key_event.key_code());
David Padlipsky07842e92024-02-13 01:18:46831 case mojom::CustomizationRestriction::kAllowTabEventRewrites:
832 return key_event.key_code() == ui::VKEY_TAB;
Danny Wangab5c8a362023-12-15 22:34:18833 case mojom::CustomizationRestriction::kDisallowCustomizations:
834 case mojom::CustomizationRestriction::kDisableKeyEventRewrites:
David Padlipskyfe51c1162024-02-10 02:00:18835 case mojom::CustomizationRestriction::kAllowHorizontalScrollWheelRewrites:
Danny Wangab5c8a362023-12-15 22:34:18836 return false;
837 }
838}
839
David Padlipskyeedcbfe2023-08-08 23:58:36840bool PeripheralCustomizationEventRewriter::NotifyKeyEventObserving(
841 const ui::KeyEvent& key_event,
842 DeviceType device_type) {
Danny Wangab5c8a362023-12-15 22:34:18843 if (device_type == DeviceType::kMouse && !IsButtonCustomizable(key_event)) {
844 return false;
Danny Wang50d45182023-10-05 17:55:45845 }
846
David Padlipskyeedcbfe2023-08-08 23:58:36847 // Observers should only be notified on key presses.
848 if (key_event.type() != ui::ET_KEY_PRESSED) {
849 return true;
850 }
851
852 const auto button = mojom::Button::NewVkey(key_event.key_code());
David Padlipskyc16dd522023-09-08 21:18:22853 switch (device_type) {
854 case DeviceType::kMouse:
855 input_device_settings_controller_->OnMouseButtonPressed(
856 key_event.source_device_id(), *button);
857 break;
858 case DeviceType::kGraphicsTablet:
859 input_device_settings_controller_->OnGraphicsTabletButtonPressed(
860 key_event.source_device_id(), *button);
861 break;
David Padlipskyeedcbfe2023-08-08 23:58:36862 }
863
864 return true;
865}
866
David Padlipskycc7c2de2023-08-23 17:16:54867bool PeripheralCustomizationEventRewriter::RewriteEventFromButton(
868 const ui::Event& event,
869 const mojom::Button& button,
David Padlipskya0e5e022024-02-10 00:08:03870 std::vector<std::unique_ptr<ui::Event>>& rewritten_events) {
871 absl::optional<RemappingActionResult> remapping_action_result =
872 GetRemappingAction(event.source_device_id(), button);
YuhanYang92cbe1592023-12-05 02:13:29873 if (!remapping_action_result) {
David Padlipskycc7c2de2023-08-23 17:16:54874 return false;
875 }
YuhanYang92cbe1592023-12-05 02:13:29876 auto remapping_action = remapping_action_result->remapping_action;
877
David Padlipsky459bb3b2024-02-07 20:31:03878 if (event.type() == ui::ET_KEY_PRESSED ||
879 event.type() == ui::ET_MOUSE_PRESSED) {
880 metrics_manager_->RecordRemappingActionWhenButtonPressed(
881 *remapping_action,
882 ToMetricsString(remapping_action_result->peripheral_kind).data());
883 }
David Padlipskycc7c2de2023-08-23 17:16:54884
Danny Wangd388f6b2023-09-29 00:06:50885 if (remapping_action->is_accelerator_action()) {
David Padlipskyf8730952023-09-01 19:38:27886 if (event.type() == ui::ET_KEY_PRESSED ||
David Padlipskyfe51c1162024-02-10 02:00:18887 event.type() == ui::ET_MOUSE_PRESSED ||
888 event.type() == ui::ET_MOUSEWHEEL) {
David Padlipskyf8730952023-09-01 19:38:27889 // Every accelerator supported by peripheral customization is not impacted
890 // by the accelerator passed. Therefore, passing an empty accelerator will
891 // cause no issues.
892 Shell::Get()->accelerator_controller()->PerformActionIfEnabled(
Danny Wangd388f6b2023-09-29 00:06:50893 remapping_action->get_accelerator_action(), /*accelerator=*/{});
David Padlipskyf8730952023-09-01 19:38:27894 }
895
David Padlipskycc7c2de2023-08-23 17:16:54896 return true;
897 }
898
David Padlipsky3472a1e2024-02-16 19:12:40899 // Get flags to release in rewriting key events.
900 int flags_to_release = 0;
901 auto iter =
902 device_button_to_flags_.find({event.source_device_id(), button.Clone()});
903 if (iter != device_button_to_flags_.end()) {
904 flags_to_release = iter->second;
905 }
906
David Padlipskycc7c2de2023-08-23 17:16:54907 if (remapping_action->is_key_event()) {
908 const auto& key_event = remapping_action->get_key_event();
David Padlipsky5b39dc02024-01-03 20:36:48909 auto entry = FindKeyCodeEntry(key_event->vkey);
910 // If no entry can be found, use the stored key_event struct.
911 if (!entry) {
David Padlipsky3472a1e2024-02-16 19:12:40912 rewritten_events =
913 RewriteEventToKeyEvents(event, *key_event, flags_to_release);
David Padlipsky5b39dc02024-01-03 20:36:48914 } else {
David Padlipskya0e5e022024-02-10 00:08:03915 rewritten_events = RewriteEventToKeyEvents(
David Padlipsky3472a1e2024-02-16 19:12:40916 event,
917 mojom::KeyEvent(
918 entry->resulting_key_code, static_cast<int>(entry->dom_code),
919 static_cast<int>(entry->dom_key), key_event->modifiers, ""),
920 flags_to_release);
David Padlipsky5b39dc02024-01-03 20:36:48921 }
Danny Wang6bdb5582023-09-18 21:27:29922 }
923
Danny Wangd388f6b2023-09-29 00:06:50924 if (remapping_action->is_static_shortcut_action()) {
David Padlipskyd664e672023-10-25 21:32:15925 const auto static_action = remapping_action->get_static_shortcut_action();
926 if (static_action == mojom::StaticShortcutAction::kDisable) {
Danny Wang75a9a86f2023-09-29 21:00:30927 // Return true to discard the event.
928 return true;
929 }
David Padlipskyd664e672023-10-25 21:32:15930
931 if (kStaticActionToMouseButtonFlag.contains(static_action)) {
David Padlipskyfe51c1162024-02-10 02:00:18932 rewritten_events = RewriteEventToMouseButtonEvents(event, static_action);
David Padlipskyd664e672023-10-25 21:32:15933 } else {
David Padlipskya0e5e022024-02-10 00:08:03934 rewritten_events = RewriteEventToKeyEvents(
David Padlipsky3472a1e2024-02-16 19:12:40935 event,
936 GetStaticShortcutAction(
937 remapping_action->get_static_shortcut_action()),
938 flags_to_release);
David Padlipskyd664e672023-10-25 21:32:15939 }
David Padlipskycc7c2de2023-08-23 17:16:54940 }
941
942 return false;
943}
944
David Padlipskyeedcbfe2023-08-08 23:58:36945ui::EventDispatchDetails PeripheralCustomizationEventRewriter::RewriteKeyEvent(
946 const ui::KeyEvent& key_event,
947 const Continuation continuation) {
948 auto device_type_to_observe =
949 GetDeviceTypeToObserve(key_event.source_device_id());
950 if (device_type_to_observe) {
951 if (NotifyKeyEventObserving(key_event, *device_type_to_observe)) {
952 return DiscardEvent(continuation);
953 }
954 }
955
David Padlipskya0e5e022024-02-10 00:08:03956 // Clone event and remove the already remapped modifiers and use this as the
957 // "source" key event for the rest of the rewriting.
958 std::unique_ptr<ui::Event> original_event_with_modifiers_removed =
959 CloneEvent(key_event);
960 RemoveRemappedModifiers(*original_event_with_modifiers_removed);
961
962 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
David Padlipsky3b55bb12023-09-05 22:24:57963 mojom::ButtonPtr button = mojom::Button::NewVkey(key_event.key_code());
David Padlipsky3394af92023-10-27 21:30:50964 bool updated_button_map = false;
David Padlipskya0e5e022024-02-10 00:08:03965 if (RewriteEventFromButton(*original_event_with_modifiers_removed, *button,
966 rewritten_events)) {
David Padlipskycc7c2de2023-08-23 17:16:54967 return DiscardEvent(continuation);
968 }
David Padlipsky3394af92023-10-27 21:30:50969
David Padlipskya0e5e022024-02-10 00:08:03970 const bool event_rewritten = !rewritten_events.empty();
David Padlipskycc7c2de2023-08-23 17:16:54971
David Padlipskya0e5e022024-02-10 00:08:03972 // Discard all "button" type events usually from graphics tablets.
973 if (!event_rewritten && key_event.key_code() >= ui::VKEY_BUTTON_0 &&
David Padlipsky341564182024-01-11 22:09:32974 key_event.key_code() <= ui::VKEY_BUTTON_Z) {
975 return DiscardEvent(continuation);
976 }
977
David Padlipskya0e5e022024-02-10 00:08:03978 // Add an event to our list to rewrite based on other pressed buttons.
979 if (rewritten_events.empty()) {
980 rewritten_events.push_back(
981 std::move(original_event_with_modifiers_removed));
David Padlipskycc7c2de2023-08-23 17:16:54982 }
983
David Padlipskya0e5e022024-02-10 00:08:03984 // If the button was released, the pressed button map must be updated before
985 // applying remapped modifiers.
986 const ui::Event& last_rewritten_event = *rewritten_events.back();
987 if (event_rewritten &&
988 (last_rewritten_event.type() == ui::ET_MOUSE_RELEASED ||
989 last_rewritten_event.type() == ui::ET_KEY_RELEASED)) {
990 updated_button_map = true;
991 UpdatePressedButtonMap(std::move(button), key_event, rewritten_events);
David Padlipsky3394af92023-10-27 21:30:50992 }
993
David Padlipsky3472a1e2024-02-16 19:12:40994 // Remove flags from modifiers that are released on other devices.
995 if (!event_rewritten) {
996 UpdatePressedButtonMapFlags(key_event);
997 }
998
David Padlipskya0e5e022024-02-10 00:08:03999 for (const auto& rewritten_event : rewritten_events) {
1000 ApplyRemappedModifiers(*rewritten_event);
1001 }
1002
1003 if (event_rewritten && !updated_button_map) {
1004 UpdatePressedButtonMap(std::move(button), key_event, rewritten_events);
1005 }
1006
1007 ui::EventDispatchDetails details;
1008 for (const auto& rewritten_event : rewritten_events) {
1009 details = SendEvent(continuation, rewritten_event.get());
1010 }
1011 return details;
David Padlipskyeedcbfe2023-08-08 23:58:361012}
1013
David Padlipsky3b55bb12023-09-05 22:24:571014void PeripheralCustomizationEventRewriter::UpdatePressedButtonMap(
1015 mojom::ButtonPtr button,
1016 const ui::Event& original_event,
David Padlipskya0e5e022024-02-10 00:08:031017 const std::vector<std::unique_ptr<ui::Event>>& rewritten_events) {
David Padlipskyfe51c1162024-02-10 02:00:181018 // Scroll wheel events cannot affect other events modifiers since they do a
1019 // full press/release sequence with the one event.
1020 if (original_event.type() == ui::ET_MOUSEWHEEL) {
1021 return;
1022 }
1023
David Padlipsky3b55bb12023-09-05 22:24:571024 DeviceIdButton device_id_button_key =
1025 DeviceIdButton{original_event.source_device_id(), std::move(button)};
David Padlipsky3394af92023-10-27 21:30:501026 // If the button is released, the entry must be removed from the map.
1027 if (original_event.type() == ui::ET_MOUSE_RELEASED ||
1028 original_event.type() == ui::ET_KEY_RELEASED) {
1029 device_button_to_flags_.erase(std::move(device_id_button_key));
David Padlipsky3472a1e2024-02-16 19:12:401030
1031 // Release all modifier flags on other currently pressed buttons.
1032 for (const auto& rewritten_event : rewritten_events) {
1033 if (rewritten_event->IsKeyEvent()) {
1034 UpdatePressedButtonMapFlags(*rewritten_event->AsKeyEvent());
1035 }
1036 }
David Padlipsky3394af92023-10-27 21:30:501037 return;
1038 }
1039
David Padlipskya0e5e022024-02-10 00:08:031040 // For each rewritten event, combine the flags that need to be applied to
1041 // correctly handle the newly pressed event. This matters when pressing a
1042 // modifier or a key with a combo of modifiers or when holding a rewritten
1043 // mouse button.
1044 ui::EventFlags event_flags = 0;
1045 for (const auto& rewritten_event : rewritten_events) {
1046 if (!rewritten_event) {
1047 continue;
1048 }
David Padlipsky3b55bb12023-09-05 22:24:571049
David Padlipskya0e5e022024-02-10 00:08:031050 if (rewritten_event->IsKeyEvent()) {
1051 const auto& key_event = *rewritten_event->AsKeyEvent();
1052 event_flags |= ConvertKeyCodeToFlags(key_event.key_code());
1053 continue;
1054 }
1055
1056 if (rewritten_event->IsMouseEvent()) {
1057 const auto& mouse_event = *rewritten_event->AsMouseEvent();
1058 event_flags |= mouse_event.changed_button_flags();
1059 continue;
1060 }
1061 }
1062
1063 if (!event_flags) {
David Padlipsky3b55bb12023-09-05 22:24:571064 return;
1065 }
1066
1067 // Add the entry to the map with the flags that must be applied to other
1068 // events.
1069 device_button_to_flags_.insert_or_assign(std::move(device_id_button_key),
David Padlipskya0e5e022024-02-10 00:08:031070 event_flags);
David Padlipsky3b55bb12023-09-05 22:24:571071}
1072
David Padlipsky3472a1e2024-02-16 19:12:401073void PeripheralCustomizationEventRewriter::UpdatePressedButtonMapFlags(
1074 const ui::KeyEvent& key_event) {
1075 if (key_event.type() == ui::ET_KEY_PRESSED) {
1076 return;
1077 }
1078
1079 // Remap the released key based on modifier remappings.
1080 auto* settings = input_device_settings_controller_->GetKeyboardSettings(
1081 key_event.source_device_id());
1082 auto modifier_key = ConvertDomCodeToModifierKey(key_event.code());
1083 int key_event_characteristic_flag =
1084 ConvertKeyCodeToFlags(key_event.key_code());
1085 if (settings && modifier_key) {
1086 auto iter = settings->modifier_remappings.find(*modifier_key);
1087 if (iter != settings->modifier_remappings.end()) {
1088 key_event_characteristic_flag = ConvertModifierKeyToFlags(iter->second);
1089 }
1090 }
1091
1092 // Remove the key event characteristic flag as the key has already been
1093 // released and should no longer apply the flag to other pressed events.
1094 for (auto& [_, flag] : device_button_to_flags_) {
1095 flag &= ~key_event_characteristic_flag;
1096 }
1097}
1098
David Padlipskyb5a52cd12023-08-08 21:45:191099ui::EventDispatchDetails
David Padlipskyfe51c1162024-02-10 02:00:181100PeripheralCustomizationEventRewriter::RewriteMouseWheelEvent(
1101 const ui::MouseWheelEvent& mouse_wheel_event,
1102 const Continuation continuation) {
1103 auto device_type_to_observe =
1104 GetDeviceTypeToObserve(mouse_wheel_event.source_device_id());
1105 if (device_type_to_observe) {
1106 if (NotifyMouseWheelEventObserving(mouse_wheel_event,
1107 *device_type_to_observe)) {
1108 return DiscardEvent(continuation);
1109 }
1110
1111 // Otherwise, the flags must be cleared for the remappable buttons so they
1112 // do not affect the application while the mouse is meant to be observed.
1113 std::unique_ptr<ui::Event> rewritten_event = CloneEvent(mouse_wheel_event);
1114 const int remappable_flags =
1115 GetRemappableMouseEventFlags(*device_type_to_observe);
1116 rewritten_event->SetFlags(rewritten_event->flags() & ~remappable_flags);
1117 if (rewritten_event->IsMouseEvent()) {
1118 auto& rewritten_mouse_event = *rewritten_event->AsMouseEvent();
1119 rewritten_mouse_event.set_changed_button_flags(
1120 rewritten_mouse_event.changed_button_flags() & ~remappable_flags);
1121 }
1122 return SendEvent(continuation, rewritten_event.get());
1123 }
1124
1125 // Clone event and remove the already remapped modifiers and use this as the
1126 // "source" key event for the rest of the rewriting.
1127 std::unique_ptr<ui::Event> original_event_with_modifiers_removed =
1128 CloneEvent(mouse_wheel_event);
1129 RemoveRemappedModifiers(*original_event_with_modifiers_removed);
1130
1131 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
1132 mojom::ButtonPtr button = GetButtonFromMouseWheelEvent(mouse_wheel_event);
1133 bool updated_button_map = false;
1134 if (!button.is_null()) {
1135 if (RewriteEventFromButton(*original_event_with_modifiers_removed, *button,
1136 rewritten_events)) {
1137 return DiscardEvent(continuation);
1138 }
1139 }
1140
1141 const bool event_rewritten = !rewritten_events.empty();
1142
1143 // Add an event to our list to rewrite based on other pressed buttons.
1144 if (!event_rewritten) {
1145 rewritten_events.push_back(
1146 std::move(original_event_with_modifiers_removed));
1147 }
1148
1149 // If the button was released, the pressed button map must be updated before
1150 // applying remapped modifiers.
1151 const ui::Event& last_rewritten_event = *rewritten_events.back();
1152 if (event_rewritten &&
1153 (last_rewritten_event.type() == ui::ET_MOUSE_RELEASED ||
1154 last_rewritten_event.type() == ui::ET_KEY_RELEASED)) {
1155 updated_button_map = true;
1156 UpdatePressedButtonMap(std::move(button), mouse_wheel_event,
1157 rewritten_events);
1158 }
1159
1160 for (const auto& rewritten_event : rewritten_events) {
1161 ApplyRemappedModifiers(*rewritten_event);
1162 }
1163
1164 if (event_rewritten && !updated_button_map) {
1165 UpdatePressedButtonMap(std::move(button), mouse_wheel_event,
1166 rewritten_events);
1167 }
1168
1169 ui::EventDispatchDetails details;
1170 for (const auto& rewritten_event : rewritten_events) {
1171 details = SendEvent(continuation, rewritten_event.get());
1172 }
1173 return details;
1174}
1175
1176ui::EventDispatchDetails
David Padlipskyb5a52cd12023-08-08 21:45:191177PeripheralCustomizationEventRewriter::RewriteMouseEvent(
1178 const ui::MouseEvent& mouse_event,
1179 const Continuation continuation) {
David Padlipskyeedcbfe2023-08-08 23:58:361180 auto device_type_to_observe =
1181 GetDeviceTypeToObserve(mouse_event.source_device_id());
1182 if (device_type_to_observe) {
1183 if (NotifyMouseEventObserving(mouse_event, *device_type_to_observe)) {
David Padlipskyb5a52cd12023-08-08 21:45:191184 return DiscardEvent(continuation);
1185 }
1186
1187 // Otherwise, the flags must be cleared for the remappable buttons so they
1188 // do not affect the application while the mouse is meant to be observed.
David Padlipskydcd57e12023-10-25 23:00:181189 std::unique_ptr<ui::Event> rewritten_event = CloneEvent(mouse_event);
David Padlipskyeedcbfe2023-08-08 23:58:361190 const int remappable_flags =
1191 GetRemappableMouseEventFlags(*device_type_to_observe);
David Padlipsky4687d1e12024-01-04 00:18:451192 rewritten_event->SetFlags(rewritten_event->flags() & ~remappable_flags);
David Padlipskydcd57e12023-10-25 23:00:181193 if (rewritten_event->IsMouseEvent()) {
1194 auto& rewritten_mouse_event = *rewritten_event->AsMouseEvent();
1195 rewritten_mouse_event.set_changed_button_flags(
1196 rewritten_mouse_event.changed_button_flags() & ~remappable_flags);
1197 }
1198 return SendEvent(continuation, rewritten_event.get());
David Padlipskyb5a52cd12023-08-08 21:45:191199 }
1200
David Padlipskya0e5e022024-02-10 00:08:031201 // Clone event and remove the already remapped modifiers and use this as the
1202 // "source" key event for the rest of the rewriting.
1203 std::unique_ptr<ui::Event> original_event_with_modifiers_removed =
1204 CloneEvent(mouse_event);
1205 RemoveRemappedModifiers(*original_event_with_modifiers_removed);
1206
1207 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
David Padlipsky3394af92023-10-27 21:30:501208 mojom::ButtonPtr button;
1209 bool updated_button_map = false;
David Padlipsky3b55bb12023-09-05 22:24:571210 if (IsMouseButtonEvent(mouse_event) && mouse_event.changed_button_flags()) {
David Padlipsky3394af92023-10-27 21:30:501211 button = GetButtonFromMouseEvent(mouse_event);
David Padlipskya0e5e022024-02-10 00:08:031212 if (RewriteEventFromButton(*original_event_with_modifiers_removed, *button,
1213 rewritten_events)) {
David Padlipskycc7c2de2023-08-23 17:16:541214 return DiscardEvent(continuation);
1215 }
David Padlipskycc7c2de2023-08-23 17:16:541216 }
David Padlipsky3394af92023-10-27 21:30:501217
David Padlipskya0e5e022024-02-10 00:08:031218 const bool event_rewritten = !rewritten_events.empty();
1219
1220 // Add an event to our list to rewrite based on other pressed buttons.
1221 if (!event_rewritten) {
1222 rewritten_events.push_back(
1223 std::move(original_event_with_modifiers_removed));
David Padlipskycc7c2de2023-08-23 17:16:541224 }
1225
David Padlipskya0e5e022024-02-10 00:08:031226 // If the button was released, the pressed button map must be updated before
1227 // applying remapped modifiers.
1228 const ui::Event& last_rewritten_event = *rewritten_events.back();
1229 if (event_rewritten &&
1230 (last_rewritten_event.type() == ui::ET_MOUSE_RELEASED ||
1231 last_rewritten_event.type() == ui::ET_KEY_RELEASED)) {
1232 updated_button_map = true;
1233 UpdatePressedButtonMap(std::move(button), mouse_event, rewritten_events);
David Padlipsky3394af92023-10-27 21:30:501234 }
1235
David Padlipskya0e5e022024-02-10 00:08:031236 for (const auto& rewritten_event : rewritten_events) {
1237 ApplyRemappedModifiers(*rewritten_event);
1238 }
1239
1240 if (event_rewritten && !updated_button_map) {
1241 UpdatePressedButtonMap(std::move(button), mouse_event, rewritten_events);
1242 }
1243
1244 ui::EventDispatchDetails details;
1245 for (const auto& rewritten_event : rewritten_events) {
1246 details = SendEvent(continuation, rewritten_event.get());
1247 }
1248 return details;
David Padlipskyb5a52cd12023-08-08 21:45:191249}
1250
David Padlipsky5eaaade2023-07-21 22:39:381251ui::EventDispatchDetails PeripheralCustomizationEventRewriter::RewriteEvent(
1252 const ui::Event& event,
1253 const Continuation continuation) {
Jimmyb36a8772023-11-10 19:41:391254 DCHECK(features::IsPeripheralCustomizationEnabled() ||
1255 ::features::IsShortcutCustomizationEnabled());
David Padlipskyb5a52cd12023-08-08 21:45:191256
David Padlipskyfe51c1162024-02-10 02:00:181257 if (event.IsMouseWheelEvent()) {
1258 return RewriteMouseWheelEvent(*event.AsMouseWheelEvent(), continuation);
1259 }
1260
David Padlipskyb5a52cd12023-08-08 21:45:191261 if (event.IsMouseEvent()) {
1262 return RewriteMouseEvent(*event.AsMouseEvent(), continuation);
1263 }
1264
David Padlipskyeedcbfe2023-08-08 23:58:361265 if (event.IsKeyEvent()) {
1266 return RewriteKeyEvent(*event.AsKeyEvent(), continuation);
1267 }
1268
David Padlipsky5eaaade2023-07-21 22:39:381269 return SendEvent(continuation, &event);
1270}
1271
YuhanYang92cbe1592023-12-05 02:13:291272std::optional<PeripheralCustomizationEventRewriter::RemappingActionResult>
David Padlipskycc7c2de2023-08-23 17:16:541273PeripheralCustomizationEventRewriter::GetRemappingAction(
1274 int device_id,
1275 const mojom::Button& button) {
David Padlipskyf9728f272023-09-06 16:50:361276 const auto* mouse_settings =
1277 input_device_settings_controller_->GetMouseSettings(device_id);
1278 if (mouse_settings) {
1279 return GetRemappingActionFromMouseSettings(button, *mouse_settings);
David Padlipskycc7c2de2023-08-23 17:16:541280 }
1281
David Padlipskyf9728f272023-09-06 16:50:361282 const auto* graphics_tablet_settings =
1283 input_device_settings_controller_->GetGraphicsTabletSettings(device_id);
1284 if (graphics_tablet_settings) {
1285 return GetRemappingActionFromGraphicsTabletSettings(
1286 button, *graphics_tablet_settings);
David Padlipskycc7c2de2023-08-23 17:16:541287 }
1288
YuhanYang92cbe1592023-12-05 02:13:291289 return absl::nullopt;
David Padlipskycc7c2de2023-08-23 17:16:541290}
1291
1292void PeripheralCustomizationEventRewriter::RemoveRemappedModifiers(
1293 ui::Event& event) {
David Padlipskyf9728f272023-09-06 16:50:361294 int modifier_flags = 0;
1295 if (const auto* mouse_settings =
1296 input_device_settings_controller_->GetMouseSettings(
1297 event.source_device_id());
1298 mouse_settings) {
1299 modifier_flags = GetRemappedModifiersFromMouseSettings(*mouse_settings);
1300 } else if (const auto* graphics_tablet_settings =
1301 input_device_settings_controller_->GetGraphicsTabletSettings(
1302 event.source_device_id());
1303 graphics_tablet_settings) {
1304 modifier_flags = GetRemappedModifiersFromGraphicsTabletSettings(
1305 *graphics_tablet_settings);
David Padlipskycc7c2de2023-08-23 17:16:541306 }
1307
1308 // TODO(dpad): This logic isn't quite correct. If a second devices is holding
1309 // "Ctrl" and the original device has a button that is "Ctrl" that is
1310 // remapped, this will behave incorrectly as it will remove "Ctrl". Instead,
1311 // this needs to track what keys are being pressed by the device that have
1312 // modifiers attached to them. For now, this is close enough to being correct.
David Padlipsky4687d1e12024-01-04 00:18:451313 event.SetFlags(event.flags() & ~modifier_flags);
David Padlipskycc7c2de2023-08-23 17:16:541314}
1315
David Padlipsky3b55bb12023-09-05 22:24:571316void PeripheralCustomizationEventRewriter::ApplyRemappedModifiers(
1317 ui::Event& event) {
1318 int flags = 0;
1319 for (const auto& [_, flag] : device_button_to_flags_) {
1320 flags |= flag;
1321 }
David Padlipsky4687d1e12024-01-04 00:18:451322 event.SetFlags(event.flags() | flags);
David Padlipsky3b55bb12023-09-05 22:24:571323}
1324
David Padlipskydcd57e12023-10-25 23:00:181325std::unique_ptr<ui::Event> PeripheralCustomizationEventRewriter::CloneEvent(
1326 const ui::Event& event) {
1327 std::unique_ptr<ui::Event> cloned_event = event.Clone();
1328 // SetNativeEvent must be called explicitly as native events are not copied
1329 // on ChromeOS by default. This is because `PlatformEvent` is a pointer by
1330 // default, so its lifetime can not be guaranteed in general. In this case,
1331 // the lifetime of `rewritten_event` is guaranteed to be less than the
1332 // original `mouse_event`.
1333 SetNativeEvent(*cloned_event, event.native_event());
1334 return cloned_event;
1335}
1336
David Padlipsky5eaaade2023-07-21 22:39:381337} // namespace ash