blob: c2dd76401bdd1130b34e14fa61dca7f04abc1f13 [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 Padlipsky086da5772024-02-16 23:17:3116#include "ash/public/cpp/input_device_settings_controller.h"
David Padlipsky3b55bb12023-09-05 22:24:5717#include "ash/public/mojom/input_device_settings.mojom-forward.h"
David Padlipskyb5a52cd12023-08-08 21:45:1918#include "ash/public/mojom/input_device_settings.mojom-shared.h"
19#include "ash/public/mojom/input_device_settings.mojom.h"
David Padlipskyf8730952023-09-01 19:38:2720#include "ash/shell.h"
David Padlipskyf9728f272023-09-06 16:50:3621#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
David Padlipsky5eaaade2023-07-21 22:39:3822#include "base/check.h"
David Padlipskya0e5e022024-02-10 00:08:0323#include "base/check_op.h"
David Padlipskyd664e672023-10-25 21:32:1524#include "base/containers/fixed_flat_map.h"
David Padlipskya0e5e022024-02-10 00:08:0325#include "base/containers/span.h"
David Padlipsky086da5772024-02-16 23:17:3126#include "base/metrics/histogram_functions.h"
David Padlipskyb5a52cd12023-08-08 21:45:1927#include "base/notreached.h"
David Padlipskycc7c2de2023-08-23 17:16:5428#include "base/ranges/algorithm.h"
David Padlipsky3472a1e2024-02-16 19:12:4029#include "base/strings/string_util.h"
David Padlipsky086da5772024-02-16 23:17:3130#include "base/strings/stringprintf.h"
Jimmyb36a8772023-11-10 19:41:3931#include "ui/base/ui_base_features.h"
David Padlipskyd664e672023-10-25 21:32:1532#include "ui/display/screen.h"
David Padlipsky3472a1e2024-02-16 19:12:4033#include "ui/events/ash/mojom/modifier_key.mojom-shared.h"
David Padlipskyb5a52cd12023-08-08 21:45:1934#include "ui/events/event.h"
35#include "ui/events/event_constants.h"
36#include "ui/events/event_dispatcher.h"
David Padlipskyd664e672023-10-25 21:32:1537#include "ui/events/event_utils.h"
David Padlipskycc7c2de2023-08-23 17:16:5438#include "ui/events/keycodes/dom/dom_code.h"
39#include "ui/events/keycodes/dom/dom_key.h"
40#include "ui/events/keycodes/keyboard_codes_posix.h"
David Padlipskyb7896da2023-10-25 19:45:4641#include "ui/events/ozone/evdev/mouse_button_property.h"
David Padlipsky5b39dc02024-01-03 20:36:4842#include "ui/events/ozone/layout/keyboard_layout_engine.h"
43#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
David Padlipskyb5a52cd12023-08-08 21:45:1944#include "ui/events/types/event_type.h"
David Padlipskyd664e672023-10-25 21:32:1545#include "ui/gfx/geometry/point_f.h"
David Padlipsky5eaaade2023-07-21 22:39:3846
47namespace ash {
48
David Padlipskyb5a52cd12023-08-08 21:45:1949namespace {
50
David Padlipskya0e5e022024-02-10 00:08:0351using RemappingActionResult =
52 PeripheralCustomizationEventRewriter::RemappingActionResult;
53
David Padlipskyb5a52cd12023-08-08 21:45:1954constexpr int kMouseRemappableFlags = ui::EF_BACK_MOUSE_BUTTON |
55 ui::EF_FORWARD_MOUSE_BUTTON |
56 ui::EF_MIDDLE_MOUSE_BUTTON;
57
58constexpr int kGraphicsTabletRemappableFlags =
59 ui::EF_RIGHT_MOUSE_BUTTON | ui::EF_BACK_MOUSE_BUTTON |
60 ui::EF_FORWARD_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON;
61
David Padlipskyd664e672023-10-25 21:32:1562constexpr auto kStaticActionToMouseButtonFlag =
63 base::MakeFixedFlatMap<mojom::StaticShortcutAction, ui::EventFlags>({
64 {mojom::StaticShortcutAction::kLeftClick, ui::EF_LEFT_MOUSE_BUTTON},
65 {mojom::StaticShortcutAction::kRightClick, ui::EF_RIGHT_MOUSE_BUTTON},
66 {mojom::StaticShortcutAction::kMiddleClick, ui::EF_MIDDLE_MOUSE_BUTTON},
67 });
68
David Padlipsky74935f592024-02-02 00:24:4169constexpr std::string_view ToMetricsString(
YuhanYang92cbe1592023-12-05 02:13:2970 PeripheralCustomizationEventRewriter::PeripheralCustomizationMetricsType
71 peripheral_kind) {
72 switch (peripheral_kind) {
73 case PeripheralCustomizationEventRewriter::
74 PeripheralCustomizationMetricsType::kMouse:
David Padlipsky74935f592024-02-02 00:24:4175 return "Mouse";
YuhanYang92cbe1592023-12-05 02:13:2976 case PeripheralCustomizationEventRewriter::
77 PeripheralCustomizationMetricsType::kGraphicsTablet:
David Padlipsky74935f592024-02-02 00:24:4178 return "GraphicsTablet";
YuhanYang92cbe1592023-12-05 02:13:2979 case PeripheralCustomizationEventRewriter::
80 PeripheralCustomizationMetricsType::kGraphicsTabletPen:
David Padlipsky74935f592024-02-02 00:24:4181 return "GraphicsTabletPen";
YuhanYang92cbe1592023-12-05 02:13:2982 }
83}
84
Danny Wangd388f6b2023-09-29 00:06:5085mojom::KeyEvent GetStaticShortcutAction(mojom::StaticShortcutAction action) {
Danny Wang6bdb5582023-09-18 21:27:2986 mojom::KeyEvent key_event;
87 switch (action) {
Danny Wang75a9a86f2023-09-29 21:00:3088 case mojom::StaticShortcutAction::kDisable:
David Padlipskyd664e672023-10-25 21:32:1589 case mojom::StaticShortcutAction::kLeftClick:
90 case mojom::StaticShortcutAction::kRightClick:
91 case mojom::StaticShortcutAction::kMiddleClick:
Danny Wang75a9a86f2023-09-29 21:00:3092 NOTREACHED_NORETURN();
Danny Wangd388f6b2023-09-29 00:06:5093 case mojom::StaticShortcutAction::kCopy:
Danny Wang6bdb5582023-09-18 21:27:2994 key_event = mojom::KeyEvent(
95 ui::VKEY_C, static_cast<int>(ui::DomCode::US_C),
96 static_cast<int>(ui::DomKey::Constant<'c'>::Character),
David Padlipskyfc60da892023-10-27 00:14:3197 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang6bdb5582023-09-18 21:27:2998 break;
Danny Wangd388f6b2023-09-29 00:06:5099 case mojom::StaticShortcutAction::kPaste:
Danny Wang6bdb5582023-09-18 21:27:29100 key_event = mojom::KeyEvent(
101 ui::VKEY_V, static_cast<int>(ui::DomCode::US_V),
102 static_cast<int>(ui::DomKey::Constant<'v'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31103 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang6bdb5582023-09-18 21:27:29104 break;
Danny Wang0dfd3b02023-10-19 01:36:02105 case mojom::StaticShortcutAction::kUndo:
106 key_event = mojom::KeyEvent(
107 ui::VKEY_Z, static_cast<int>(ui::DomCode::US_Z),
108 static_cast<int>(ui::DomKey::Constant<'z'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31109 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02110 break;
111 case mojom::StaticShortcutAction::kRedo:
112 key_event = mojom::KeyEvent(
113 ui::VKEY_Z, static_cast<int>(ui::DomCode::US_Z),
114 static_cast<int>(ui::DomKey::Constant<'z'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31115 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02116 break;
117 case mojom::StaticShortcutAction::kZoomIn:
118 key_event = mojom::KeyEvent(
119 ui::VKEY_OEM_PLUS, static_cast<int>(ui::DomCode::EQUAL),
120 static_cast<int>(ui::DomKey::Constant<'='>::Character),
David Padlipskyfc60da892023-10-27 00:14:31121 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02122 break;
123 case mojom::StaticShortcutAction::kZoomOut:
124 key_event = mojom::KeyEvent(
125 ui::VKEY_OEM_MINUS, static_cast<int>(ui::DomCode::MINUS),
126 static_cast<int>(ui::DomKey::Constant<'-'>::Character),
David Padlipskyfc60da892023-10-27 00:14:31127 ui::EF_CONTROL_DOWN, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02128 break;
129 case mojom::StaticShortcutAction::kPreviousPage:
David Padlipskyfc60da892023-10-27 00:14:31130 key_event = mojom::KeyEvent(ui::VKEY_BROWSER_BACK,
131 static_cast<int>(ui::DomCode::BROWSER_BACK),
132 static_cast<int>(ui::DomKey::BROWSER_BACK),
133 ui::EF_NONE, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02134 break;
135 case mojom::StaticShortcutAction::kNextPage:
David Padlipskyfc60da892023-10-27 00:14:31136 key_event =
137 mojom::KeyEvent(ui::VKEY_BROWSER_FORWARD,
138 static_cast<int>(ui::DomCode::BROWSER_FORWARD),
139 static_cast<int>(ui::DomKey::BROWSER_FORWARD),
140 ui::EF_NONE, /*key_display=*/"");
Danny Wang0dfd3b02023-10-19 01:36:02141 break;
Danny Wang6bdb5582023-09-18 21:27:29142 }
143 return key_event;
144}
145
David Padlipsky3394af92023-10-27 21:30:50146int ConvertKeyCodeToFlags(ui::KeyboardCode key_code) {
147 switch (key_code) {
148 case ui::VKEY_LWIN:
149 case ui::VKEY_RWIN:
150 return ui::EF_COMMAND_DOWN;
151 case ui::VKEY_CONTROL:
David Padlipsky5b39dc02024-01-03 20:36:48152 case ui::VKEY_RCONTROL:
David Padlipsky3394af92023-10-27 21:30:50153 return ui::EF_CONTROL_DOWN;
154 case ui::VKEY_SHIFT:
155 case ui::VKEY_LSHIFT:
156 case ui::VKEY_RSHIFT:
157 return ui::EF_SHIFT_DOWN;
158 case ui::VKEY_MENU:
159 case ui::VKEY_RMENU:
160 return ui::EF_ALT_DOWN;
161 default:
162 return ui::EF_NONE;
163 }
164}
165
David Padlipsky3472a1e2024-02-16 19:12:40166int ConvertModifierKeyToFlags(ui::mojom::ModifierKey modifier_key) {
167 switch (modifier_key) {
168 case ui::mojom::ModifierKey::kMeta:
169 return ui::EF_COMMAND_DOWN;
170 case ui::mojom::ModifierKey::kControl:
171 return ui::EF_CONTROL_DOWN;
172 case ui::mojom::ModifierKey::kAlt:
173 return ui::EF_ALT_DOWN;
174 case ui::mojom::ModifierKey::kEscape:
175 case ui::mojom::ModifierKey::kBackspace:
176 case ui::mojom::ModifierKey::kAssistant:
177 case ui::mojom::ModifierKey::kCapsLock:
178 case ui::mojom::ModifierKey::kVoid:
179 case ui::mojom::ModifierKey::kIsoLevel5ShiftMod3:
180 return ui::EF_NONE;
181 }
182}
183
David Padlipskyfe51c1162024-02-10 02:00:18184bool AreScrollWheelEventRewritesAllowed(
185 mojom::CustomizationRestriction customization_restriction) {
186 switch (customization_restriction) {
187 case mojom::CustomizationRestriction::kDisallowCustomizations:
188 case mojom::CustomizationRestriction::kDisableKeyEventRewrites:
189 case mojom::CustomizationRestriction::kAllowAlphabetKeyEventRewrites:
190 case mojom::CustomizationRestriction::
191 kAllowAlphabetOrNumberKeyEventRewrites:
David Padlipsky07842e92024-02-13 01:18:46192 case mojom::CustomizationRestriction::kAllowTabEventRewrites:
David Padlipskyfe51c1162024-02-10 02:00:18193 return false;
194 case mojom::CustomizationRestriction::kAllowHorizontalScrollWheelRewrites:
195 case mojom::CustomizationRestriction::kAllowCustomizations:
196 return true;
197 }
198}
199
David Padlipskya0e5e022024-02-10 00:08:03200template <typename Iterator>
201std::vector<std::unique_ptr<ui::Event>> RewriteModifiers(
202 const ui::Event& event,
203 uint32_t modifiers_to_press,
204 uint32_t modifiers_already_pressed,
205 bool pressed,
206 Iterator begin,
207 Iterator end) {
208 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
209
210 // Keeps track of the modifier flags that must be applied to the next
211 // rewritten event. For key presses, this should start at
212 // `0` and go to `modifiers_to_press`. For releases, it should do the opposite
213 // as we start will all modifiers down.
214 uint32_t modifiers_pressed = pressed ? 0u : modifiers_to_press;
215
216 for (auto iter = begin; iter != end; iter++) {
217 if (!(iter->flag & modifiers_to_press)) {
218 continue;
219 }
220
221 if (pressed) {
222 modifiers_pressed += iter->flag;
223 } else {
224 modifiers_pressed -= iter->flag;
225 }
226
227 const ui::EventType pressed_or_released_type =
228 pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
229 auto rewritten_modifier_event = std::make_unique<ui::KeyEvent>(
230 pressed_or_released_type, iter->key_code, iter->dom_code,
David Padlipsky544ae2a02024-02-17 01:25:06231 modifiers_pressed | modifiers_already_pressed |
232 ui::EF_IS_CUSTOMIZED_FROM_BUTTON,
233 event.time_stamp());
David Padlipskya0e5e022024-02-10 00:08:03234 rewritten_modifier_event->set_source_device_id(event.source_device_id());
235 rewritten_events.push_back(std::move(rewritten_modifier_event));
236 }
237
238 // Verify our modifier rewriting worked as expected.
239 if (pressed) {
240 CHECK_EQ(modifiers_to_press, modifiers_pressed);
241 } else {
242 CHECK_EQ(0u, modifiers_pressed);
243 }
244
245 return rewritten_events;
246}
247
248std::vector<std::unique_ptr<ui::Event>> GenerateFullKeyEventSequence(
249 const ui::Event& event,
250 uint32_t modifiers_to_press,
251 uint32_t modifiers_already_pressed,
252 bool pressed,
253 std::unique_ptr<ui::Event> rewritten_event) {
254 static constexpr struct {
255 ui::KeyboardCode key_code;
256 ui::DomCode dom_code;
257 ui::EventFlags flag;
258 } kModifiers[] = {
259 {ui::VKEY_LWIN, ui::DomCode::META_LEFT, ui::EF_COMMAND_DOWN},
260 {ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT, ui::EF_CONTROL_DOWN},
261 {ui::VKEY_MENU, ui::DomCode::ALT_LEFT, ui::EF_ALT_DOWN},
262 {ui::VKEY_SHIFT, ui::DomCode::SHIFT_LEFT, ui::EF_SHIFT_DOWN},
263 };
264 static constexpr auto kModifierSpan = base::make_span(kModifiers);
265
266 CHECK(rewritten_event);
267 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
268
269 if (pressed) {
270 // If it is a key press, we rewrite the modifiers in forward order and then
271 // add the main rewritten event after the press events.
272 rewritten_events =
273 RewriteModifiers(event, modifiers_to_press, modifiers_already_pressed,
274 pressed, kModifierSpan.begin(), kModifierSpan.end());
275 rewritten_events.push_back(std::move(rewritten_event));
276 } else {
277 // For key releases, we add the main rewritten event first and then append
278 // the rewritten modifiers after. The modifiers must be rewritten in reverse
279 // order from the `kModifiers` array.
280 rewritten_events.push_back(std::move(rewritten_event));
281 auto modifier_events =
282 RewriteModifiers(event, modifiers_to_press, modifiers_already_pressed,
283 pressed, kModifierSpan.rbegin(), kModifierSpan.rend());
284 rewritten_events.insert(rewritten_events.end(),
285 std::make_move_iterator(modifier_events.begin()),
286 std::make_move_iterator(modifier_events.end()));
287 }
288
289 return rewritten_events;
290}
291
292std::vector<std::unique_ptr<ui::Event>> RewriteEventToKeyEvents(
Danny Wang6bdb5582023-09-18 21:27:29293 const ui::Event& event,
David Padlipskyfe51c1162024-02-10 02:00:18294 const mojom::KeyEvent& key_event,
David Padlipsky3472a1e2024-02-16 19:12:40295 int flags_to_release,
David Padlipskyfe51c1162024-02-10 02:00:18296 bool key_press) {
297 const ui::EventType event_type =
298 key_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED;
David Padlipskya0e5e022024-02-10 00:08:03299 const uint32_t modifier_key_flag = ConvertKeyCodeToFlags(key_event.vkey);
300
301 // `other_modifiers_to_apply` symbolizes the flags that are not handled by
302 // `modifier_key_flag` or flags that are already included in the event. The
303 // flags remaining in `other_modifiers_to_apply` are the modifiers we must
304 // write events for in addition to the main key event.
David Padlipsky3472a1e2024-02-16 19:12:40305
306 // On release events, we should release the flags passed in instead of our
307 // computed set of flags in case some modifiers were released since we
308 // originally pressed them down.
309
310 // Mouse wheel is an exception here since presses and releases happen
311 // atomically. Therefore always release every key you originally pressed.
David Padlipskya0e5e022024-02-10 00:08:03312 const uint32_t other_modifiers_to_apply =
David Padlipsky3472a1e2024-02-16 19:12:40313 (key_press || event.type() == ui::ET_MOUSEWHEEL)
314 ? (key_event.modifiers & ~event.flags() & ~modifier_key_flag)
315 : (flags_to_release & ~event.flags() & ~modifier_key_flag);
David Padlipskya0e5e022024-02-10 00:08:03316
317 uint32_t applied_modifier_key_flag = modifier_key_flag;
David Padlipsky3394af92023-10-27 21:30:50318 // Do not apply modifier flags when the key is a modifier and it is a release
319 // event. Modifier keys do not apply their flag on release.
320 if (event_type == ui::ET_KEY_RELEASED &&
David Padlipskya0e5e022024-02-10 00:08:03321 key_event.modifiers == modifier_key_flag) {
322 applied_modifier_key_flag = ui::EF_NONE;
David Padlipsky3394af92023-10-27 21:30:50323 }
David Padlipskyfe51c1162024-02-10 02:00:18324
Danny Wang6bdb5582023-09-18 21:27:29325 auto rewritten_event = std::make_unique<ui::KeyEvent>(
326 event_type, key_event.vkey, static_cast<ui::DomCode>(key_event.dom_code),
David Padlipsky544ae2a02024-02-17 01:25:06327 applied_modifier_key_flag | other_modifiers_to_apply | event.flags() |
328 ui::EF_IS_CUSTOMIZED_FROM_BUTTON,
Danny Wang6bdb5582023-09-18 21:27:29329 static_cast<ui::DomKey>(key_event.dom_key), event.time_stamp());
330 rewritten_event->set_source_device_id(event.source_device_id());
David Padlipskya0e5e022024-02-10 00:08:03331
332 return GenerateFullKeyEventSequence(
333 event, other_modifiers_to_apply, event.flags(),
334 /*pressed=*/event_type == ui::ET_KEY_PRESSED, std::move(rewritten_event));
Danny Wang6bdb5582023-09-18 21:27:29335}
336
David Padlipskyfe51c1162024-02-10 02:00:18337std::vector<std::unique_ptr<ui::Event>> RewriteEventToKeyEvents(
338 const ui::Event& event,
David Padlipsky3472a1e2024-02-16 19:12:40339 const mojom::KeyEvent& key_event,
340 int flags_to_release) {
David Padlipskyfe51c1162024-02-10 02:00:18341 // If the original event is a mouse scroll event, we must generate both a
342 // press and release from the single event.
343 const bool should_press_and_release = event.type() == ui::ET_MOUSEWHEEL;
344
345 const bool key_press = should_press_and_release ||
346 event.type() == ui::ET_MOUSE_PRESSED ||
347 event.type() == ui::ET_KEY_PRESSED;
348 std::vector<std::unique_ptr<ui::Event>> rewritten_events =
David Padlipsky3472a1e2024-02-16 19:12:40349 RewriteEventToKeyEvents(event, key_event, flags_to_release, key_press);
David Padlipskyfe51c1162024-02-10 02:00:18350
351 if (should_press_and_release) {
352 std::vector<std::unique_ptr<ui::Event>> release_rewritten_events =
David Padlipsky3472a1e2024-02-16 19:12:40353 RewriteEventToKeyEvents(event, key_event, flags_to_release, false);
David Padlipskyfe51c1162024-02-10 02:00:18354 rewritten_events.reserve(rewritten_events.size() +
355 release_rewritten_events.size());
356 rewritten_events.insert(
357 rewritten_events.end(),
358 std::make_move_iterator(release_rewritten_events.begin()),
359 std::make_move_iterator(release_rewritten_events.end()));
360 }
361 return rewritten_events;
362}
363
364std::vector<std::unique_ptr<ui::Event>> RewriteEventToMouseButtonEvents(
David Padlipskyd664e672023-10-25 21:32:15365 const ui::Event& event,
366 mojom::StaticShortcutAction action) {
David Padlipskyfe51c1162024-02-10 02:00:18367 // If the original event is a mouse scroll event, we must generate both a
368 // press and release from the single event.
369 const bool should_press_and_release = event.type() == ui::ET_MOUSEWHEEL;
370
371 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
372
David Padlipskyd664e672023-10-25 21:32:15373 auto* flag_iter = kStaticActionToMouseButtonFlag.find(action);
374 CHECK(flag_iter != kStaticActionToMouseButtonFlag.end());
375 const int characteristic_flag = flag_iter->second;
376
377 auto* screen = display::Screen::GetScreen();
378 CHECK(screen);
David Padlipsky3394af92023-10-27 21:30:50379 auto display = screen->GetDisplayNearestPoint(screen->GetCursorScreenPoint());
380 const gfx::PointF location =
381 gfx::ScalePoint(gfx::PointF(screen->GetCursorScreenPoint() -
382 display.bounds().origin().OffsetFromOrigin()),
383 display.device_scale_factor());
David Padlipskyd664e672023-10-25 21:32:15384
David Padlipskyfe51c1162024-02-10 02:00:18385 const ui::EventType type =
386 (should_press_and_release || event.type() == ui::ET_MOUSE_PRESSED ||
387 event.type() == ui::ET_KEY_PRESSED)
388 ? ui::ET_MOUSE_PRESSED
389 : ui::ET_MOUSE_RELEASED;
390 rewritten_events.push_back(std::make_unique<ui::MouseEvent>(
David Padlipskyd664e672023-10-25 21:32:15391 type, location, location, event.time_stamp(),
David Padlipskyfe51c1162024-02-10 02:00:18392 event.flags() | characteristic_flag, characteristic_flag));
393 rewritten_events.back()->set_source_device_id(event.source_device_id());
394
395 if (should_press_and_release) {
396 rewritten_events.push_back(std::make_unique<ui::MouseEvent>(
397 ui::ET_MOUSE_RELEASED, location, location, event.time_stamp(),
398 event.flags() | characteristic_flag, characteristic_flag));
399 rewritten_events.back()->set_source_device_id(event.source_device_id());
400 }
401
402 return rewritten_events;
David Padlipskyd664e672023-10-25 21:32:15403}
404
David Padlipskyb5a52cd12023-08-08 21:45:19405bool IsMouseButtonEvent(const ui::MouseEvent& mouse_event) {
406 return mouse_event.type() == ui::ET_MOUSE_PRESSED ||
407 mouse_event.type() == ui::ET_MOUSE_RELEASED;
408}
409
410bool IsMouseRemappableButton(int flags) {
411 return (flags & kMouseRemappableFlags) != 0;
412}
413
414bool IsGraphicsTabletRemappableButton(int flags) {
415 return (flags & kGraphicsTabletRemappableFlags) != 0;
416}
417
418int GetRemappableMouseEventFlags(
419 PeripheralCustomizationEventRewriter::DeviceType device_type) {
420 switch (device_type) {
421 case PeripheralCustomizationEventRewriter::DeviceType::kMouse:
422 return kMouseRemappableFlags;
423 case PeripheralCustomizationEventRewriter::DeviceType::kGraphicsTablet:
424 return kGraphicsTabletRemappableFlags;
425 }
426}
427
David Padlipskyb7896da2023-10-25 19:45:46428mojom::ButtonPtr GetButtonFromMouseEvent(const ui::MouseEvent& mouse_event) {
429 switch (mouse_event.changed_button_flags()) {
David Padlipskyb5a52cd12023-08-08 21:45:19430 case ui::EF_LEFT_MOUSE_BUTTON:
431 return mojom::Button::NewCustomizableButton(
432 mojom::CustomizableButton::kLeft);
433 case ui::EF_RIGHT_MOUSE_BUTTON:
434 return mojom::Button::NewCustomizableButton(
435 mojom::CustomizableButton::kRight);
436 case ui::EF_MIDDLE_MOUSE_BUTTON:
437 return mojom::Button::NewCustomizableButton(
438 mojom::CustomizableButton::kMiddle);
439 case ui::EF_FORWARD_MOUSE_BUTTON:
David Padlipskyb7896da2023-10-25 19:45:46440 case ui::EF_BACK_MOUSE_BUTTON:
441 break;
442 }
443
444 CHECK(mouse_event.changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON ||
445 mouse_event.changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON);
446 auto linux_key_code = ui::GetForwardBackMouseButtonProperty(mouse_event);
447 if (!linux_key_code) {
448 return (mouse_event.changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
449 ? mojom::Button::NewCustomizableButton(
450 mojom::CustomizableButton::kForward)
451 : mojom::Button::NewCustomizableButton(
452 mojom::CustomizableButton::kBack);
453 }
454
455 switch (*linux_key_code) {
456 case BTN_FORWARD:
David Padlipskyb5a52cd12023-08-08 21:45:19457 return mojom::Button::NewCustomizableButton(
458 mojom::CustomizableButton::kForward);
David Padlipskyb7896da2023-10-25 19:45:46459 case BTN_BACK:
David Padlipskyb5a52cd12023-08-08 21:45:19460 return mojom::Button::NewCustomizableButton(
461 mojom::CustomizableButton::kBack);
David Padlipskyb7896da2023-10-25 19:45:46462 case BTN_SIDE:
463 return mojom::Button::NewCustomizableButton(
464 mojom::CustomizableButton::kSide);
465 case BTN_EXTRA:
466 return mojom::Button::NewCustomizableButton(
467 mojom::CustomizableButton::kExtra);
David Padlipskyb5a52cd12023-08-08 21:45:19468 }
David Padlipskyb7896da2023-10-25 19:45:46469
David Padlipskyb5a52cd12023-08-08 21:45:19470 NOTREACHED_NORETURN();
471}
472
David Padlipskyfe51c1162024-02-10 02:00:18473// Returns the customizable button for the scroll wheel event. Will return null
474// if the scroll event is not a horizontal scroll event.
475mojom::ButtonPtr GetButtonFromMouseWheelEvent(
476 const ui::MouseWheelEvent& mouse_wheel_event) {
477 if (mouse_wheel_event.x_offset() == 0) {
478 return nullptr;
479 }
480
481 if (mouse_wheel_event.x_offset() > 0) {
482 return mojom::Button::NewCustomizableButton(
483 mojom::CustomizableButton::kScrollRight);
484 }
485
486 return mojom::Button::NewCustomizableButton(
487 mojom::CustomizableButton::kScrollLeft);
488}
489
David Padlipskycc7c2de2023-08-23 17:16:54490int ConvertButtonToFlags(const mojom::Button& button) {
491 if (button.is_customizable_button()) {
492 switch (button.get_customizable_button()) {
493 case mojom::CustomizableButton::kLeft:
494 return ui::EF_LEFT_MOUSE_BUTTON;
495 case mojom::CustomizableButton::kRight:
496 return ui::EF_RIGHT_MOUSE_BUTTON;
497 case mojom::CustomizableButton::kMiddle:
498 return ui::EF_MIDDLE_MOUSE_BUTTON;
499 case mojom::CustomizableButton::kForward:
David Padlipskycc7c2de2023-08-23 17:16:54500 case mojom::CustomizableButton::kExtra:
501 return ui::EF_FORWARD_MOUSE_BUTTON;
David Padlipskyb7896da2023-10-25 19:45:46502 case mojom::CustomizableButton::kBack:
David Padlipskycc7c2de2023-08-23 17:16:54503 case mojom::CustomizableButton::kSide:
504 return ui::EF_BACK_MOUSE_BUTTON;
David Padlipskyfe51c1162024-02-10 02:00:18505 case mojom::CustomizableButton::kScrollLeft:
506 case mojom::CustomizableButton::kScrollRight:
507 return ui::EF_NONE;
David Padlipskycc7c2de2023-08-23 17:16:54508 }
509 }
510
511 if (button.is_vkey()) {
David Padlipsky3b55bb12023-09-05 22:24:57512 return ConvertKeyCodeToFlags(button.get_vkey());
David Padlipskycc7c2de2023-08-23 17:16:54513 }
514
515 return ui::EF_NONE;
516}
517
David Padlipsky3472a1e2024-02-16 19:12:40518std::optional<ui::mojom::ModifierKey> ConvertDomCodeToModifierKey(
519 ui::DomCode code) {
520 switch (code) {
521 case ui::DomCode::META_LEFT:
522 case ui::DomCode::META_RIGHT:
523 return ui::mojom::ModifierKey::kMeta;
524 case ui::DomCode::CONTROL_LEFT:
525 case ui::DomCode::CONTROL_RIGHT:
526 return ui::mojom::ModifierKey::kControl;
527 case ui::DomCode::ALT_LEFT:
528 case ui::DomCode::ALT_RIGHT:
529 return ui::mojom::ModifierKey::kAlt;
530 case ui::DomCode::CAPS_LOCK:
531 return ui::mojom::ModifierKey::kCapsLock;
532 case ui::DomCode::BACKSPACE:
533 return ui::mojom::ModifierKey::kBackspace;
534 case ui::DomCode::LAUNCH_ASSISTANT:
535 return ui::mojom::ModifierKey::kAssistant;
536 case ui::DomCode::ESCAPE:
537 return ui::mojom::ModifierKey::kEscape;
538 default:
539 return std::nullopt;
540 }
541}
542
YuhanYang92cbe1592023-12-05 02:13:29543std::optional<PeripheralCustomizationEventRewriter::RemappingActionResult>
544GetRemappingActionFromMouseSettings(const mojom::Button& button,
545 const mojom::MouseSettings& settings) {
David Padlipskyf9728f272023-09-06 16:50:36546 const auto button_remapping_iter = base::ranges::find(
547 settings.button_remappings, button,
548 [](const mojom::ButtonRemappingPtr& entry) { return *entry->button; });
549 if (button_remapping_iter != settings.button_remappings.end()) {
David Padlipsky1eb6f0ae2024-01-08 18:49:21550 const mojom::ButtonRemapping& button_remapping = *(*button_remapping_iter);
551 if (!button_remapping.remapping_action) {
552 return std::nullopt;
553 }
554
YuhanYang92cbe1592023-12-05 02:13:29555 auto result = PeripheralCustomizationEventRewriter::RemappingActionResult(
David Padlipsky1eb6f0ae2024-01-08 18:49:21556 *button_remapping.remapping_action,
YuhanYang92cbe1592023-12-05 02:13:29557 PeripheralCustomizationEventRewriter::
558 PeripheralCustomizationMetricsType::kMouse);
David Padlipsky1eb6f0ae2024-01-08 18:49:21559 return result;
David Padlipskyf9728f272023-09-06 16:50:36560 }
561
David Padlipsky1eb6f0ae2024-01-08 18:49:21562 return std::nullopt;
David Padlipskyf9728f272023-09-06 16:50:36563}
564
YuhanYang92cbe1592023-12-05 02:13:29565std::optional<PeripheralCustomizationEventRewriter::RemappingActionResult>
566GetRemappingActionFromGraphicsTabletSettings(
David Padlipskyf9728f272023-09-06 16:50:36567 const mojom::Button& button,
568 const mojom::GraphicsTabletSettings& settings) {
569 const auto pen_button_remapping_iter = base::ranges::find(
570 settings.pen_button_remappings, button,
571 [](const mojom::ButtonRemappingPtr& entry) { return *entry->button; });
572 if (pen_button_remapping_iter != settings.pen_button_remappings.end()) {
David Padlipsky1eb6f0ae2024-01-08 18:49:21573 const mojom::ButtonRemapping& button_remapping =
574 *(*pen_button_remapping_iter);
575 if (!button_remapping.remapping_action) {
576 return std::nullopt;
577 }
578
YuhanYang92cbe1592023-12-05 02:13:29579 auto pen_action =
580 PeripheralCustomizationEventRewriter::RemappingActionResult(
David Padlipsky1eb6f0ae2024-01-08 18:49:21581 *button_remapping.remapping_action,
YuhanYang92cbe1592023-12-05 02:13:29582 PeripheralCustomizationEventRewriter::
583 PeripheralCustomizationMetricsType::kGraphicsTabletPen);
584 return std::move(pen_action);
David Padlipskyf9728f272023-09-06 16:50:36585 }
586
587 const auto tablet_button_remapping_iter = base::ranges::find(
588 settings.tablet_button_remappings, button,
589 [](const mojom::ButtonRemappingPtr& entry) { return *entry->button; });
590 if (tablet_button_remapping_iter != settings.tablet_button_remappings.end()) {
David Padlipsky1eb6f0ae2024-01-08 18:49:21591 const mojom::ButtonRemapping& button_remapping =
592 *(*tablet_button_remapping_iter);
593 if (!button_remapping.remapping_action) {
594 return std::nullopt;
595 }
596
YuhanYang92cbe1592023-12-05 02:13:29597 auto tablet_action =
598 PeripheralCustomizationEventRewriter::RemappingActionResult(
David Padlipsky1eb6f0ae2024-01-08 18:49:21599 *button_remapping.remapping_action,
YuhanYang92cbe1592023-12-05 02:13:29600 PeripheralCustomizationEventRewriter::
601 PeripheralCustomizationMetricsType::kGraphicsTablet);
602 return std::move(tablet_action);
David Padlipskyf9728f272023-09-06 16:50:36603 }
604
David Padlipsky1eb6f0ae2024-01-08 18:49:21605 return std::nullopt;
David Padlipskyf9728f272023-09-06 16:50:36606}
607
608int GetRemappedModifiersFromMouseSettings(
609 const mojom::MouseSettings& settings) {
610 int modifiers = 0;
611 for (const auto& button_remapping : settings.button_remappings) {
David Padlipskyd664e672023-10-25 21:32:15612 if (button_remapping->remapping_action) {
613 modifiers |= ConvertButtonToFlags(*button_remapping->button);
614 }
David Padlipskyf9728f272023-09-06 16:50:36615 }
616 return modifiers;
617}
618
619int GetRemappedModifiersFromGraphicsTabletSettings(
620 const mojom::GraphicsTabletSettings& settings) {
621 int modifiers = 0;
622 for (const auto& button_remapping : settings.pen_button_remappings) {
623 modifiers |= ConvertButtonToFlags(*button_remapping->button);
624 }
625 for (const auto& button_remapping : settings.tablet_button_remappings) {
626 modifiers |= ConvertButtonToFlags(*button_remapping->button);
627 }
628 return modifiers;
629}
630
David Padlipsky6103bed12024-02-17 01:47:02631// Verify if the keyboard code is an alpha key or punctuation.
632bool IsAlphaKeyEvent(const ui::KeyEvent& key_event) {
633 return GetKeyInputTypeFromKeyEvent(key_event) ==
634 AcceleratorKeyInputType::kAlpha;
Danny Wanga917f0c2023-12-21 00:05:50635}
636
637// Verify if the keyboard code is a number.
David Padlipsky6103bed12024-02-17 01:47:02638bool IsNumberKeyEvent(const ui::KeyEvent& key_event) {
639 return GetKeyInputTypeFromKeyEvent(key_event) ==
640 AcceleratorKeyInputType::kDigit;
Danny Wanga917f0c2023-12-21 00:05:50641}
642
David Padlipsky086da5772024-02-16 23:17:31643void RecordMouseInvalidKeyPressed(InputDeviceSettingsController* controller,
644 const ui::KeyEvent& key_event) {
645 if (key_event.type() == ui::ET_KEY_RELEASED || key_event.is_repeat()) {
646 return;
647 }
648
649 auto* mouse = controller->GetMouse(key_event.source_device_id());
650 if (!mouse) {
651 return;
652 }
653
654 LOG(WARNING) << base::StringPrintf(
655 "Mouse '%s' with identifier '%s' attempted to register keyboard code "
656 "'%04x'.",
657 mouse->name.c_str(), mouse->device_key.c_str(), key_event.key_code());
658 base::UmaHistogramSparse("ChromeOS.Inputs.Mouse.InvalidRegistration",
659 key_event.key_code());
660}
661
David Padlipskyb5a52cd12023-08-08 21:45:19662} // namespace
663
David Padlipsky3b55bb12023-09-05 22:24:57664// Compares the `DeviceIdButton` struct based on first the device id, and then
665// the button stored within the `DeviceIdButton` struct.
666bool operator<(
667 const PeripheralCustomizationEventRewriter::DeviceIdButton& left,
668 const PeripheralCustomizationEventRewriter::DeviceIdButton& right) {
669 if (right.device_id != left.device_id) {
670 return left.device_id < right.device_id;
671 }
672
673 // If both are VKeys, compare them.
674 if (left.button->is_vkey() && right.button->is_vkey()) {
675 return left.button->get_vkey() < right.button->get_vkey();
676 }
677
678 // If both are customizable buttons, compare them.
679 if (left.button->is_customizable_button() &&
680 right.button->is_customizable_button()) {
681 return left.button->get_customizable_button() <
682 right.button->get_customizable_button();
683 }
684
685 // Otherwise, return true if the lhs is a VKey as they mismatch and VKeys
686 // should be considered less than customizable buttons.
687 return left.button->is_vkey();
688}
689
690PeripheralCustomizationEventRewriter::DeviceIdButton::DeviceIdButton(
691 int device_id,
692 mojom::ButtonPtr button)
693 : device_id(device_id), button(std::move(button)) {}
694
695PeripheralCustomizationEventRewriter::DeviceIdButton::DeviceIdButton(
696 DeviceIdButton&& device_id_button)
697 : device_id(device_id_button.device_id),
698 button(std::move(device_id_button.button)) {}
699
700PeripheralCustomizationEventRewriter::DeviceIdButton::~DeviceIdButton() =
701 default;
702
703PeripheralCustomizationEventRewriter::DeviceIdButton&
704PeripheralCustomizationEventRewriter::DeviceIdButton::operator=(
705 PeripheralCustomizationEventRewriter::DeviceIdButton&& device_id_button) =
706 default;
707
YuhanYang92cbe1592023-12-05 02:13:29708PeripheralCustomizationEventRewriter::RemappingActionResult::
709 RemappingActionResult(mojom::RemappingAction& remapping_action,
710 PeripheralCustomizationMetricsType peripheral_kind)
711 : remapping_action(remapping_action), peripheral_kind(peripheral_kind) {}
712
713PeripheralCustomizationEventRewriter::RemappingActionResult::
714 RemappingActionResult(RemappingActionResult&& result)
715 : remapping_action(std::move(result.remapping_action)),
716 peripheral_kind(result.peripheral_kind) {}
717
718PeripheralCustomizationEventRewriter::RemappingActionResult::
719 ~RemappingActionResult() = default;
720
David Padlipskyf9728f272023-09-06 16:50:36721PeripheralCustomizationEventRewriter::PeripheralCustomizationEventRewriter(
722 InputDeviceSettingsController* input_device_settings_controller)
YuhanYang92cbe1592023-12-05 02:13:29723 : input_device_settings_controller_(input_device_settings_controller) {
724 metrics_manager_ = std::make_unique<InputDeviceSettingsMetricsManager>();
725}
726
David Padlipsky5eaaade2023-07-21 22:39:38727PeripheralCustomizationEventRewriter::~PeripheralCustomizationEventRewriter() =
728 default;
729
Arthur Sonzognia98e4432023-11-28 18:15:01730std::optional<PeripheralCustomizationEventRewriter::DeviceType>
David Padlipskyeedcbfe2023-08-08 23:58:36731PeripheralCustomizationEventRewriter::GetDeviceTypeToObserve(int device_id) {
732 if (mice_to_observe_.contains(device_id)) {
733 return DeviceType::kMouse;
734 }
735 if (graphics_tablets_to_observe_.contains(device_id)) {
736 return DeviceType::kGraphicsTablet;
737 }
Arthur Sonzognia98e4432023-11-28 18:15:01738 return std::nullopt;
David Padlipskyeedcbfe2023-08-08 23:58:36739}
740
Danny Wang50d45182023-10-05 17:55:45741void PeripheralCustomizationEventRewriter::StartObservingMouse(
742 int device_id,
Danny Wang6bc788e2023-12-08 23:08:02743 mojom::CustomizationRestriction customization_restriction) {
744 mice_to_observe_.insert_or_assign(device_id, customization_restriction);
David Padlipskyb5a52cd12023-08-08 21:45:19745}
746
747void PeripheralCustomizationEventRewriter::StartObservingGraphicsTablet(
Danny Wangf2ecf152023-12-08 23:13:22748 int device_id,
749 mojom::CustomizationRestriction customization_restriction) {
750 graphics_tablets_to_observe_.insert_or_assign(device_id,
751 customization_restriction);
David Padlipskyb5a52cd12023-08-08 21:45:19752}
753
754void PeripheralCustomizationEventRewriter::StopObserving() {
755 graphics_tablets_to_observe_.clear();
756 mice_to_observe_.clear();
757}
758
David Padlipskyfe51c1162024-02-10 02:00:18759bool PeripheralCustomizationEventRewriter::NotifyMouseWheelEventObserving(
760 const ui::MouseWheelEvent& mouse_wheel_event,
761 DeviceType device_type) {
762 const auto customization_restriction_iter =
763 mice_to_observe_.find(mouse_wheel_event.source_device_id());
764 if (customization_restriction_iter == mice_to_observe_.end()) {
765 return false;
766 }
767
768 auto customization_restriction = customization_restriction_iter->second;
769 if (!AreScrollWheelEventRewritesAllowed(customization_restriction)) {
770 return false;
771 }
772
773 const mojom::ButtonPtr button =
774 GetButtonFromMouseWheelEvent(mouse_wheel_event);
775 if (!button) {
776 return false;
777 }
778
779 switch (device_type) {
780 case DeviceType::kMouse:
781 input_device_settings_controller_->OnMouseButtonPressed(
782 mouse_wheel_event.source_device_id(), *button);
783 break;
784 case DeviceType::kGraphicsTablet:
785 input_device_settings_controller_->OnGraphicsTabletButtonPressed(
786 mouse_wheel_event.source_device_id(), *button);
787 break;
788 }
789
790 return true;
791}
792
David Padlipskyb5a52cd12023-08-08 21:45:19793bool PeripheralCustomizationEventRewriter::NotifyMouseEventObserving(
794 const ui::MouseEvent& mouse_event,
795 DeviceType device_type) {
796 if (!IsMouseButtonEvent(mouse_event)) {
797 return false;
798 }
799
800 // Make sure the button is remappable for the current `device_type`.
801 switch (device_type) {
802 case DeviceType::kMouse:
803 if (!IsMouseRemappableButton(mouse_event.changed_button_flags())) {
804 return false;
805 }
806 break;
807 case DeviceType::kGraphicsTablet:
808 if (!IsGraphicsTabletRemappableButton(
809 mouse_event.changed_button_flags())) {
810 return false;
811 }
812 break;
813 }
814
815 if (mouse_event.type() != ui::ET_MOUSE_PRESSED) {
816 return true;
817 }
818
David Padlipskyb7896da2023-10-25 19:45:46819 const auto button = GetButtonFromMouseEvent(mouse_event);
David Padlipskyc16dd522023-09-08 21:18:22820 switch (device_type) {
821 case DeviceType::kMouse:
822 input_device_settings_controller_->OnMouseButtonPressed(
823 mouse_event.source_device_id(), *button);
824 break;
825 case DeviceType::kGraphicsTablet:
826 input_device_settings_controller_->OnGraphicsTabletButtonPressed(
827 mouse_event.source_device_id(), *button);
828 break;
David Padlipskyb5a52cd12023-08-08 21:45:19829 }
830
831 return true;
832}
833
Danny Wangab5c8a362023-12-15 22:34:18834bool PeripheralCustomizationEventRewriter::IsButtonCustomizable(
835 const ui::KeyEvent& key_event) {
836 const auto iter = mice_to_observe_.find(key_event.source_device_id());
837 if (iter == mice_to_observe().end()) {
838 return false;
839 }
840 const auto customization_restriction = iter->second;
841 // There are several cases for the customization restriction:
842 // 1. If restriction is kAllowCustomizations, mice are allowed to observe
843 // key events.
844 // 2. If restriction is kAllowAlphabetKeyEventRewrites, mice are allowed to
David Padlipsky6103bed12024-02-17 01:47:02845 // observe only alphabet or punctuation events.
Danny Wange2a701872023-12-15 23:13:47846 // 3. If restriction is kAllowAlphabetOrNumberKeyEventRewrites, mice are
David Padlipsky6103bed12024-02-17 01:47:02847 // allowed to observe alphabet, punctuation, or number key event.
Danny Wange2a701872023-12-15 23:13:47848 // 4. Mice are not allowed to observe key event in other cases.
Danny Wangab5c8a362023-12-15 22:34:18849 switch (customization_restriction) {
850 case mojom::CustomizationRestriction::kAllowCustomizations:
851 return true;
852 case mojom::CustomizationRestriction::kAllowAlphabetKeyEventRewrites:
David Padlipsky6103bed12024-02-17 01:47:02853 return IsAlphaKeyEvent(key_event);
Danny Wange2a701872023-12-15 23:13:47854 case mojom::CustomizationRestriction::
855 kAllowAlphabetOrNumberKeyEventRewrites:
David Padlipsky6103bed12024-02-17 01:47:02856 return IsAlphaKeyEvent(key_event) || IsNumberKeyEvent(key_event);
David Padlipsky07842e92024-02-13 01:18:46857 case mojom::CustomizationRestriction::kAllowTabEventRewrites:
858 return key_event.key_code() == ui::VKEY_TAB;
Danny Wangab5c8a362023-12-15 22:34:18859 case mojom::CustomizationRestriction::kDisallowCustomizations:
860 case mojom::CustomizationRestriction::kDisableKeyEventRewrites:
David Padlipskyfe51c1162024-02-10 02:00:18861 case mojom::CustomizationRestriction::kAllowHorizontalScrollWheelRewrites:
Danny Wangab5c8a362023-12-15 22:34:18862 return false;
863 }
864}
865
David Padlipskyeedcbfe2023-08-08 23:58:36866bool PeripheralCustomizationEventRewriter::NotifyKeyEventObserving(
867 const ui::KeyEvent& key_event,
868 DeviceType device_type) {
Danny Wangab5c8a362023-12-15 22:34:18869 if (device_type == DeviceType::kMouse && !IsButtonCustomizable(key_event)) {
David Padlipsky086da5772024-02-16 23:17:31870 RecordMouseInvalidKeyPressed(input_device_settings_controller_, key_event);
Danny Wangab5c8a362023-12-15 22:34:18871 return false;
Danny Wang50d45182023-10-05 17:55:45872 }
873
David Padlipskyeedcbfe2023-08-08 23:58:36874 // Observers should only be notified on key presses.
875 if (key_event.type() != ui::ET_KEY_PRESSED) {
876 return true;
877 }
878
879 const auto button = mojom::Button::NewVkey(key_event.key_code());
David Padlipskyc16dd522023-09-08 21:18:22880 switch (device_type) {
881 case DeviceType::kMouse:
882 input_device_settings_controller_->OnMouseButtonPressed(
883 key_event.source_device_id(), *button);
884 break;
885 case DeviceType::kGraphicsTablet:
886 input_device_settings_controller_->OnGraphicsTabletButtonPressed(
887 key_event.source_device_id(), *button);
888 break;
David Padlipskyeedcbfe2023-08-08 23:58:36889 }
890
891 return true;
892}
893
David Padlipskycc7c2de2023-08-23 17:16:54894bool PeripheralCustomizationEventRewriter::RewriteEventFromButton(
895 const ui::Event& event,
896 const mojom::Button& button,
David Padlipskya0e5e022024-02-10 00:08:03897 std::vector<std::unique_ptr<ui::Event>>& rewritten_events) {
Arthur Sonzognie5fff99c2024-02-21 15:58:24898 std::optional<RemappingActionResult> remapping_action_result =
David Padlipskya0e5e022024-02-10 00:08:03899 GetRemappingAction(event.source_device_id(), button);
YuhanYang92cbe1592023-12-05 02:13:29900 if (!remapping_action_result) {
David Padlipskycc7c2de2023-08-23 17:16:54901 return false;
902 }
YuhanYang92cbe1592023-12-05 02:13:29903 auto remapping_action = remapping_action_result->remapping_action;
904
David Padlipsky459bb3b2024-02-07 20:31:03905 if (event.type() == ui::ET_KEY_PRESSED ||
906 event.type() == ui::ET_MOUSE_PRESSED) {
907 metrics_manager_->RecordRemappingActionWhenButtonPressed(
908 *remapping_action,
909 ToMetricsString(remapping_action_result->peripheral_kind).data());
910 }
David Padlipskycc7c2de2023-08-23 17:16:54911
Danny Wangd388f6b2023-09-29 00:06:50912 if (remapping_action->is_accelerator_action()) {
David Padlipskyf8730952023-09-01 19:38:27913 if (event.type() == ui::ET_KEY_PRESSED ||
David Padlipskyfe51c1162024-02-10 02:00:18914 event.type() == ui::ET_MOUSE_PRESSED ||
915 event.type() == ui::ET_MOUSEWHEEL) {
David Padlipskyf8730952023-09-01 19:38:27916 // Every accelerator supported by peripheral customization is not impacted
917 // by the accelerator passed. Therefore, passing an empty accelerator will
918 // cause no issues.
919 Shell::Get()->accelerator_controller()->PerformActionIfEnabled(
Danny Wangd388f6b2023-09-29 00:06:50920 remapping_action->get_accelerator_action(), /*accelerator=*/{});
David Padlipskyf8730952023-09-01 19:38:27921 }
922
David Padlipskycc7c2de2023-08-23 17:16:54923 return true;
924 }
925
David Padlipsky3472a1e2024-02-16 19:12:40926 // Get flags to release in rewriting key events.
927 int flags_to_release = 0;
928 auto iter =
929 device_button_to_flags_.find({event.source_device_id(), button.Clone()});
930 if (iter != device_button_to_flags_.end()) {
931 flags_to_release = iter->second;
932 }
933
David Padlipskycc7c2de2023-08-23 17:16:54934 if (remapping_action->is_key_event()) {
935 const auto& key_event = remapping_action->get_key_event();
David Padlipsky5b39dc02024-01-03 20:36:48936 auto entry = FindKeyCodeEntry(key_event->vkey);
937 // If no entry can be found, use the stored key_event struct.
938 if (!entry) {
David Padlipsky3472a1e2024-02-16 19:12:40939 rewritten_events =
940 RewriteEventToKeyEvents(event, *key_event, flags_to_release);
David Padlipsky5b39dc02024-01-03 20:36:48941 } else {
David Padlipskya0e5e022024-02-10 00:08:03942 rewritten_events = RewriteEventToKeyEvents(
David Padlipsky3472a1e2024-02-16 19:12:40943 event,
944 mojom::KeyEvent(
945 entry->resulting_key_code, static_cast<int>(entry->dom_code),
946 static_cast<int>(entry->dom_key), key_event->modifiers, ""),
947 flags_to_release);
David Padlipsky5b39dc02024-01-03 20:36:48948 }
Danny Wang6bdb5582023-09-18 21:27:29949 }
950
Danny Wangd388f6b2023-09-29 00:06:50951 if (remapping_action->is_static_shortcut_action()) {
David Padlipskyd664e672023-10-25 21:32:15952 const auto static_action = remapping_action->get_static_shortcut_action();
953 if (static_action == mojom::StaticShortcutAction::kDisable) {
Danny Wang75a9a86f2023-09-29 21:00:30954 // Return true to discard the event.
955 return true;
956 }
David Padlipskyd664e672023-10-25 21:32:15957
958 if (kStaticActionToMouseButtonFlag.contains(static_action)) {
David Padlipskyfe51c1162024-02-10 02:00:18959 rewritten_events = RewriteEventToMouseButtonEvents(event, static_action);
David Padlipskyd664e672023-10-25 21:32:15960 } else {
David Padlipskya0e5e022024-02-10 00:08:03961 rewritten_events = RewriteEventToKeyEvents(
David Padlipsky3472a1e2024-02-16 19:12:40962 event,
963 GetStaticShortcutAction(
964 remapping_action->get_static_shortcut_action()),
965 flags_to_release);
David Padlipskyd664e672023-10-25 21:32:15966 }
David Padlipskycc7c2de2023-08-23 17:16:54967 }
968
969 return false;
970}
971
David Padlipskyeedcbfe2023-08-08 23:58:36972ui::EventDispatchDetails PeripheralCustomizationEventRewriter::RewriteKeyEvent(
973 const ui::KeyEvent& key_event,
974 const Continuation continuation) {
975 auto device_type_to_observe =
976 GetDeviceTypeToObserve(key_event.source_device_id());
977 if (device_type_to_observe) {
978 if (NotifyKeyEventObserving(key_event, *device_type_to_observe)) {
979 return DiscardEvent(continuation);
980 }
981 }
982
David Padlipskya0e5e022024-02-10 00:08:03983 // Clone event and remove the already remapped modifiers and use this as the
984 // "source" key event for the rest of the rewriting.
985 std::unique_ptr<ui::Event> original_event_with_modifiers_removed =
986 CloneEvent(key_event);
987 RemoveRemappedModifiers(*original_event_with_modifiers_removed);
988
989 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
David Padlipsky3b55bb12023-09-05 22:24:57990 mojom::ButtonPtr button = mojom::Button::NewVkey(key_event.key_code());
David Padlipsky3394af92023-10-27 21:30:50991 bool updated_button_map = false;
David Padlipskya0e5e022024-02-10 00:08:03992 if (RewriteEventFromButton(*original_event_with_modifiers_removed, *button,
993 rewritten_events)) {
David Padlipskycc7c2de2023-08-23 17:16:54994 return DiscardEvent(continuation);
995 }
David Padlipsky3394af92023-10-27 21:30:50996
David Padlipskya0e5e022024-02-10 00:08:03997 const bool event_rewritten = !rewritten_events.empty();
David Padlipskycc7c2de2023-08-23 17:16:54998
David Padlipskya0e5e022024-02-10 00:08:03999 // Discard all "button" type events usually from graphics tablets.
1000 if (!event_rewritten && key_event.key_code() >= ui::VKEY_BUTTON_0 &&
David Padlipsky341564182024-01-11 22:09:321001 key_event.key_code() <= ui::VKEY_BUTTON_Z) {
1002 return DiscardEvent(continuation);
1003 }
1004
David Padlipskya0e5e022024-02-10 00:08:031005 // Add an event to our list to rewrite based on other pressed buttons.
1006 if (rewritten_events.empty()) {
1007 rewritten_events.push_back(
1008 std::move(original_event_with_modifiers_removed));
David Padlipskycc7c2de2023-08-23 17:16:541009 }
1010
David Padlipskya0e5e022024-02-10 00:08:031011 // If the button was released, the pressed button map must be updated before
1012 // applying remapped modifiers.
1013 const ui::Event& last_rewritten_event = *rewritten_events.back();
1014 if (event_rewritten &&
1015 (last_rewritten_event.type() == ui::ET_MOUSE_RELEASED ||
1016 last_rewritten_event.type() == ui::ET_KEY_RELEASED)) {
1017 updated_button_map = true;
1018 UpdatePressedButtonMap(std::move(button), key_event, rewritten_events);
David Padlipsky3394af92023-10-27 21:30:501019 }
1020
David Padlipsky3472a1e2024-02-16 19:12:401021 // Remove flags from modifiers that are released on other devices.
1022 if (!event_rewritten) {
1023 UpdatePressedButtonMapFlags(key_event);
1024 }
1025
David Padlipskya0e5e022024-02-10 00:08:031026 for (const auto& rewritten_event : rewritten_events) {
1027 ApplyRemappedModifiers(*rewritten_event);
1028 }
1029
1030 if (event_rewritten && !updated_button_map) {
1031 UpdatePressedButtonMap(std::move(button), key_event, rewritten_events);
1032 }
1033
1034 ui::EventDispatchDetails details;
1035 for (const auto& rewritten_event : rewritten_events) {
1036 details = SendEvent(continuation, rewritten_event.get());
1037 }
1038 return details;
David Padlipskyeedcbfe2023-08-08 23:58:361039}
1040
David Padlipsky3b55bb12023-09-05 22:24:571041void PeripheralCustomizationEventRewriter::UpdatePressedButtonMap(
1042 mojom::ButtonPtr button,
1043 const ui::Event& original_event,
David Padlipskya0e5e022024-02-10 00:08:031044 const std::vector<std::unique_ptr<ui::Event>>& rewritten_events) {
David Padlipskyfe51c1162024-02-10 02:00:181045 // Scroll wheel events cannot affect other events modifiers since they do a
1046 // full press/release sequence with the one event.
1047 if (original_event.type() == ui::ET_MOUSEWHEEL) {
1048 return;
1049 }
1050
David Padlipsky3b55bb12023-09-05 22:24:571051 DeviceIdButton device_id_button_key =
1052 DeviceIdButton{original_event.source_device_id(), std::move(button)};
David Padlipsky3394af92023-10-27 21:30:501053 // If the button is released, the entry must be removed from the map.
1054 if (original_event.type() == ui::ET_MOUSE_RELEASED ||
1055 original_event.type() == ui::ET_KEY_RELEASED) {
1056 device_button_to_flags_.erase(std::move(device_id_button_key));
David Padlipsky3472a1e2024-02-16 19:12:401057
1058 // Release all modifier flags on other currently pressed buttons.
1059 for (const auto& rewritten_event : rewritten_events) {
1060 if (rewritten_event->IsKeyEvent()) {
1061 UpdatePressedButtonMapFlags(*rewritten_event->AsKeyEvent());
1062 }
1063 }
David Padlipsky3394af92023-10-27 21:30:501064 return;
1065 }
1066
David Padlipskya0e5e022024-02-10 00:08:031067 // For each rewritten event, combine the flags that need to be applied to
1068 // correctly handle the newly pressed event. This matters when pressing a
1069 // modifier or a key with a combo of modifiers or when holding a rewritten
1070 // mouse button.
1071 ui::EventFlags event_flags = 0;
1072 for (const auto& rewritten_event : rewritten_events) {
1073 if (!rewritten_event) {
1074 continue;
1075 }
David Padlipsky3b55bb12023-09-05 22:24:571076
David Padlipskya0e5e022024-02-10 00:08:031077 if (rewritten_event->IsKeyEvent()) {
1078 const auto& key_event = *rewritten_event->AsKeyEvent();
1079 event_flags |= ConvertKeyCodeToFlags(key_event.key_code());
1080 continue;
1081 }
1082
1083 if (rewritten_event->IsMouseEvent()) {
1084 const auto& mouse_event = *rewritten_event->AsMouseEvent();
1085 event_flags |= mouse_event.changed_button_flags();
1086 continue;
1087 }
1088 }
1089
1090 if (!event_flags) {
David Padlipsky3b55bb12023-09-05 22:24:571091 return;
1092 }
1093
1094 // Add the entry to the map with the flags that must be applied to other
1095 // events.
1096 device_button_to_flags_.insert_or_assign(std::move(device_id_button_key),
David Padlipskya0e5e022024-02-10 00:08:031097 event_flags);
David Padlipsky3b55bb12023-09-05 22:24:571098}
1099
David Padlipsky3472a1e2024-02-16 19:12:401100void PeripheralCustomizationEventRewriter::UpdatePressedButtonMapFlags(
1101 const ui::KeyEvent& key_event) {
1102 if (key_event.type() == ui::ET_KEY_PRESSED) {
1103 return;
1104 }
1105
1106 // Remap the released key based on modifier remappings.
1107 auto* settings = input_device_settings_controller_->GetKeyboardSettings(
1108 key_event.source_device_id());
1109 auto modifier_key = ConvertDomCodeToModifierKey(key_event.code());
1110 int key_event_characteristic_flag =
1111 ConvertKeyCodeToFlags(key_event.key_code());
1112 if (settings && modifier_key) {
1113 auto iter = settings->modifier_remappings.find(*modifier_key);
1114 if (iter != settings->modifier_remappings.end()) {
1115 key_event_characteristic_flag = ConvertModifierKeyToFlags(iter->second);
1116 }
1117 }
1118
1119 // Remove the key event characteristic flag as the key has already been
1120 // released and should no longer apply the flag to other pressed events.
1121 for (auto& [_, flag] : device_button_to_flags_) {
1122 flag &= ~key_event_characteristic_flag;
1123 }
1124}
1125
David Padlipskyb5a52cd12023-08-08 21:45:191126ui::EventDispatchDetails
David Padlipskyfe51c1162024-02-10 02:00:181127PeripheralCustomizationEventRewriter::RewriteMouseWheelEvent(
1128 const ui::MouseWheelEvent& mouse_wheel_event,
1129 const Continuation continuation) {
1130 auto device_type_to_observe =
1131 GetDeviceTypeToObserve(mouse_wheel_event.source_device_id());
1132 if (device_type_to_observe) {
1133 if (NotifyMouseWheelEventObserving(mouse_wheel_event,
1134 *device_type_to_observe)) {
1135 return DiscardEvent(continuation);
1136 }
1137
1138 // Otherwise, the flags must be cleared for the remappable buttons so they
1139 // do not affect the application while the mouse is meant to be observed.
1140 std::unique_ptr<ui::Event> rewritten_event = CloneEvent(mouse_wheel_event);
1141 const int remappable_flags =
1142 GetRemappableMouseEventFlags(*device_type_to_observe);
1143 rewritten_event->SetFlags(rewritten_event->flags() & ~remappable_flags);
1144 if (rewritten_event->IsMouseEvent()) {
1145 auto& rewritten_mouse_event = *rewritten_event->AsMouseEvent();
1146 rewritten_mouse_event.set_changed_button_flags(
1147 rewritten_mouse_event.changed_button_flags() & ~remappable_flags);
1148 }
1149 return SendEvent(continuation, rewritten_event.get());
1150 }
1151
1152 // Clone event and remove the already remapped modifiers and use this as the
1153 // "source" key event for the rest of the rewriting.
1154 std::unique_ptr<ui::Event> original_event_with_modifiers_removed =
1155 CloneEvent(mouse_wheel_event);
1156 RemoveRemappedModifiers(*original_event_with_modifiers_removed);
1157
1158 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
1159 mojom::ButtonPtr button = GetButtonFromMouseWheelEvent(mouse_wheel_event);
1160 bool updated_button_map = false;
1161 if (!button.is_null()) {
1162 if (RewriteEventFromButton(*original_event_with_modifiers_removed, *button,
1163 rewritten_events)) {
1164 return DiscardEvent(continuation);
1165 }
1166 }
1167
1168 const bool event_rewritten = !rewritten_events.empty();
1169
1170 // Add an event to our list to rewrite based on other pressed buttons.
1171 if (!event_rewritten) {
1172 rewritten_events.push_back(
1173 std::move(original_event_with_modifiers_removed));
1174 }
1175
1176 // If the button was released, the pressed button map must be updated before
1177 // applying remapped modifiers.
1178 const ui::Event& last_rewritten_event = *rewritten_events.back();
1179 if (event_rewritten &&
1180 (last_rewritten_event.type() == ui::ET_MOUSE_RELEASED ||
1181 last_rewritten_event.type() == ui::ET_KEY_RELEASED)) {
1182 updated_button_map = true;
1183 UpdatePressedButtonMap(std::move(button), mouse_wheel_event,
1184 rewritten_events);
1185 }
1186
1187 for (const auto& rewritten_event : rewritten_events) {
1188 ApplyRemappedModifiers(*rewritten_event);
1189 }
1190
1191 if (event_rewritten && !updated_button_map) {
1192 UpdatePressedButtonMap(std::move(button), mouse_wheel_event,
1193 rewritten_events);
1194 }
1195
1196 ui::EventDispatchDetails details;
1197 for (const auto& rewritten_event : rewritten_events) {
1198 details = SendEvent(continuation, rewritten_event.get());
1199 }
1200 return details;
1201}
1202
1203ui::EventDispatchDetails
David Padlipskyb5a52cd12023-08-08 21:45:191204PeripheralCustomizationEventRewriter::RewriteMouseEvent(
1205 const ui::MouseEvent& mouse_event,
1206 const Continuation continuation) {
David Padlipskyeedcbfe2023-08-08 23:58:361207 auto device_type_to_observe =
1208 GetDeviceTypeToObserve(mouse_event.source_device_id());
1209 if (device_type_to_observe) {
1210 if (NotifyMouseEventObserving(mouse_event, *device_type_to_observe)) {
David Padlipskyb5a52cd12023-08-08 21:45:191211 return DiscardEvent(continuation);
1212 }
1213
1214 // Otherwise, the flags must be cleared for the remappable buttons so they
1215 // do not affect the application while the mouse is meant to be observed.
David Padlipskydcd57e12023-10-25 23:00:181216 std::unique_ptr<ui::Event> rewritten_event = CloneEvent(mouse_event);
David Padlipskyeedcbfe2023-08-08 23:58:361217 const int remappable_flags =
1218 GetRemappableMouseEventFlags(*device_type_to_observe);
David Padlipsky4687d1e12024-01-04 00:18:451219 rewritten_event->SetFlags(rewritten_event->flags() & ~remappable_flags);
David Padlipskydcd57e12023-10-25 23:00:181220 if (rewritten_event->IsMouseEvent()) {
1221 auto& rewritten_mouse_event = *rewritten_event->AsMouseEvent();
1222 rewritten_mouse_event.set_changed_button_flags(
1223 rewritten_mouse_event.changed_button_flags() & ~remappable_flags);
1224 }
1225 return SendEvent(continuation, rewritten_event.get());
David Padlipskyb5a52cd12023-08-08 21:45:191226 }
1227
David Padlipskya0e5e022024-02-10 00:08:031228 // Clone event and remove the already remapped modifiers and use this as the
1229 // "source" key event for the rest of the rewriting.
1230 std::unique_ptr<ui::Event> original_event_with_modifiers_removed =
1231 CloneEvent(mouse_event);
1232 RemoveRemappedModifiers(*original_event_with_modifiers_removed);
1233
1234 std::vector<std::unique_ptr<ui::Event>> rewritten_events;
David Padlipsky3394af92023-10-27 21:30:501235 mojom::ButtonPtr button;
1236 bool updated_button_map = false;
David Padlipsky3b55bb12023-09-05 22:24:571237 if (IsMouseButtonEvent(mouse_event) && mouse_event.changed_button_flags()) {
David Padlipsky3394af92023-10-27 21:30:501238 button = GetButtonFromMouseEvent(mouse_event);
David Padlipskya0e5e022024-02-10 00:08:031239 if (RewriteEventFromButton(*original_event_with_modifiers_removed, *button,
1240 rewritten_events)) {
David Padlipskycc7c2de2023-08-23 17:16:541241 return DiscardEvent(continuation);
1242 }
David Padlipskycc7c2de2023-08-23 17:16:541243 }
David Padlipsky3394af92023-10-27 21:30:501244
David Padlipskya0e5e022024-02-10 00:08:031245 const bool event_rewritten = !rewritten_events.empty();
1246
1247 // Add an event to our list to rewrite based on other pressed buttons.
1248 if (!event_rewritten) {
1249 rewritten_events.push_back(
1250 std::move(original_event_with_modifiers_removed));
David Padlipskycc7c2de2023-08-23 17:16:541251 }
1252
David Padlipskya0e5e022024-02-10 00:08:031253 // If the button was released, the pressed button map must be updated before
1254 // applying remapped modifiers.
1255 const ui::Event& last_rewritten_event = *rewritten_events.back();
1256 if (event_rewritten &&
1257 (last_rewritten_event.type() == ui::ET_MOUSE_RELEASED ||
1258 last_rewritten_event.type() == ui::ET_KEY_RELEASED)) {
1259 updated_button_map = true;
1260 UpdatePressedButtonMap(std::move(button), mouse_event, rewritten_events);
David Padlipsky3394af92023-10-27 21:30:501261 }
1262
David Padlipskya0e5e022024-02-10 00:08:031263 for (const auto& rewritten_event : rewritten_events) {
1264 ApplyRemappedModifiers(*rewritten_event);
1265 }
1266
1267 if (event_rewritten && !updated_button_map) {
1268 UpdatePressedButtonMap(std::move(button), mouse_event, rewritten_events);
1269 }
1270
1271 ui::EventDispatchDetails details;
1272 for (const auto& rewritten_event : rewritten_events) {
1273 details = SendEvent(continuation, rewritten_event.get());
1274 }
1275 return details;
David Padlipskyb5a52cd12023-08-08 21:45:191276}
1277
David Padlipsky5eaaade2023-07-21 22:39:381278ui::EventDispatchDetails PeripheralCustomizationEventRewriter::RewriteEvent(
1279 const ui::Event& event,
1280 const Continuation continuation) {
Jimmyb36a8772023-11-10 19:41:391281 DCHECK(features::IsPeripheralCustomizationEnabled() ||
1282 ::features::IsShortcutCustomizationEnabled());
David Padlipskyb5a52cd12023-08-08 21:45:191283
David Padlipskyfe51c1162024-02-10 02:00:181284 if (event.IsMouseWheelEvent()) {
1285 return RewriteMouseWheelEvent(*event.AsMouseWheelEvent(), continuation);
1286 }
1287
David Padlipskyb5a52cd12023-08-08 21:45:191288 if (event.IsMouseEvent()) {
1289 return RewriteMouseEvent(*event.AsMouseEvent(), continuation);
1290 }
1291
David Padlipskyeedcbfe2023-08-08 23:58:361292 if (event.IsKeyEvent()) {
1293 return RewriteKeyEvent(*event.AsKeyEvent(), continuation);
1294 }
1295
David Padlipsky5eaaade2023-07-21 22:39:381296 return SendEvent(continuation, &event);
1297}
1298
YuhanYang92cbe1592023-12-05 02:13:291299std::optional<PeripheralCustomizationEventRewriter::RemappingActionResult>
David Padlipskycc7c2de2023-08-23 17:16:541300PeripheralCustomizationEventRewriter::GetRemappingAction(
1301 int device_id,
1302 const mojom::Button& button) {
David Padlipskyf9728f272023-09-06 16:50:361303 const auto* mouse_settings =
1304 input_device_settings_controller_->GetMouseSettings(device_id);
1305 if (mouse_settings) {
1306 return GetRemappingActionFromMouseSettings(button, *mouse_settings);
David Padlipskycc7c2de2023-08-23 17:16:541307 }
1308
David Padlipskyf9728f272023-09-06 16:50:361309 const auto* graphics_tablet_settings =
1310 input_device_settings_controller_->GetGraphicsTabletSettings(device_id);
1311 if (graphics_tablet_settings) {
1312 return GetRemappingActionFromGraphicsTabletSettings(
1313 button, *graphics_tablet_settings);
David Padlipskycc7c2de2023-08-23 17:16:541314 }
1315
Arthur Sonzognie5fff99c2024-02-21 15:58:241316 return std::nullopt;
David Padlipskycc7c2de2023-08-23 17:16:541317}
1318
1319void PeripheralCustomizationEventRewriter::RemoveRemappedModifiers(
1320 ui::Event& event) {
David Padlipskyf9728f272023-09-06 16:50:361321 int modifier_flags = 0;
1322 if (const auto* mouse_settings =
1323 input_device_settings_controller_->GetMouseSettings(
1324 event.source_device_id());
1325 mouse_settings) {
1326 modifier_flags = GetRemappedModifiersFromMouseSettings(*mouse_settings);
1327 } else if (const auto* graphics_tablet_settings =
1328 input_device_settings_controller_->GetGraphicsTabletSettings(
1329 event.source_device_id());
1330 graphics_tablet_settings) {
1331 modifier_flags = GetRemappedModifiersFromGraphicsTabletSettings(
1332 *graphics_tablet_settings);
David Padlipskycc7c2de2023-08-23 17:16:541333 }
1334
1335 // TODO(dpad): This logic isn't quite correct. If a second devices is holding
1336 // "Ctrl" and the original device has a button that is "Ctrl" that is
1337 // remapped, this will behave incorrectly as it will remove "Ctrl". Instead,
1338 // this needs to track what keys are being pressed by the device that have
1339 // modifiers attached to them. For now, this is close enough to being correct.
David Padlipsky4687d1e12024-01-04 00:18:451340 event.SetFlags(event.flags() & ~modifier_flags);
David Padlipskycc7c2de2023-08-23 17:16:541341}
1342
David Padlipsky3b55bb12023-09-05 22:24:571343void PeripheralCustomizationEventRewriter::ApplyRemappedModifiers(
1344 ui::Event& event) {
1345 int flags = 0;
1346 for (const auto& [_, flag] : device_button_to_flags_) {
1347 flags |= flag;
1348 }
David Padlipsky4687d1e12024-01-04 00:18:451349 event.SetFlags(event.flags() | flags);
David Padlipsky3b55bb12023-09-05 22:24:571350}
1351
David Padlipskydcd57e12023-10-25 23:00:181352std::unique_ptr<ui::Event> PeripheralCustomizationEventRewriter::CloneEvent(
1353 const ui::Event& event) {
1354 std::unique_ptr<ui::Event> cloned_event = event.Clone();
1355 // SetNativeEvent must be called explicitly as native events are not copied
1356 // on ChromeOS by default. This is because `PlatformEvent` is a pointer by
1357 // default, so its lifetime can not be guaranteed in general. In this case,
1358 // the lifetime of `rewritten_event` is guaranteed to be less than the
1359 // original `mouse_event`.
1360 SetNativeEvent(*cloned_event, event.native_event());
1361 return cloned_event;
1362}
1363
David Padlipsky5eaaade2023-07-21 22:39:381364} // namespace ash