event_rewriter_chromeos.cc 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/chromeos/events/event_rewriter_chromeos.h"
  5. #include <fcntl.h>
  6. #include <stddef.h>
  7. #include "ash/constants/ash_features.h"
  8. #include "base/feature_list.h"
  9. #include "base/files/file_path.h"
  10. #include "base/files/scoped_file.h"
  11. #include "base/logging.h"
  12. #include "base/metrics/user_metrics.h"
  13. #include "base/strings/string_number_conversions.h"
  14. #include "base/strings/string_split.h"
  15. #include "base/strings/string_util.h"
  16. #include "base/system/sys_info.h"
  17. #include "device/udev_linux/scoped_udev.h"
  18. #include "ui/base/ime/ash/ime_keyboard.h"
  19. #include "ui/base/ime/ash/input_method_manager.h"
  20. #include "ui/base/ui_base_features.h"
  21. #include "ui/chromeos/events/modifier_key.h"
  22. #include "ui/chromeos/events/pref_names.h"
  23. #include "ui/events/devices/device_data_manager.h"
  24. #include "ui/events/event_utils.h"
  25. #include "ui/events/keycodes/dom/dom_code.h"
  26. #include "ui/events/keycodes/dom/keycode_converter.h"
  27. #include "ui/events/keycodes/keyboard_code_conversion.h"
  28. #include "ui/events/ozone/evdev/event_device_info.h"
  29. namespace ui {
  30. namespace {
  31. // Hotrod controller vendor/product ids.
  32. const int kHotrodRemoteVendorId = 0x0471;
  33. const int kHotrodRemoteProductId = 0x21cc;
  34. // Flag masks for remapping alt+click or search+click to right click.
  35. constexpr int kAltLeftButton = (EF_ALT_DOWN | EF_LEFT_MOUSE_BUTTON);
  36. constexpr int kSearchLeftButton = (EF_COMMAND_DOWN | EF_LEFT_MOUSE_BUTTON);
  37. // Table of properties of remappable keys and/or remapping targets (not
  38. // strictly limited to "modifiers").
  39. //
  40. // This is used in two distinct ways: for rewriting key up/down events,
  41. // and for rewriting modifier EventFlags on any kind of event.
  42. //
  43. // For the first case, rewriting key up/down events, |RewriteModifierKeys()|
  44. // determines the preference name |prefs::kLanguageRemap...KeyTo| for the
  45. // incoming key and, using |GetRemappedKey()|, gets the user preference
  46. // value |input_method::k...Key| for the incoming key, and finally finds that
  47. // value in this table to obtain the |result| properties of the target key.
  48. //
  49. // For the second case, rewriting modifier EventFlags,
  50. // |GetRemappedModifierMasks()| processes every table entry whose |flag|
  51. // is set in the incoming event. Using the |pref_name| in the table entry,
  52. // it likewise uses |GetRemappedKey()| to find the properties of the
  53. // user preference target key, and replaces the flag accordingly.
  54. const struct ModifierRemapping {
  55. int flag;
  56. chromeos::ModifierKey remap_to;
  57. const char* pref_name;
  58. EventRewriterChromeOS::MutableKeyState result;
  59. } kModifierRemappings[] = {
  60. {EF_CONTROL_DOWN,
  61. chromeos::ModifierKey::kControlKey,
  62. prefs::kLanguageRemapControlKeyTo,
  63. {EF_CONTROL_DOWN, DomCode::CONTROL_LEFT, DomKey::CONTROL, VKEY_CONTROL}},
  64. {// kModifierRemappingNeoMod3 references this entry by index.
  65. EF_MOD3_DOWN | EF_ALTGR_DOWN,
  66. chromeos::ModifierKey::kNumModifierKeys,
  67. nullptr,
  68. {EF_MOD3_DOWN | EF_ALTGR_DOWN, DomCode::CAPS_LOCK, DomKey::ALT_GRAPH,
  69. VKEY_ALTGR}},
  70. {EF_COMMAND_DOWN,
  71. chromeos::ModifierKey::kSearchKey,
  72. prefs::kLanguageRemapSearchKeyTo,
  73. {EF_COMMAND_DOWN, DomCode::META_LEFT, DomKey::META, VKEY_LWIN}},
  74. {EF_ALT_DOWN,
  75. chromeos::ModifierKey::kAltKey,
  76. prefs::kLanguageRemapAltKeyTo,
  77. {EF_ALT_DOWN, DomCode::ALT_LEFT, DomKey::ALT, VKEY_MENU}},
  78. {EF_NONE,
  79. chromeos::ModifierKey::kVoidKey,
  80. nullptr,
  81. {EF_NONE, DomCode::NONE, DomKey::NONE, VKEY_UNKNOWN}},
  82. {EF_MOD3_DOWN,
  83. chromeos::ModifierKey::kCapsLockKey,
  84. prefs::kLanguageRemapCapsLockKeyTo,
  85. {EF_MOD3_DOWN, DomCode::CAPS_LOCK, DomKey::CAPS_LOCK, VKEY_CAPITAL}},
  86. {EF_NONE,
  87. chromeos::ModifierKey::kEscapeKey,
  88. prefs::kLanguageRemapEscapeKeyTo,
  89. {EF_NONE, DomCode::ESCAPE, DomKey::ESCAPE, VKEY_ESCAPE}},
  90. {EF_NONE,
  91. chromeos::ModifierKey::kBackspaceKey,
  92. prefs::kLanguageRemapBackspaceKeyTo,
  93. {EF_NONE, DomCode::BACKSPACE, DomKey::BACKSPACE, VKEY_BACK}},
  94. {EF_NONE,
  95. chromeos::ModifierKey::kAssistantKey,
  96. prefs::kLanguageRemapAssistantKeyTo,
  97. {EF_NONE, DomCode::LAUNCH_ASSISTANT, DomKey::LAUNCH_ASSISTANT,
  98. VKEY_ASSISTANT}}};
  99. const EventRewriterChromeOS::MutableKeyState kCustomTopRowLayoutFKeys[] = {
  100. {EF_NONE, DomCode::F1, DomKey::F1, VKEY_F1},
  101. {EF_NONE, DomCode::F2, DomKey::F2, VKEY_F2},
  102. {EF_NONE, DomCode::F3, DomKey::F3, VKEY_F3},
  103. {EF_NONE, DomCode::F4, DomKey::F4, VKEY_F4},
  104. {EF_NONE, DomCode::F5, DomKey::F5, VKEY_F5},
  105. {EF_NONE, DomCode::F6, DomKey::F6, VKEY_F6},
  106. {EF_NONE, DomCode::F7, DomKey::F7, VKEY_F7},
  107. {EF_NONE, DomCode::F8, DomKey::F8, VKEY_F8},
  108. {EF_NONE, DomCode::F9, DomKey::F9, VKEY_F9},
  109. {EF_NONE, DomCode::F10, DomKey::F10, VKEY_F10},
  110. {EF_NONE, DomCode::F11, DomKey::F11, VKEY_F11},
  111. {EF_NONE, DomCode::F12, DomKey::F12, VKEY_F12},
  112. {EF_NONE, DomCode::F13, DomKey::F13, VKEY_F13},
  113. {EF_NONE, DomCode::F14, DomKey::F14, VKEY_F14},
  114. {EF_NONE, DomCode::F15, DomKey::F15, VKEY_F15},
  115. };
  116. const size_t kAllFKeysSize = std::size(kCustomTopRowLayoutFKeys);
  117. constexpr KeyboardCode kMaxCustomTopRowLayoutFKeyCode = VKEY_F15;
  118. bool IsCustomLayoutFunctionKey(KeyboardCode key_code) {
  119. return key_code >= VKEY_F1 && key_code <= kMaxCustomTopRowLayoutFKeyCode;
  120. }
  121. const ModifierRemapping* kModifierRemappingNeoMod3 = &kModifierRemappings[1];
  122. // Gets a remapped key for |pref_name| key. For example, to find out which
  123. // key Ctrl is currently remapped to, call the function with
  124. // prefs::kLanguageRemapControlKeyTo.
  125. // Note: For the Search key, call GetSearchRemappedKey().
  126. const ModifierRemapping* GetRemappedKey(
  127. const std::string& pref_name,
  128. EventRewriterChromeOS::Delegate* delegate) {
  129. if (!delegate)
  130. return nullptr;
  131. int value = -1;
  132. if (!delegate->GetKeyboardRemappedPrefValue(pref_name, &value))
  133. return nullptr;
  134. for (auto& remapping : kModifierRemappings) {
  135. if (value == static_cast<int>(remapping.remap_to))
  136. return &remapping;
  137. }
  138. return nullptr;
  139. }
  140. // Gets a remapped key for the Search key based on the |keyboard_type| of the
  141. // last event. Internal Search key, Command key on external Apple keyboards, and
  142. // Meta key (either Search or Windows) on external non-Apple keyboards can all
  143. // be remapped separately.
  144. const ModifierRemapping* GetSearchRemappedKey(
  145. EventRewriterChromeOS::Delegate* delegate,
  146. EventRewriterChromeOS::DeviceType keyboard_type) {
  147. std::string pref_name;
  148. switch (keyboard_type) {
  149. case EventRewriterChromeOS::kDeviceExternalAppleKeyboard:
  150. pref_name = prefs::kLanguageRemapExternalCommandKeyTo;
  151. break;
  152. case EventRewriterChromeOS::kDeviceExternalGenericKeyboard:
  153. case EventRewriterChromeOS::kDeviceExternalUnknown:
  154. pref_name = prefs::kLanguageRemapExternalMetaKeyTo;
  155. break;
  156. case EventRewriterChromeOS::kDeviceExternalChromeOsKeyboard:
  157. case EventRewriterChromeOS::kDeviceInternalKeyboard:
  158. case EventRewriterChromeOS::kDeviceHotrodRemote:
  159. case EventRewriterChromeOS::kDeviceVirtualCoreKeyboard:
  160. case EventRewriterChromeOS::kDeviceUnknown:
  161. // Use the preference for internal Search key remapping.
  162. pref_name = prefs::kLanguageRemapSearchKeyTo;
  163. break;
  164. }
  165. return GetRemappedKey(pref_name, delegate);
  166. }
  167. bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
  168. // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
  169. // it's not possible to make both features work. For now, we don't remap
  170. // Mod3Mask when Neo2 is in use.
  171. // TODO(yusukes): Remove the restriction.
  172. auto* manager = ash::input_method::InputMethodManager::Get();
  173. return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
  174. }
  175. struct KeyboardRemapping {
  176. // MatchKeyboardRemapping() succeeds if the tested has all of the specified
  177. // flags (and possibly other flags), and either the key_code matches or the
  178. // condition's key_code is VKEY_UNKNOWN.
  179. struct Condition {
  180. int flags;
  181. KeyboardCode key_code;
  182. } condition;
  183. // ApplyRemapping(), which is the primary user of this structure,
  184. // conditionally sets the output fields from the |result| here.
  185. // - |dom_code| is set if |result.dom_code| is not NONE.
  186. // - |dom_key| and |character| are set if |result.dom_key| is not NONE.
  187. // -|key_code| is set if |result.key_code| is not VKEY_UNKNOWN.
  188. // - |flags| are always set from |result.flags|, but this can be |EF_NONE|.
  189. EventRewriterChromeOS::MutableKeyState result;
  190. };
  191. // If |strict| is true, the flags must match exactly the same. In other words,
  192. // the event will be rewritten only if the exactly specified modifier is
  193. // pressed. If false, it can match even if other modifiers are pressed.
  194. bool MatchKeyboardRemapping(
  195. const EventRewriterChromeOS::MutableKeyState& suspect,
  196. const KeyboardRemapping::Condition& test,
  197. bool strict = false) {
  198. // Reset non modifier key event related flags for strict mode.
  199. constexpr int kKeyEventModifiersMask = EF_SHIFT_DOWN | EF_CONTROL_DOWN |
  200. EF_ALT_DOWN | EF_COMMAND_DOWN |
  201. EF_ALTGR_DOWN | EF_MOD3_DOWN;
  202. const int suspect_flags_for_strict = suspect.flags & kKeyEventModifiersMask;
  203. const bool flag_matched = strict
  204. ? suspect_flags_for_strict == test.flags
  205. : ((suspect.flags & test.flags) == test.flags);
  206. return flag_matched && ((test.key_code == VKEY_UNKNOWN) ||
  207. (test.key_code == suspect.key_code));
  208. }
  209. void ApplyRemapping(const EventRewriterChromeOS::MutableKeyState& changes,
  210. EventRewriterChromeOS::MutableKeyState* state) {
  211. state->flags |= changes.flags;
  212. if (changes.code != DomCode::NONE)
  213. state->code = changes.code;
  214. if (changes.key != DomKey::NONE)
  215. state->key = changes.key;
  216. if (changes.key_code != VKEY_UNKNOWN)
  217. state->key_code = changes.key_code;
  218. }
  219. // Given a set of KeyboardRemapping structs, finds a matching struct
  220. // if possible, and updates the remapped event values. Returns true if a
  221. // remapping was found and remapped values were updated.
  222. // See MatchKeyboardRemapping() for |strict|.
  223. bool RewriteWithKeyboardRemappings(
  224. const KeyboardRemapping* mappings,
  225. size_t num_mappings,
  226. const EventRewriterChromeOS::MutableKeyState& input_state,
  227. EventRewriterChromeOS::MutableKeyState* remapped_state,
  228. bool strict = false) {
  229. for (size_t i = 0; i < num_mappings; ++i) {
  230. const KeyboardRemapping& map = mappings[i];
  231. if (MatchKeyboardRemapping(input_state, map.condition, strict)) {
  232. remapped_state->flags = (input_state.flags & ~map.condition.flags);
  233. ApplyRemapping(map.result, remapped_state);
  234. return true;
  235. }
  236. }
  237. return false;
  238. }
  239. // Given a set of KeyboardRemapping structs, finds a matching struct
  240. // if possible, then returns the KeyboardCode that would have been the
  241. // result of the remapping. If there is no match then VKEY_UNKNOWN
  242. // is returned. No remapping actually occurs in either case.
  243. ui::KeyboardCode MatchedDeprecatedRemapping(
  244. const KeyboardRemapping* mappings,
  245. size_t num_mappings,
  246. const EventRewriterChromeOS::MutableKeyState& input_state) {
  247. for (size_t i = 0; i < num_mappings; ++i) {
  248. const KeyboardRemapping& map = mappings[i];
  249. if (MatchKeyboardRemapping(input_state, map.condition, /*strict=*/false)) {
  250. return map.result.key_code;
  251. }
  252. }
  253. return VKEY_UNKNOWN;
  254. }
  255. void SetMeaningForLayout(EventType type,
  256. EventRewriterChromeOS::MutableKeyState* state) {
  257. // Currently layout is applied by creating a temporary key event with the
  258. // current physical state, and extracting the layout results.
  259. KeyEvent key(type, state->key_code, state->code, state->flags);
  260. state->key = key.GetDomKey();
  261. }
  262. DomCode RelocateModifier(DomCode code, DomKeyLocation location) {
  263. bool right = (location == DomKeyLocation::RIGHT);
  264. switch (code) {
  265. case DomCode::CONTROL_LEFT:
  266. case DomCode::CONTROL_RIGHT:
  267. return right ? DomCode::CONTROL_RIGHT : DomCode::CONTROL_LEFT;
  268. case DomCode::SHIFT_LEFT:
  269. case DomCode::SHIFT_RIGHT:
  270. return right ? DomCode::SHIFT_RIGHT : DomCode::SHIFT_LEFT;
  271. case DomCode::ALT_LEFT:
  272. case DomCode::ALT_RIGHT:
  273. return right ? DomCode::ALT_RIGHT : DomCode::ALT_LEFT;
  274. case DomCode::META_LEFT:
  275. case DomCode::META_RIGHT:
  276. return right ? DomCode::META_RIGHT : DomCode::META_LEFT;
  277. default:
  278. break;
  279. }
  280. return code;
  281. }
  282. // Returns true if |mouse_event| was generated from a touchpad device.
  283. bool IsFromTouchpadDevice(const MouseEvent& mouse_event) {
  284. for (const InputDevice& touchpad :
  285. DeviceDataManager::GetInstance()->GetTouchpadDevices()) {
  286. if (touchpad.id == mouse_event.source_device_id())
  287. return true;
  288. }
  289. return false;
  290. }
  291. // Returns true if |value| is replaced with the specific device property value
  292. // without getting an error.
  293. bool GetDeviceProperty(const base::FilePath& device_path,
  294. const char* key,
  295. std::string* value) {
  296. device::ScopedUdevPtr udev(device::udev_new());
  297. if (!udev.get())
  298. return false;
  299. device::ScopedUdevDevicePtr device(device::udev_device_new_from_syspath(
  300. udev.get(), device_path.value().c_str()));
  301. if (!device.get())
  302. return false;
  303. *value = device::UdevDeviceGetPropertyValue(device.get(), key);
  304. return true;
  305. }
  306. // Returns true if |value| is replaced with the specific device attribute value
  307. // without getting an error. |device_path| should be obtained from the
  308. // |InputDevice.sys_path| field.
  309. bool GetDeviceAttributeRecursive(const base::FilePath& device_path,
  310. const char* key,
  311. std::string* value) {
  312. device::ScopedUdevPtr udev(device::udev_new());
  313. if (!udev.get())
  314. return false;
  315. device::ScopedUdevDevicePtr device(device::udev_device_new_from_syspath(
  316. udev.get(), device_path.value().c_str()));
  317. if (!device.get())
  318. return false;
  319. *value = device::UdevDeviceRecursiveGetSysattrValue(device.get(), key);
  320. return true;
  321. }
  322. constexpr char kLayoutProperty[] = "CROS_KEYBOARD_TOP_ROW_LAYOUT";
  323. constexpr char kCustomTopRowLayoutAttribute[] = "function_row_physmap";
  324. constexpr char kCustomTopRowLayoutProperty[] = "FUNCTION_ROW_PHYSMAP";
  325. bool GetTopRowLayoutProperty(const InputDevice& keyboard_device,
  326. std::string* out_prop) {
  327. return GetDeviceProperty(keyboard_device.sys_path, kLayoutProperty, out_prop);
  328. }
  329. // Parses keyboard to row layout string. Returns true if data is valid.
  330. bool ParseKeyboardTopRowLayout(
  331. const std::string& layout_string,
  332. EventRewriterChromeOS::KeyboardTopRowLayout* out_layout) {
  333. if (layout_string.empty()) {
  334. *out_layout = EventRewriterChromeOS::kKbdTopRowLayoutDefault;
  335. return true;
  336. }
  337. int layout_id;
  338. if (!base::StringToInt(layout_string, &layout_id)) {
  339. LOG(WARNING) << "Failed to parse layout " << kLayoutProperty << " value '"
  340. << layout_string << "'";
  341. return false;
  342. }
  343. if (layout_id < EventRewriterChromeOS::kKbdTopRowLayoutMin ||
  344. layout_id > EventRewriterChromeOS::kKbdTopRowLayoutMax) {
  345. LOG(WARNING) << "Invalid " << kLayoutProperty << " '" << layout_string
  346. << "'";
  347. return false;
  348. }
  349. *out_layout =
  350. static_cast<EventRewriterChromeOS::KeyboardTopRowLayout>(layout_id);
  351. return true;
  352. }
  353. // Parses the custom top row layout string. The string contains a space
  354. // separated list of scan codes in hex. eg "aa ab ac" for F1, F2, F3, etc.
  355. // Returns true if the string can be parsed.
  356. bool ParseCustomTopRowLayoutMap(
  357. const std::string& layout,
  358. base::flat_map<uint32_t, EventRewriterChromeOS::MutableKeyState>*
  359. out_scan_code_map) {
  360. const std::vector<std::string> scan_code_strings = base::SplitString(
  361. layout, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  362. if (scan_code_strings.size() == 0 ||
  363. scan_code_strings.size() > kAllFKeysSize) {
  364. return false;
  365. }
  366. base::flat_map<uint32_t, EventRewriterChromeOS::MutableKeyState>
  367. scan_code_map;
  368. for (size_t i = 0; i < scan_code_strings.size(); i++) {
  369. uint32_t scan_code = 0;
  370. if (!base::HexStringToUInt(scan_code_strings[i], &scan_code)) {
  371. return false;
  372. }
  373. scan_code_map[scan_code] = kCustomTopRowLayoutFKeys[i];
  374. }
  375. if (out_scan_code_map)
  376. *out_scan_code_map = std::move(scan_code_map);
  377. return true;
  378. }
  379. bool GetCustomTopRowLayoutAttribute(const InputDevice& keyboard_device,
  380. std::string* out_prop) {
  381. bool result = GetDeviceAttributeRecursive(
  382. keyboard_device.sys_path, kCustomTopRowLayoutAttribute, out_prop);
  383. if (result && out_prop->size() > 0) {
  384. VLOG(1) << "Identified custom top row keyboard layout: sys_path="
  385. << keyboard_device.sys_path << " layout=" << *out_prop;
  386. return true;
  387. }
  388. return false;
  389. }
  390. bool GetCustomTopRowLayout(const InputDevice& keyboard_device,
  391. std::string* out_prop) {
  392. if (GetCustomTopRowLayoutAttribute(keyboard_device, out_prop))
  393. return true;
  394. return GetDeviceProperty(keyboard_device.sys_path,
  395. kCustomTopRowLayoutProperty, out_prop);
  396. }
  397. bool HasCustomTopRowLayout(
  398. const InputDevice& keyboard_device,
  399. base::flat_map<uint32_t, EventRewriterChromeOS::MutableKeyState>*
  400. out_top_row_map) {
  401. std::string layout;
  402. if (!GetCustomTopRowLayout(keyboard_device, &layout))
  403. return false;
  404. if (layout.empty())
  405. return false;
  406. if (!ParseCustomTopRowLayoutMap(layout, out_top_row_map)) {
  407. LOG(WARNING) << "Could not parse top row layout map: " << layout;
  408. return false;
  409. }
  410. return true;
  411. }
  412. // Returns whether |key_code| appears as one of the key codes that might be
  413. // remapped by table mappings.
  414. bool IsKeyCodeInMappings(KeyboardCode key_code,
  415. const KeyboardRemapping* mappings,
  416. size_t num_mappings) {
  417. for (size_t i = 0; i < num_mappings; ++i) {
  418. const KeyboardRemapping& map = mappings[i];
  419. if (key_code == map.condition.key_code) {
  420. return true;
  421. }
  422. }
  423. return false;
  424. }
  425. // Returns true if all bits in |flag_mask| are set in |flags|.
  426. bool AreFlagsSet(int flags, int flag_mask) {
  427. return (flags & flag_mask) == flag_mask;
  428. }
  429. // Determines the type of |keyboard_device| we are dealing with.
  430. // |has_chromeos_top_row| argument indicates that the keyboard's top
  431. // row has "action" keys (such as back, refresh, etc.) instead of the
  432. // standard F1-F12 keys.
  433. EventRewriterChromeOS::DeviceType IdentifyKeyboardType(
  434. const InputDevice& keyboard_device,
  435. bool has_chromeos_top_row) {
  436. if (keyboard_device.vendor_id == kHotrodRemoteVendorId &&
  437. keyboard_device.product_id == kHotrodRemoteProductId) {
  438. VLOG(1) << "Hotrod remote '" << keyboard_device.name
  439. << "' connected: id=" << keyboard_device.id;
  440. return EventRewriterChromeOS::kDeviceHotrodRemote;
  441. }
  442. if (base::EqualsCaseInsensitiveASCII(keyboard_device.name,
  443. "virtual core keyboard")) {
  444. VLOG(1) << "Xorg virtual '" << keyboard_device.name
  445. << "' connected: id=" << keyboard_device.id;
  446. return EventRewriterChromeOS::kDeviceVirtualCoreKeyboard;
  447. }
  448. if (keyboard_device.type == INPUT_DEVICE_INTERNAL) {
  449. VLOG(1) << "Internal keyboard '" << keyboard_device.name
  450. << "' connected: id=" << keyboard_device.id;
  451. return EventRewriterChromeOS::kDeviceInternalKeyboard;
  452. }
  453. // This is an external device.
  454. if (has_chromeos_top_row) {
  455. // If the device was tagged as having Chrome OS top row layout it must be a
  456. // Chrome OS keyboard.
  457. VLOG(1) << "External Chrome OS keyboard '" << keyboard_device.name
  458. << "' connected: id=" << keyboard_device.id;
  459. return EventRewriterChromeOS::kDeviceExternalChromeOsKeyboard;
  460. }
  461. const std::vector<std::string> tokens =
  462. base::SplitString(keyboard_device.name, " .", base::KEEP_WHITESPACE,
  463. base::SPLIT_WANT_NONEMPTY);
  464. // Parse |device_name| to help classify it.
  465. bool found_apple = false;
  466. bool found_keyboard = false;
  467. for (size_t i = 0; i < tokens.size(); ++i) {
  468. if (!found_apple && base::EqualsCaseInsensitiveASCII(tokens[i], "apple"))
  469. found_apple = true;
  470. if (!found_keyboard &&
  471. base::EqualsCaseInsensitiveASCII(tokens[i], "keyboard"))
  472. found_keyboard = true;
  473. }
  474. if (found_apple) {
  475. // If the |device_name| contains the two words, "apple" and "keyboard",
  476. // treat it as an Apple keyboard.
  477. if (found_keyboard) {
  478. VLOG(1) << "Apple keyboard '" << keyboard_device.name
  479. << "' connected: id=" << keyboard_device.id;
  480. return EventRewriterChromeOS::kDeviceExternalAppleKeyboard;
  481. } else {
  482. VLOG(1) << "Apple device '" << keyboard_device.name
  483. << "' connected: id=" << keyboard_device.id;
  484. return EventRewriterChromeOS::kDeviceExternalUnknown;
  485. }
  486. } else if (found_keyboard) {
  487. VLOG(1) << "External keyboard '" << keyboard_device.name
  488. << "' connected: id=" << keyboard_device.id;
  489. return EventRewriterChromeOS::kDeviceExternalGenericKeyboard;
  490. } else {
  491. VLOG(1) << "External device '" << keyboard_device.name
  492. << "' connected: id=" << keyboard_device.id;
  493. return EventRewriterChromeOS::kDeviceExternalUnknown;
  494. }
  495. }
  496. // Records a user action when the user press search plus a digit to
  497. // generate an F-key.
  498. void RecordSearchPlusDigitFKeyRewrite(ui::EventType event_type,
  499. ui::KeyboardCode key_code) {
  500. if (event_type != ET_KEY_PRESSED) {
  501. return;
  502. }
  503. switch (key_code) {
  504. case ui::VKEY_F1:
  505. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F1"));
  506. break;
  507. case ui::VKEY_F2:
  508. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F2"));
  509. break;
  510. case ui::VKEY_F3:
  511. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F3"));
  512. break;
  513. case ui::VKEY_F4:
  514. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F4"));
  515. break;
  516. case ui::VKEY_F5:
  517. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F5"));
  518. break;
  519. case ui::VKEY_F6:
  520. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F6"));
  521. break;
  522. case ui::VKEY_F7:
  523. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F7"));
  524. break;
  525. case ui::VKEY_F8:
  526. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F8"));
  527. break;
  528. case ui::VKEY_F9:
  529. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F9"));
  530. break;
  531. case ui::VKEY_F10:
  532. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F10"));
  533. break;
  534. case ui::VKEY_F11:
  535. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F11"));
  536. break;
  537. case ui::VKEY_F12:
  538. base::RecordAction(base::UserMetricsAction("SearchPlusDigitRewrite_F12"));
  539. break;
  540. default:
  541. NOTREACHED();
  542. break;
  543. }
  544. }
  545. // Records metrics for the Alt and Search based variants of keys in the
  546. // "six pack" eg. Home, End, PageUp, PageDown, Delete, Insert.
  547. void RecordSixPackEventRewrites(ui::EventType event_type,
  548. ui::KeyboardCode key_code,
  549. bool legacy_variant) {
  550. if (event_type != ET_KEY_PRESSED) {
  551. return;
  552. }
  553. if (!legacy_variant) {
  554. switch (key_code) {
  555. case ui::VKEY_DELETE:
  556. base::RecordAction(
  557. base::UserMetricsAction("SearchBasedKeyRewrite_Delete"));
  558. break;
  559. case ui::VKEY_INSERT:
  560. base::RecordAction(base::UserMetricsAction(
  561. "SearchBasedKeyRewrite_Insert_ViaSearchShiftBackspace"));
  562. break;
  563. case ui::VKEY_HOME:
  564. base::RecordAction(
  565. base::UserMetricsAction("SearchBasedKeyRewrite_Home"));
  566. break;
  567. case ui::VKEY_END:
  568. base::RecordAction(
  569. base::UserMetricsAction("SearchBasedKeyRewrite_End"));
  570. break;
  571. case ui::VKEY_PRIOR:
  572. base::RecordAction(
  573. base::UserMetricsAction("SearchBasedKeyRewrite_PageUp"));
  574. break;
  575. case ui::VKEY_NEXT:
  576. base::RecordAction(
  577. base::UserMetricsAction("SearchBasedKeyRewrite_PageDown"));
  578. break;
  579. default:
  580. NOTREACHED();
  581. break;
  582. }
  583. } else {
  584. switch (key_code) {
  585. case ui::VKEY_DELETE:
  586. base::RecordAction(
  587. base::UserMetricsAction("AltBasedKeyRewrite_Delete"));
  588. break;
  589. case ui::VKEY_INSERT:
  590. base::RecordAction(
  591. base::UserMetricsAction("SearchBasedKeyRewrite_Insert"));
  592. break;
  593. case ui::VKEY_HOME:
  594. base::RecordAction(base::UserMetricsAction("AltBasedKeyRewrite_Home"));
  595. break;
  596. case ui::VKEY_END:
  597. base::RecordAction(base::UserMetricsAction("AltBasedKeyRewrite_End"));
  598. break;
  599. case ui::VKEY_PRIOR:
  600. base::RecordAction(
  601. base::UserMetricsAction("AltBasedKeyRewrite_PageUp"));
  602. break;
  603. case ui::VKEY_NEXT:
  604. base::RecordAction(
  605. base::UserMetricsAction("AltBasedKeyRewrite_PageDown"));
  606. break;
  607. default:
  608. NOTREACHED();
  609. break;
  610. }
  611. }
  612. }
  613. } // namespace
  614. ///////////////////////////////////////////////////////////////////////////////
  615. EventRewriterChromeOS::MutableKeyState::MutableKeyState()
  616. : MutableKeyState(0, DomCode::NONE, 0, KeyboardCode::VKEY_NONAME) {}
  617. EventRewriterChromeOS::MutableKeyState::MutableKeyState(
  618. const KeyEvent* key_event)
  619. : MutableKeyState(key_event->flags(),
  620. key_event->code(),
  621. key_event->GetDomKey(),
  622. key_event->key_code()) {}
  623. EventRewriterChromeOS::MutableKeyState::MutableKeyState(
  624. int input_flags,
  625. DomCode input_code,
  626. DomKey::Base input_key,
  627. KeyboardCode input_key_code)
  628. : flags(input_flags),
  629. code(input_code),
  630. key(input_key),
  631. key_code(input_key_code) {}
  632. ///////////////////////////////////////////////////////////////////////////////
  633. EventRewriterChromeOS::EventRewriterChromeOS(
  634. Delegate* delegate,
  635. EventRewriter* sticky_keys_controller,
  636. bool privacy_screen_supported)
  637. : EventRewriterChromeOS(
  638. delegate,
  639. sticky_keys_controller,
  640. privacy_screen_supported,
  641. ash::input_method::InputMethodManager::Get()->GetImeKeyboard()) {}
  642. EventRewriterChromeOS::EventRewriterChromeOS(
  643. Delegate* delegate,
  644. EventRewriter* sticky_keys_controller,
  645. bool privacy_screen_supported,
  646. ash::input_method::ImeKeyboard* ime_keyboard)
  647. : last_keyboard_device_id_(ED_UNKNOWN_DEVICE),
  648. delegate_(delegate),
  649. sticky_keys_controller_(sticky_keys_controller),
  650. privacy_screen_supported_(privacy_screen_supported),
  651. pressed_modifier_latches_(EF_NONE),
  652. latched_modifier_latches_(EF_NONE),
  653. used_modifier_latches_(EF_NONE),
  654. ime_keyboard_(ime_keyboard) {}
  655. EventRewriterChromeOS::~EventRewriterChromeOS() {}
  656. void EventRewriterChromeOS::KeyboardDeviceAddedForTesting(int device_id) {
  657. KeyboardDeviceAdded(device_id);
  658. }
  659. void EventRewriterChromeOS::ResetStateForTesting() {
  660. pressed_key_states_.clear();
  661. pressed_modifier_latches_ = latched_modifier_latches_ =
  662. used_modifier_latches_ = EF_NONE;
  663. }
  664. void EventRewriterChromeOS::RewriteMouseButtonEventForTesting(
  665. const MouseEvent& event,
  666. const Continuation continuation) {
  667. RewriteMouseButtonEvent(event, continuation);
  668. }
  669. EventDispatchDetails EventRewriterChromeOS::RewriteEvent(
  670. const Event& event,
  671. const Continuation continuation) {
  672. if ((event.type() == ET_KEY_PRESSED) || (event.type() == ET_KEY_RELEASED)) {
  673. std::unique_ptr<Event> rewritten_event;
  674. EventRewriteStatus status =
  675. RewriteKeyEvent(*((&event)->AsKeyEvent()), &rewritten_event);
  676. return RewriteKeyEventInContext(*((&event)->AsKeyEvent()),
  677. std::move(rewritten_event), status,
  678. continuation);
  679. }
  680. if ((event.type() == ET_MOUSE_PRESSED) ||
  681. (event.type() == ET_MOUSE_RELEASED)) {
  682. return RewriteMouseButtonEvent(static_cast<const MouseEvent&>(event),
  683. continuation);
  684. }
  685. if (event.type() == ET_MOUSEWHEEL) {
  686. return RewriteMouseWheelEvent(static_cast<const MouseWheelEvent&>(event),
  687. continuation);
  688. }
  689. if ((event.type() == ET_TOUCH_PRESSED) ||
  690. (event.type() == ET_TOUCH_RELEASED)) {
  691. return RewriteTouchEvent(static_cast<const TouchEvent&>(event),
  692. continuation);
  693. }
  694. if (event.IsScrollEvent()) {
  695. return RewriteScrollEvent(static_cast<const ScrollEvent&>(event),
  696. continuation);
  697. }
  698. return SendEvent(continuation, &event);
  699. }
  700. void EventRewriterChromeOS::BuildRewrittenKeyEvent(
  701. const KeyEvent& key_event,
  702. const MutableKeyState& state,
  703. std::unique_ptr<Event>* rewritten_event) {
  704. auto key_event_ptr = std::make_unique<KeyEvent>(
  705. key_event.type(), state.key_code, state.code, state.flags, state.key,
  706. key_event.time_stamp());
  707. key_event_ptr->set_scan_code(key_event.scan_code());
  708. *rewritten_event = std::move(key_event_ptr);
  709. }
  710. // static
  711. EventRewriterChromeOS::DeviceType EventRewriterChromeOS::GetDeviceType(
  712. const InputDevice& keyboard_device) {
  713. DeviceType type;
  714. KeyboardTopRowLayout layout;
  715. if (IdentifyKeyboard(keyboard_device, &type, &layout, nullptr))
  716. return type;
  717. return EventRewriterChromeOS::kDeviceUnknown;
  718. }
  719. // static
  720. EventRewriterChromeOS::KeyboardTopRowLayout
  721. EventRewriterChromeOS::GetKeyboardTopRowLayout(
  722. const InputDevice& keyboard_device) {
  723. DeviceType type;
  724. KeyboardTopRowLayout layout;
  725. if (IdentifyKeyboard(keyboard_device, &type, &layout, nullptr))
  726. return layout;
  727. return kKbdTopRowLayoutDefault;
  728. }
  729. // static
  730. bool EventRewriterChromeOS::HasAssistantKeyOnKeyboard(
  731. const InputDevice& keyboard_device,
  732. bool* has_assistant_key) {
  733. const char kDevNameProperty[] = "DEVNAME";
  734. std::string dev_name;
  735. if (!GetDeviceProperty(keyboard_device.sys_path, kDevNameProperty,
  736. &dev_name) ||
  737. dev_name.empty()) {
  738. return false;
  739. }
  740. base::ScopedFD fd(open(dev_name.c_str(), O_RDONLY));
  741. if (fd.get() < 0) {
  742. LOG(ERROR) << "Cannot open " << dev_name.c_str() << " : " << errno;
  743. return false;
  744. }
  745. EventDeviceInfo devinfo;
  746. if (!devinfo.Initialize(fd.get(), keyboard_device.sys_path)) {
  747. LOG(ERROR) << "Failed to get device information for "
  748. << keyboard_device.sys_path.value();
  749. return false;
  750. }
  751. *has_assistant_key = devinfo.HasKeyEvent(KEY_ASSISTANT);
  752. return true;
  753. }
  754. // static
  755. bool EventRewriterChromeOS::IdentifyKeyboard(
  756. const InputDevice& keyboard_device,
  757. EventRewriterChromeOS::DeviceType* out_type,
  758. EventRewriterChromeOS::KeyboardTopRowLayout* out_layout,
  759. base::flat_map<uint32_t, EventRewriterChromeOS::MutableKeyState>*
  760. out_scan_code_map) {
  761. std::string layout_string;
  762. EventRewriterChromeOS::KeyboardTopRowLayout layout;
  763. const bool has_custom_top_row =
  764. HasCustomTopRowLayout(keyboard_device, out_scan_code_map);
  765. if (has_custom_top_row) {
  766. layout = EventRewriterChromeOS::kKbdTopRowLayoutCustom;
  767. } else if (!GetTopRowLayoutProperty(keyboard_device, &layout_string) ||
  768. !ParseKeyboardTopRowLayout(layout_string, &layout)) {
  769. *out_type = EventRewriterChromeOS::kDeviceUnknown;
  770. *out_layout = EventRewriterChromeOS::kKbdTopRowLayoutDefault;
  771. return false;
  772. }
  773. *out_type = IdentifyKeyboardType(
  774. keyboard_device, has_custom_top_row || !layout_string.empty());
  775. *out_layout = layout;
  776. return true;
  777. }
  778. bool EventRewriterChromeOS::RewriteModifierKeys(const KeyEvent& key_event,
  779. MutableKeyState* state) {
  780. DCHECK(key_event.type() == ET_KEY_PRESSED ||
  781. key_event.type() == ET_KEY_RELEASED);
  782. if (!delegate_ || !delegate_->RewriteModifierKeys())
  783. return false;
  784. // Preserve a copy of the original before rewriting |state| based on
  785. // user preferences, device configuration, and certain IME properties.
  786. MutableKeyState incoming = *state;
  787. state->flags = EF_NONE;
  788. int characteristic_flag = EF_NONE;
  789. bool exact_event = false;
  790. // First, remap the key code.
  791. const ModifierRemapping* remapped_key = nullptr;
  792. // Remapping based on DomKey.
  793. switch (incoming.key) {
  794. case DomKey::ALT_GRAPH:
  795. // The Neo2 codes modifiers such that CapsLock appears as VKEY_ALTGR,
  796. // but AltGraph (right Alt) also appears as VKEY_ALTGR in Neo2,
  797. // as it does in other layouts. Neo2's "Mod3" is represented in
  798. // EventFlags by a combination of AltGr+Mod3, while its "Mod4" is
  799. // AltGr alone.
  800. if (IsISOLevel5ShiftUsedByCurrentInputMethod()) {
  801. if (incoming.code == DomCode::CAPS_LOCK) {
  802. characteristic_flag = EF_ALTGR_DOWN | EF_MOD3_DOWN;
  803. remapped_key =
  804. GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, delegate_);
  805. } else {
  806. characteristic_flag = EF_ALTGR_DOWN;
  807. remapped_key = GetSearchRemappedKey(delegate_, GetLastKeyboardType());
  808. }
  809. }
  810. if (remapped_key && remapped_key->result.key_code == VKEY_CAPITAL)
  811. remapped_key = kModifierRemappingNeoMod3;
  812. break;
  813. case DomKey::ALT_GRAPH_LATCH:
  814. if (key_event.type() == ET_KEY_PRESSED) {
  815. pressed_modifier_latches_ |= EF_ALTGR_DOWN;
  816. } else {
  817. pressed_modifier_latches_ &= ~EF_ALTGR_DOWN;
  818. if (used_modifier_latches_ & EF_ALTGR_DOWN)
  819. used_modifier_latches_ &= ~EF_ALTGR_DOWN;
  820. else
  821. latched_modifier_latches_ |= EF_ALTGR_DOWN;
  822. }
  823. // Rewrite to AltGraph. When this key is used like a regular modifier,
  824. // the web-exposed result looks like a use of the regular modifier.
  825. // When it's used as a latch, the web-exposed result is a vacuous
  826. // modifier press-and-release, which should be harmless, but preserves
  827. // the event for applications using the |code| (e.g. remoting).
  828. state->key = DomKey::ALT_GRAPH;
  829. state->key_code = VKEY_ALTGR;
  830. exact_event = true;
  831. break;
  832. default:
  833. break;
  834. }
  835. // Remapping based on DomCode.
  836. switch (incoming.code) {
  837. // On Chrome OS, Caps_Lock with Mod3Mask is sent when Caps Lock is pressed
  838. // (with one exception: when IsISOLevel5ShiftUsedByCurrentInputMethod() is
  839. // true, the key generates XK_ISO_Level3_Shift with Mod3Mask, not
  840. // Caps_Lock).
  841. case DomCode::CAPS_LOCK:
  842. // This key is already remapped to Mod3 in remapping based on DomKey. Skip
  843. // more remapping.
  844. if (IsISOLevel5ShiftUsedByCurrentInputMethod() && remapped_key)
  845. break;
  846. characteristic_flag = EF_CAPS_LOCK_ON;
  847. remapped_key =
  848. GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, delegate_);
  849. break;
  850. case DomCode::META_LEFT:
  851. case DomCode::META_RIGHT:
  852. characteristic_flag = EF_COMMAND_DOWN;
  853. remapped_key = GetSearchRemappedKey(delegate_, GetLastKeyboardType());
  854. // Default behavior is Super key, hence don't remap the event if the pref
  855. // is unavailable.
  856. break;
  857. case DomCode::CONTROL_LEFT:
  858. case DomCode::CONTROL_RIGHT:
  859. characteristic_flag = EF_CONTROL_DOWN;
  860. remapped_key =
  861. GetRemappedKey(prefs::kLanguageRemapControlKeyTo, delegate_);
  862. break;
  863. case DomCode::ALT_LEFT:
  864. case DomCode::ALT_RIGHT:
  865. // ALT key
  866. characteristic_flag = EF_ALT_DOWN;
  867. remapped_key = GetRemappedKey(prefs::kLanguageRemapAltKeyTo, delegate_);
  868. break;
  869. case DomCode::ESCAPE:
  870. remapped_key =
  871. GetRemappedKey(prefs::kLanguageRemapEscapeKeyTo, delegate_);
  872. break;
  873. case DomCode::BACKSPACE:
  874. remapped_key =
  875. GetRemappedKey(prefs::kLanguageRemapBackspaceKeyTo, delegate_);
  876. break;
  877. case DomCode::LAUNCH_ASSISTANT:
  878. remapped_key =
  879. GetRemappedKey(prefs::kLanguageRemapAssistantKeyTo, delegate_);
  880. break;
  881. default:
  882. break;
  883. }
  884. if (remapped_key) {
  885. state->key_code = remapped_key->result.key_code;
  886. state->code = remapped_key->result.code;
  887. state->key = remapped_key->result.key;
  888. incoming.flags |= characteristic_flag;
  889. characteristic_flag = remapped_key->flag;
  890. // If the internal state of CapLocks is enabled, we should not remove
  891. // the modifier flag. This is important for the case in which the user
  892. // remaps the CapsLock key to another key (e.g. Search) and CapsLock is
  893. // enabled. If the user were to press the CapsLock key (remapped to Search),
  894. // we risk removing the CapsLock modifier and accidentally disabling
  895. // CapsLocks.
  896. if (incoming.key_code == VKEY_CAPITAL &&
  897. !ime_keyboard_->CapsLockIsEnabled()) {
  898. // We remove the CapsLock modifier here because we do not want to
  899. // turn on the Capslock modifier when the key has been remapped.
  900. incoming.flags &= ~EF_CAPS_LOCK_ON;
  901. }
  902. if (remapped_key->remap_to == chromeos::ModifierKey::kCapsLockKey)
  903. characteristic_flag |= EF_CAPS_LOCK_ON;
  904. state->code = RelocateModifier(
  905. state->code, KeycodeConverter::DomCodeToLocation(incoming.code));
  906. }
  907. // Next, remap modifier bits.
  908. state->flags |= GetRemappedModifierMasks(key_event, incoming.flags);
  909. // If the DomKey is not a modifier before remapping but is after, set the
  910. // modifier latches for the later non-modifier key's modifier states.
  911. bool non_modifier_to_modifier =
  912. !KeycodeConverter::IsDomKeyForModifier(incoming.key) &&
  913. KeycodeConverter::IsDomKeyForModifier(state->key);
  914. if (key_event.type() == ET_KEY_PRESSED) {
  915. state->flags |= characteristic_flag;
  916. if (non_modifier_to_modifier)
  917. pressed_modifier_latches_ |= characteristic_flag;
  918. } else {
  919. state->flags &= ~characteristic_flag;
  920. if (non_modifier_to_modifier)
  921. pressed_modifier_latches_ &= ~characteristic_flag;
  922. }
  923. if (key_event.type() == ET_KEY_PRESSED) {
  924. if (!KeycodeConverter::IsDomKeyForModifier(state->key)) {
  925. used_modifier_latches_ |= pressed_modifier_latches_;
  926. latched_modifier_latches_ = EF_NONE;
  927. }
  928. }
  929. // Implement the Caps Lock modifier here, rather than in the
  930. // AcceleratorController, so that the event is visible to apps (see
  931. // crbug.com/775743).
  932. if (key_event.type() == ET_KEY_RELEASED && state->key_code == VKEY_CAPITAL) {
  933. ime_keyboard_->SetCapsLockEnabled(!ime_keyboard_->CapsLockIsEnabled());
  934. }
  935. return exact_event;
  936. }
  937. void EventRewriterChromeOS::DeviceKeyPressedOrReleased(int device_id) {
  938. const auto iter = device_id_to_info_.find(device_id);
  939. DeviceType type;
  940. if (iter != device_id_to_info_.end())
  941. type = iter->second.type;
  942. else
  943. type = KeyboardDeviceAdded(device_id);
  944. // Ignore virtual Xorg keyboard (magic that generates key repeat
  945. // events). Pretend that the previous real keyboard is the one that is still
  946. // in use.
  947. if (type == kDeviceVirtualCoreKeyboard)
  948. return;
  949. last_keyboard_device_id_ = device_id;
  950. }
  951. bool EventRewriterChromeOS::IsHotrodRemote() const {
  952. return IsLastKeyboardOfType(kDeviceHotrodRemote);
  953. }
  954. bool EventRewriterChromeOS::IsLastKeyboardOfType(DeviceType device_type) const {
  955. return GetLastKeyboardType() == device_type;
  956. }
  957. EventRewriterChromeOS::DeviceType EventRewriterChromeOS::GetLastKeyboardType()
  958. const {
  959. if ((last_keyboard_device_id_ == ED_UNKNOWN_DEVICE) ||
  960. (last_keyboard_device_id_ == ED_REMOTE_INPUT_DEVICE)) {
  961. return kDeviceUnknown;
  962. }
  963. const auto iter = device_id_to_info_.find(last_keyboard_device_id_);
  964. if (iter == device_id_to_info_.end()) {
  965. LOG(ERROR) << "Device ID " << last_keyboard_device_id_ << " is unknown.";
  966. return kDeviceUnknown;
  967. }
  968. return iter->second.type;
  969. }
  970. int EventRewriterChromeOS::GetRemappedModifierMasks(const Event& event,
  971. int original_flags) const {
  972. int unmodified_flags = original_flags;
  973. int rewritten_flags = pressed_modifier_latches_ | latched_modifier_latches_;
  974. for (size_t i = 0; unmodified_flags && (i < std::size(kModifierRemappings));
  975. ++i) {
  976. const ModifierRemapping* remapped_key = nullptr;
  977. if (!(unmodified_flags & kModifierRemappings[i].flag))
  978. continue;
  979. switch (kModifierRemappings[i].flag) {
  980. case EF_COMMAND_DOWN:
  981. remapped_key = GetSearchRemappedKey(delegate_, GetLastKeyboardType());
  982. break;
  983. case EF_MOD3_DOWN:
  984. // If EF_MOD3_DOWN is used by the current input method, leave it alone;
  985. // it is not remappable.
  986. if (IsISOLevel5ShiftUsedByCurrentInputMethod())
  987. continue;
  988. // Otherwise, Mod3Mask is set on X events when the Caps Lock key
  989. // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
  990. // because pressing the key does not invoke caps lock. So, the
  991. // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
  992. // Lock remapping.
  993. break;
  994. case EF_MOD3_DOWN | EF_ALTGR_DOWN:
  995. if ((original_flags & EF_ALTGR_DOWN) &&
  996. IsISOLevel5ShiftUsedByCurrentInputMethod()) {
  997. remapped_key = kModifierRemappingNeoMod3;
  998. }
  999. break;
  1000. default:
  1001. break;
  1002. }
  1003. if (!remapped_key && kModifierRemappings[i].pref_name) {
  1004. remapped_key =
  1005. GetRemappedKey(kModifierRemappings[i].pref_name, delegate_);
  1006. }
  1007. if (remapped_key) {
  1008. unmodified_flags &= ~kModifierRemappings[i].flag;
  1009. rewritten_flags |= remapped_key->flag;
  1010. }
  1011. }
  1012. return rewritten_flags | unmodified_flags;
  1013. }
  1014. bool EventRewriterChromeOS::ShouldRemapToRightClick(
  1015. const MouseEvent& mouse_event,
  1016. int flags,
  1017. int* matched_mask,
  1018. bool* matched_alt_deprecation) const {
  1019. *matched_mask = 0;
  1020. *matched_alt_deprecation = false;
  1021. // TODO(crbug.com/1179893): When enabling the deprecate alt click flag by
  1022. // default, decide whether kUseSearchClickForRightClick being disabled
  1023. // should be able to override it.
  1024. const bool use_search_key =
  1025. base::FeatureList::IsEnabled(
  1026. ::chromeos::features::kUseSearchClickForRightClick) ||
  1027. ::features::IsDeprecateAltClickEnabled();
  1028. if (use_search_key) {
  1029. if (AreFlagsSet(flags, kSearchLeftButton)) {
  1030. *matched_mask = kSearchLeftButton;
  1031. } else if (AreFlagsSet(flags, kAltLeftButton) &&
  1032. is_alt_down_remapping_enabled_) {
  1033. // When the alt variant is deprecated, report when it would have matched.
  1034. *matched_alt_deprecation =
  1035. ((mouse_event.type() == ET_MOUSE_PRESSED) ||
  1036. pressed_device_ids_.count(mouse_event.source_device_id())) &&
  1037. IsFromTouchpadDevice(mouse_event);
  1038. }
  1039. } else {
  1040. if (AreFlagsSet(flags, kAltLeftButton) && is_alt_down_remapping_enabled_) {
  1041. *matched_mask = kAltLeftButton;
  1042. }
  1043. }
  1044. // If the event rewrite matched (ie. matched_mask != 0) then
  1045. // |matched_alt_deprecation| must be false.
  1046. DCHECK(*matched_mask == 0 || !*matched_alt_deprecation);
  1047. return (*matched_mask != 0) &&
  1048. ((mouse_event.type() == ET_MOUSE_PRESSED) ||
  1049. pressed_device_ids_.count(mouse_event.source_device_id())) &&
  1050. IsFromTouchpadDevice(mouse_event);
  1051. }
  1052. EventRewriteStatus EventRewriterChromeOS::RewriteKeyEvent(
  1053. const KeyEvent& key_event,
  1054. std::unique_ptr<Event>* rewritten_event) {
  1055. if (key_event.source_device_id() != ED_UNKNOWN_DEVICE)
  1056. DeviceKeyPressedOrReleased(key_event.source_device_id());
  1057. // Drop repeated keys from Hotrod remote.
  1058. if ((key_event.flags() & EF_IS_REPEAT) &&
  1059. (key_event.type() == ET_KEY_PRESSED) && IsHotrodRemote() &&
  1060. key_event.key_code() != VKEY_BACK) {
  1061. return EVENT_REWRITE_DISCARD;
  1062. }
  1063. MutableKeyState state = {key_event.flags(), key_event.code(),
  1064. key_event.GetDomKey(), key_event.key_code()};
  1065. // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
  1066. // crbug.com/136465.
  1067. if (!(key_event.flags() & EF_FINAL)) {
  1068. // If RewriteModifierKeys() returns true there should be no more processing
  1069. // done to the key event. It will only return true if the key event is
  1070. // rewritten to ALTGR. A false return is not an error.
  1071. if (RewriteModifierKeys(key_event, &state)) {
  1072. // Early exit with completed event.
  1073. BuildRewrittenKeyEvent(key_event, state, rewritten_event);
  1074. return EVENT_REWRITE_REWRITTEN;
  1075. }
  1076. RewriteNumPadKeys(key_event, &state);
  1077. }
  1078. if (delegate_ &&
  1079. delegate_->IsExtensionCommandRegistered(state.key_code, state.flags)) {
  1080. // If |state| and |key_event| have any different fields, a rewrite has
  1081. // occurred. Build the rewritten key event and return early.
  1082. if (MutableKeyState(&key_event) != state) {
  1083. BuildRewrittenKeyEvent(key_event, state, rewritten_event);
  1084. return EVENT_REWRITE_REWRITTEN;
  1085. }
  1086. // The key event was not modified, forward the event downstream.
  1087. return EVENT_REWRITE_CONTINUE;
  1088. }
  1089. EventRewriteStatus status = EVENT_REWRITE_CONTINUE;
  1090. bool is_sticky_key_extension_command = false;
  1091. if (sticky_keys_controller_) {
  1092. KeyEvent tmp_event = key_event;
  1093. tmp_event.set_key_code(state.key_code);
  1094. tmp_event.set_flags(state.flags);
  1095. std::unique_ptr<Event> output_event;
  1096. status = sticky_keys_controller_->RewriteEvent(tmp_event, &output_event);
  1097. if (status == EVENT_REWRITE_REWRITTEN ||
  1098. status == EVENT_REWRITE_DISPATCH_ANOTHER)
  1099. state.flags = output_event->flags();
  1100. if (status == EVENT_REWRITE_DISCARD)
  1101. return EVENT_REWRITE_DISCARD;
  1102. is_sticky_key_extension_command =
  1103. delegate_ &&
  1104. delegate_->IsExtensionCommandRegistered(state.key_code, state.flags);
  1105. }
  1106. // If flags have changed, this may change the interpretation of the key,
  1107. // so reapply layout.
  1108. if (state.flags != key_event.flags())
  1109. SetMeaningForLayout(key_event.type(), &state);
  1110. // If sticky key rewrites the event, and it matches an extension command, do
  1111. // not further rewrite the event since it won't match the extension command
  1112. // thereafter.
  1113. if (!is_sticky_key_extension_command && !(key_event.flags() & EF_FINAL)) {
  1114. RewriteExtendedKeys(key_event, &state);
  1115. RewriteFunctionKeys(key_event, &state);
  1116. }
  1117. if ((key_event.flags() == state.flags) &&
  1118. (key_event.key_code() == state.key_code) &&
  1119. (status == EVENT_REWRITE_CONTINUE)) {
  1120. return EVENT_REWRITE_CONTINUE;
  1121. }
  1122. // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
  1123. // in which case we need to preserve that return status. Alternatively, we
  1124. // might be here because key_event changed, in which case we need to
  1125. // return |EVENT_REWRITE_REWRITTEN|.
  1126. if (status == EVENT_REWRITE_CONTINUE)
  1127. status = EVENT_REWRITE_REWRITTEN;
  1128. BuildRewrittenKeyEvent(key_event, state, rewritten_event);
  1129. return status;
  1130. }
  1131. // TODO(yhanada): Clean up this method once StickyKeysController migrates to the
  1132. // new API.
  1133. EventDispatchDetails EventRewriterChromeOS::RewriteMouseButtonEvent(
  1134. const MouseEvent& mouse_event,
  1135. const Continuation continuation) {
  1136. int flags = RewriteLocatedEvent(mouse_event);
  1137. EventRewriteStatus status = EVENT_REWRITE_CONTINUE;
  1138. if (sticky_keys_controller_) {
  1139. MouseEvent tmp_event = mouse_event;
  1140. tmp_event.set_flags(flags);
  1141. std::unique_ptr<Event> output_event;
  1142. status = sticky_keys_controller_->RewriteEvent(tmp_event, &output_event);
  1143. if (status == EVENT_REWRITE_REWRITTEN ||
  1144. status == EVENT_REWRITE_DISPATCH_ANOTHER) {
  1145. flags = output_event->flags();
  1146. }
  1147. }
  1148. int changed_button = EF_NONE;
  1149. if ((mouse_event.type() == ET_MOUSE_PRESSED) ||
  1150. (mouse_event.type() == ET_MOUSE_RELEASED)) {
  1151. changed_button = RewriteModifierClick(mouse_event, &flags);
  1152. }
  1153. if ((mouse_event.flags() == flags) && (status == EVENT_REWRITE_CONTINUE)) {
  1154. return SendEvent(continuation, &mouse_event);
  1155. }
  1156. std::unique_ptr<Event> rewritten_event = mouse_event.Clone();
  1157. rewritten_event->set_flags(flags);
  1158. if (changed_button != EF_NONE) {
  1159. static_cast<MouseEvent*>(rewritten_event.get())
  1160. ->set_changed_button_flags(changed_button);
  1161. }
  1162. EventDispatchDetails details =
  1163. SendEventFinally(continuation, rewritten_event.get());
  1164. if (status == EVENT_REWRITE_DISPATCH_ANOTHER &&
  1165. !details.dispatcher_destroyed) {
  1166. // Here, we know that another event is a modifier key release event from
  1167. // StickyKeysController.
  1168. return SendStickyKeysReleaseEvents(std::move(rewritten_event),
  1169. continuation);
  1170. }
  1171. return details;
  1172. }
  1173. EventDispatchDetails EventRewriterChromeOS::RewriteMouseWheelEvent(
  1174. const MouseWheelEvent& wheel_event,
  1175. const Continuation continuation) {
  1176. if (!sticky_keys_controller_)
  1177. return SendEvent(continuation, &wheel_event);
  1178. const int flags = RewriteLocatedEvent(wheel_event);
  1179. MouseWheelEvent tmp_event = wheel_event;
  1180. tmp_event.set_flags(flags);
  1181. return sticky_keys_controller_->RewriteEvent(tmp_event, continuation);
  1182. }
  1183. EventDispatchDetails EventRewriterChromeOS::RewriteTouchEvent(
  1184. const TouchEvent& touch_event,
  1185. const Continuation continuation) {
  1186. const int flags = RewriteLocatedEvent(touch_event);
  1187. if (touch_event.flags() == flags)
  1188. return SendEvent(continuation, &touch_event);
  1189. TouchEvent rewritten_touch_event(touch_event);
  1190. rewritten_touch_event.set_flags(flags);
  1191. return SendEventFinally(continuation, &rewritten_touch_event);
  1192. }
  1193. EventDispatchDetails EventRewriterChromeOS::RewriteScrollEvent(
  1194. const ScrollEvent& scroll_event,
  1195. const Continuation continuation) {
  1196. if (!sticky_keys_controller_)
  1197. return SendEvent(continuation, &scroll_event);
  1198. return sticky_keys_controller_->RewriteEvent(scroll_event, continuation);
  1199. }
  1200. void EventRewriterChromeOS::RewriteNumPadKeys(const KeyEvent& key_event,
  1201. MutableKeyState* state) {
  1202. DCHECK(key_event.type() == ET_KEY_PRESSED ||
  1203. key_event.type() == ET_KEY_RELEASED);
  1204. static const struct NumPadRemapping {
  1205. KeyboardCode input_key_code;
  1206. MutableKeyState result;
  1207. } kNumPadRemappings[] = {{VKEY_DELETE,
  1208. {EF_NONE, DomCode::NONE,
  1209. DomKey::Constant<'.'>::Character, VKEY_DECIMAL}},
  1210. {VKEY_INSERT,
  1211. {EF_NONE, DomCode::NONE,
  1212. DomKey::Constant<'0'>::Character, VKEY_NUMPAD0}},
  1213. {VKEY_END,
  1214. {EF_NONE, DomCode::NONE,
  1215. DomKey::Constant<'1'>::Character, VKEY_NUMPAD1}},
  1216. {VKEY_DOWN,
  1217. {EF_NONE, DomCode::NONE,
  1218. DomKey::Constant<'2'>::Character, VKEY_NUMPAD2}},
  1219. {VKEY_NEXT,
  1220. {EF_NONE, DomCode::NONE,
  1221. DomKey::Constant<'3'>::Character, VKEY_NUMPAD3}},
  1222. {VKEY_LEFT,
  1223. {EF_NONE, DomCode::NONE,
  1224. DomKey::Constant<'4'>::Character, VKEY_NUMPAD4}},
  1225. {VKEY_CLEAR,
  1226. {EF_NONE, DomCode::NONE,
  1227. DomKey::Constant<'5'>::Character, VKEY_NUMPAD5}},
  1228. {VKEY_RIGHT,
  1229. {EF_NONE, DomCode::NONE,
  1230. DomKey::Constant<'6'>::Character, VKEY_NUMPAD6}},
  1231. {VKEY_HOME,
  1232. {EF_NONE, DomCode::NONE,
  1233. DomKey::Constant<'7'>::Character, VKEY_NUMPAD7}},
  1234. {VKEY_UP,
  1235. {EF_NONE, DomCode::NONE,
  1236. DomKey::Constant<'8'>::Character, VKEY_NUMPAD8}},
  1237. {VKEY_PRIOR,
  1238. {EF_NONE, DomCode::NONE,
  1239. DomKey::Constant<'9'>::Character, VKEY_NUMPAD9}}};
  1240. for (const auto& map : kNumPadRemappings) {
  1241. if (state->key_code == map.input_key_code) {
  1242. if (KeycodeConverter::DomCodeToLocation(state->code) ==
  1243. DomKeyLocation::NUMPAD) {
  1244. ApplyRemapping(map.result, state);
  1245. }
  1246. return;
  1247. }
  1248. }
  1249. }
  1250. void EventRewriterChromeOS::RewriteExtendedKeys(const KeyEvent& key_event,
  1251. MutableKeyState* state) {
  1252. DCHECK(key_event.type() == ET_KEY_PRESSED ||
  1253. key_event.type() == ET_KEY_RELEASED);
  1254. MutableKeyState incoming = *state;
  1255. // TODO(crbug.com/1179893): This workaround isn't needed once Alt rewrites
  1256. // are deprecated.
  1257. if ((!::features::IsImprovedKeyboardShortcutsEnabled() ||
  1258. !::features::IsDeprecateAltBasedSixPackEnabled()) &&
  1259. ((incoming.flags & (EF_COMMAND_DOWN | EF_ALT_DOWN)) ==
  1260. (EF_COMMAND_DOWN | EF_ALT_DOWN))) {
  1261. // Allow Search to avoid rewriting extended keys.
  1262. // For these, we only remove the EF_COMMAND_DOWN flag.
  1263. static const KeyboardRemapping::Condition kAvoidRemappings[] = {
  1264. {// Alt+Backspace
  1265. EF_ALT_DOWN | EF_COMMAND_DOWN, VKEY_BACK},
  1266. {// Control+Alt+Up
  1267. EF_ALT_DOWN | EF_CONTROL_DOWN | EF_COMMAND_DOWN, VKEY_UP},
  1268. {// Control+Alt+Down
  1269. EF_ALT_DOWN | EF_CONTROL_DOWN | EF_COMMAND_DOWN, VKEY_DOWN}};
  1270. for (const auto& condition : kAvoidRemappings) {
  1271. if (MatchKeyboardRemapping(*state, condition)) {
  1272. state->flags = incoming.flags & ~EF_COMMAND_DOWN;
  1273. return;
  1274. }
  1275. }
  1276. }
  1277. if (incoming.flags & EF_COMMAND_DOWN) {
  1278. bool strict = false;
  1279. bool skip_search_key_remapping =
  1280. delegate_ && delegate_->IsSearchKeyAcceleratorReserved();
  1281. if (!::features::IsImprovedKeyboardShortcutsEnabled()) {
  1282. // TODO(crbug.com/1179893): This workaround isn't needed once Alt rewrites
  1283. // are deprecated.
  1284. strict = ::features::IsNewShortcutMappingEnabled();
  1285. if (strict) {
  1286. DCHECK(!::features::IsImprovedKeyboardShortcutsEnabled());
  1287. // These two keys are used to select to Home/End.
  1288. static const KeyboardRemapping kNewSearchRemappings[] = {
  1289. {// Search+Shift+Left -> select to home.
  1290. {EF_COMMAND_DOWN | EF_SHIFT_DOWN, VKEY_LEFT},
  1291. {EF_SHIFT_DOWN, DomCode::HOME, DomKey::HOME, VKEY_HOME}},
  1292. {// Search+Shift+Right -> select to end.
  1293. {EF_COMMAND_DOWN | EF_SHIFT_DOWN, VKEY_RIGHT},
  1294. {EF_SHIFT_DOWN, DomCode::END, DomKey::END, VKEY_END}},
  1295. };
  1296. if (!skip_search_key_remapping &&
  1297. RewriteWithKeyboardRemappings(kNewSearchRemappings,
  1298. std::size(kNewSearchRemappings),
  1299. incoming, state, /*strict=*/true)) {
  1300. return;
  1301. }
  1302. }
  1303. }
  1304. // The new Search+Shift+Backspace rewrite is only active when
  1305. // IsImprovedKeyboardShortcutsEnabled() is true.
  1306. // TODO(crbug.com/1179893): Merge this entry into kSixPackRemappings
  1307. // once the flag is removed.
  1308. static const KeyboardRemapping kOldInsertRemapping[] = {
  1309. {// Search+Period -> Insert
  1310. {EF_COMMAND_DOWN, VKEY_OEM_PERIOD},
  1311. {EF_NONE, DomCode::INSERT, DomKey::INSERT, VKEY_INSERT}},
  1312. };
  1313. if (::features::IsImprovedKeyboardShortcutsEnabled()) {
  1314. static const KeyboardRemapping kNewInsertRemapping[] = {
  1315. {// Search+Shift+BackSpace -> Insert
  1316. {EF_COMMAND_DOWN | EF_SHIFT_DOWN, VKEY_BACK},
  1317. {EF_NONE, DomCode::INSERT, DomKey::INSERT, VKEY_INSERT}},
  1318. };
  1319. if (!skip_search_key_remapping &&
  1320. RewriteWithKeyboardRemappings(kNewInsertRemapping,
  1321. std::size(kNewInsertRemapping),
  1322. incoming, state, strict)) {
  1323. RecordSixPackEventRewrites(key_event.type(), state->key_code,
  1324. /*legacy_variant=*/false);
  1325. return;
  1326. }
  1327. // Test for the deprecated insert rewrite in order to show a notification.
  1328. const ui::KeyboardCode deprecated_key = MatchedDeprecatedRemapping(
  1329. kOldInsertRemapping, std::size(kOldInsertRemapping), incoming);
  1330. if (deprecated_key != VKEY_UNKNOWN) {
  1331. // If the key would have matched prior to being deprecated then notify
  1332. // the delegate to show a notification.
  1333. delegate_->NotifyDeprecatedSixPackKeyRewrite(deprecated_key);
  1334. }
  1335. } else {
  1336. if (!skip_search_key_remapping &&
  1337. RewriteWithKeyboardRemappings(kOldInsertRemapping,
  1338. std::size(kOldInsertRemapping),
  1339. incoming, state, strict)) {
  1340. RecordSixPackEventRewrites(key_event.type(), state->key_code,
  1341. /*legacy_variant=*/true);
  1342. return;
  1343. }
  1344. }
  1345. static const KeyboardRemapping kSixPackRemappings[] = {
  1346. {// Search+BackSpace -> Delete
  1347. {EF_COMMAND_DOWN, VKEY_BACK},
  1348. {EF_NONE, DomCode::DEL, DomKey::DEL, VKEY_DELETE}},
  1349. {// Search+Left -> Home
  1350. {EF_COMMAND_DOWN, VKEY_LEFT},
  1351. {EF_NONE, DomCode::HOME, DomKey::HOME, VKEY_HOME}},
  1352. {// Search+Up -> Prior (aka PageUp)
  1353. {EF_COMMAND_DOWN, VKEY_UP},
  1354. {EF_NONE, DomCode::PAGE_UP, DomKey::PAGE_UP, VKEY_PRIOR}},
  1355. {// Search+Right -> End
  1356. {EF_COMMAND_DOWN, VKEY_RIGHT},
  1357. {EF_NONE, DomCode::END, DomKey::END, VKEY_END}},
  1358. {// Search+Down -> Next (aka PageDown)
  1359. {EF_COMMAND_DOWN, VKEY_DOWN},
  1360. {EF_NONE, DomCode::PAGE_DOWN, DomKey::PAGE_DOWN, VKEY_NEXT}}};
  1361. if (!skip_search_key_remapping &&
  1362. RewriteWithKeyboardRemappings(kSixPackRemappings,
  1363. std::size(kSixPackRemappings), incoming,
  1364. state, strict)) {
  1365. RecordSixPackEventRewrites(key_event.type(), state->key_code,
  1366. /*legacy_variant=*/false);
  1367. return;
  1368. }
  1369. }
  1370. // TODO(crbug.com/1179893): Remove block once Alt rewrites are deprecated.
  1371. if ((incoming.flags & EF_ALT_DOWN) && is_alt_down_remapping_enabled_) {
  1372. static const KeyboardRemapping kLegacySixPackRemappings[] = {
  1373. {// Alt+BackSpace -> Delete
  1374. {EF_ALT_DOWN, VKEY_BACK},
  1375. {EF_NONE, DomCode::DEL, DomKey::DEL, VKEY_DELETE}},
  1376. {// Control+Alt+Up -> Home
  1377. {EF_ALT_DOWN | EF_CONTROL_DOWN, VKEY_UP},
  1378. {EF_NONE, DomCode::HOME, DomKey::HOME, VKEY_HOME}},
  1379. {// Alt+Up -> Prior (aka PageUp)
  1380. {EF_ALT_DOWN, VKEY_UP},
  1381. {EF_NONE, DomCode::PAGE_UP, DomKey::PAGE_UP, VKEY_PRIOR}},
  1382. {// Control+Alt+Down -> End
  1383. {EF_ALT_DOWN | EF_CONTROL_DOWN, VKEY_DOWN},
  1384. {EF_NONE, DomCode::END, DomKey::END, VKEY_END}},
  1385. {// Alt+Down -> Next (aka PageDown)
  1386. {EF_ALT_DOWN, VKEY_DOWN},
  1387. {EF_NONE, DomCode::PAGE_DOWN, DomKey::PAGE_DOWN, VKEY_NEXT}}};
  1388. if (!::features::IsImprovedKeyboardShortcutsEnabled() ||
  1389. !::features::IsDeprecateAltBasedSixPackEnabled()) {
  1390. if (RewriteWithKeyboardRemappings(kLegacySixPackRemappings,
  1391. std::size(kLegacySixPackRemappings),
  1392. incoming, state)) {
  1393. RecordSixPackEventRewrites(key_event.type(), state->key_code,
  1394. /*legacy_variant=*/true);
  1395. return;
  1396. }
  1397. } else {
  1398. const ui::KeyboardCode deprecated_key = MatchedDeprecatedRemapping(
  1399. kLegacySixPackRemappings, std::size(kLegacySixPackRemappings),
  1400. incoming);
  1401. if (deprecated_key != VKEY_UNKNOWN) {
  1402. // If the key would have matched prior to being deprecated then notify
  1403. // the delegate to show a notification.
  1404. delegate_->NotifyDeprecatedSixPackKeyRewrite(deprecated_key);
  1405. }
  1406. }
  1407. }
  1408. }
  1409. void EventRewriterChromeOS::RewriteFunctionKeys(const KeyEvent& key_event,
  1410. MutableKeyState* state) {
  1411. CHECK(key_event.type() == ET_KEY_PRESSED ||
  1412. key_event.type() == ET_KEY_RELEASED);
  1413. // Some key codes have a Dom code but no VKEY value assigned. They're mapped
  1414. // to VKEY values here.
  1415. if (state->key_code == VKEY_UNKNOWN) {
  1416. if (state->code == DomCode::SHOW_ALL_WINDOWS) {
  1417. // Show all windows is through VKEY_MEDIA_LAUNCH_APP1.
  1418. state->key_code = VKEY_MEDIA_LAUNCH_APP1;
  1419. state->key = DomKey::F4;
  1420. } else if (state->code == DomCode::DISPLAY_TOGGLE_INT_EXT) {
  1421. // Display toggle is through control + VKEY_ZOOM.
  1422. state->flags |= EF_CONTROL_DOWN;
  1423. state->key_code = VKEY_ZOOM;
  1424. state->key = DomKey::F12;
  1425. }
  1426. }
  1427. const auto iter = device_id_to_info_.find(key_event.source_device_id());
  1428. KeyboardTopRowLayout layout = kKbdTopRowLayoutDefault;
  1429. if (iter != device_id_to_info_.end()) {
  1430. layout = iter->second.top_row_layout;
  1431. }
  1432. const bool search_is_pressed = (state->flags & EF_COMMAND_DOWN) != 0;
  1433. if (layout == kKbdTopRowLayoutCustom) {
  1434. if (RewriteTopRowKeysForCustomLayout(key_event.source_device_id(),
  1435. key_event, search_is_pressed, state)) {
  1436. return;
  1437. }
  1438. } else if (layout == kKbdTopRowLayoutWilco ||
  1439. layout == kKbdTopRowLayoutDrallion) {
  1440. if (RewriteTopRowKeysForLayoutWilco(key_event, search_is_pressed, state,
  1441. layout)) {
  1442. return;
  1443. }
  1444. } else if ((state->key_code >= VKEY_F1) && (state->key_code <= VKEY_F12)) {
  1445. // Search? Top Row Result
  1446. // ------- -------- ------
  1447. // No Fn Unchanged
  1448. // No System Fn -> System
  1449. // Yes Fn Fn -> System
  1450. // Yes System Search+Fn -> Fn
  1451. if (ForceTopRowAsFunctionKeys() == search_is_pressed) {
  1452. // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
  1453. // This is the original Chrome OS layout.
  1454. static const KeyboardRemapping kFkeysToSystemKeys1[] = {
  1455. {{EF_NONE, VKEY_F1},
  1456. {EF_NONE, DomCode::BROWSER_BACK, DomKey::BROWSER_BACK,
  1457. VKEY_BROWSER_BACK}},
  1458. {{EF_NONE, VKEY_F2},
  1459. {EF_NONE, DomCode::BROWSER_FORWARD, DomKey::BROWSER_FORWARD,
  1460. VKEY_BROWSER_FORWARD}},
  1461. {{EF_NONE, VKEY_F3},
  1462. {EF_NONE, DomCode::BROWSER_REFRESH, DomKey::BROWSER_REFRESH,
  1463. VKEY_BROWSER_REFRESH}},
  1464. {{EF_NONE, VKEY_F4},
  1465. {EF_NONE, DomCode::ZOOM_TOGGLE, DomKey::ZOOM_TOGGLE, VKEY_ZOOM}},
  1466. {{EF_NONE, VKEY_F5},
  1467. {EF_NONE, DomCode::SELECT_TASK, DomKey::LAUNCH_MY_COMPUTER,
  1468. VKEY_MEDIA_LAUNCH_APP1}},
  1469. {{EF_NONE, VKEY_F6},
  1470. {EF_NONE, DomCode::BRIGHTNESS_DOWN, DomKey::BRIGHTNESS_DOWN,
  1471. VKEY_BRIGHTNESS_DOWN}},
  1472. {{EF_NONE, VKEY_F7},
  1473. {EF_NONE, DomCode::BRIGHTNESS_UP, DomKey::BRIGHTNESS_UP,
  1474. VKEY_BRIGHTNESS_UP}},
  1475. {{EF_NONE, VKEY_F8},
  1476. {EF_NONE, DomCode::VOLUME_MUTE, DomKey::AUDIO_VOLUME_MUTE,
  1477. VKEY_VOLUME_MUTE}},
  1478. {{EF_NONE, VKEY_F9},
  1479. {EF_NONE, DomCode::VOLUME_DOWN, DomKey::AUDIO_VOLUME_DOWN,
  1480. VKEY_VOLUME_DOWN}},
  1481. {{EF_NONE, VKEY_F10},
  1482. {EF_NONE, DomCode::VOLUME_UP, DomKey::AUDIO_VOLUME_UP,
  1483. VKEY_VOLUME_UP}},
  1484. };
  1485. // The new layout with forward button removed and play/pause added.
  1486. static const KeyboardRemapping kFkeysToSystemKeys2[] = {
  1487. {{EF_NONE, VKEY_F1},
  1488. {EF_NONE, DomCode::BROWSER_BACK, DomKey::BROWSER_BACK,
  1489. VKEY_BROWSER_BACK}},
  1490. {{EF_NONE, VKEY_F2},
  1491. {EF_NONE, DomCode::BROWSER_REFRESH, DomKey::BROWSER_REFRESH,
  1492. VKEY_BROWSER_REFRESH}},
  1493. {{EF_NONE, VKEY_F3},
  1494. {EF_NONE, DomCode::ZOOM_TOGGLE, DomKey::ZOOM_TOGGLE, VKEY_ZOOM}},
  1495. {{EF_NONE, VKEY_F4},
  1496. {EF_NONE, DomCode::SELECT_TASK, DomKey::LAUNCH_MY_COMPUTER,
  1497. VKEY_MEDIA_LAUNCH_APP1}},
  1498. {{EF_NONE, VKEY_F5},
  1499. {EF_NONE, DomCode::BRIGHTNESS_DOWN, DomKey::BRIGHTNESS_DOWN,
  1500. VKEY_BRIGHTNESS_DOWN}},
  1501. {{EF_NONE, VKEY_F6},
  1502. {EF_NONE, DomCode::BRIGHTNESS_UP, DomKey::BRIGHTNESS_UP,
  1503. VKEY_BRIGHTNESS_UP}},
  1504. {{EF_NONE, VKEY_F7},
  1505. {EF_NONE, DomCode::MEDIA_PLAY_PAUSE, DomKey::MEDIA_PLAY_PAUSE,
  1506. VKEY_MEDIA_PLAY_PAUSE}},
  1507. {{EF_NONE, VKEY_F8},
  1508. {EF_NONE, DomCode::VOLUME_MUTE, DomKey::AUDIO_VOLUME_MUTE,
  1509. VKEY_VOLUME_MUTE}},
  1510. {{EF_NONE, VKEY_F9},
  1511. {EF_NONE, DomCode::VOLUME_DOWN, DomKey::AUDIO_VOLUME_DOWN,
  1512. VKEY_VOLUME_DOWN}},
  1513. {{EF_NONE, VKEY_F10},
  1514. {EF_NONE, DomCode::VOLUME_UP, DomKey::AUDIO_VOLUME_UP,
  1515. VKEY_VOLUME_UP}},
  1516. };
  1517. const KeyboardRemapping* mapping = nullptr;
  1518. size_t mappingSize = 0u;
  1519. switch (layout) {
  1520. case kKbdTopRowLayout2:
  1521. mapping = kFkeysToSystemKeys2;
  1522. mappingSize = std::size(kFkeysToSystemKeys2);
  1523. break;
  1524. case kKbdTopRowLayout1:
  1525. default:
  1526. mapping = kFkeysToSystemKeys1;
  1527. mappingSize = std::size(kFkeysToSystemKeys1);
  1528. break;
  1529. }
  1530. MutableKeyState incoming_without_command = *state;
  1531. incoming_without_command.flags &= ~EF_COMMAND_DOWN;
  1532. if (RewriteWithKeyboardRemappings(mapping, mappingSize,
  1533. incoming_without_command, state)) {
  1534. return;
  1535. }
  1536. } else if (search_is_pressed) {
  1537. // Allow Search to avoid rewriting F1-F12.
  1538. state->flags &= ~EF_COMMAND_DOWN;
  1539. return;
  1540. }
  1541. }
  1542. // TODO(crbug.com/1179893): Remove this entire block when
  1543. // IsImprovedKeyboardShortcutsEnabled is always on.
  1544. if (state->flags & EF_COMMAND_DOWN) {
  1545. const bool strict = ::features::IsNewShortcutMappingEnabled();
  1546. struct SearchToFunctionMap {
  1547. DomCode input_dom_code;
  1548. MutableKeyState result;
  1549. };
  1550. // We check the DOM3 |code| here instead of the VKEY, as these keys may
  1551. // have different |KeyboardCode|s when modifiers are pressed, such as
  1552. // shift.
  1553. if (strict) {
  1554. DCHECK(!::features::IsImprovedKeyboardShortcutsEnabled());
  1555. // Remap Search + 1/2 to F11/12.
  1556. static const SearchToFunctionMap kNumberKeysToFkeys[] = {
  1557. {DomCode::DIGIT1, {EF_NONE, DomCode::F11, DomKey::F12, VKEY_F11}},
  1558. {DomCode::DIGIT2, {EF_NONE, DomCode::F12, DomKey::F12, VKEY_F12}},
  1559. };
  1560. for (const auto& map : kNumberKeysToFkeys) {
  1561. if (state->code == map.input_dom_code) {
  1562. state->flags &= ~EF_COMMAND_DOWN;
  1563. ApplyRemapping(map.result, state);
  1564. return;
  1565. }
  1566. }
  1567. } else {
  1568. // Remap Search + digit row to F1~F12.
  1569. static const SearchToFunctionMap kNumberKeysToFkeys[] = {
  1570. {DomCode::DIGIT1, {EF_NONE, DomCode::F1, DomKey::F1, VKEY_F1}},
  1571. {DomCode::DIGIT2, {EF_NONE, DomCode::F2, DomKey::F2, VKEY_F2}},
  1572. {DomCode::DIGIT3, {EF_NONE, DomCode::F3, DomKey::F3, VKEY_F3}},
  1573. {DomCode::DIGIT4, {EF_NONE, DomCode::F4, DomKey::F4, VKEY_F4}},
  1574. {DomCode::DIGIT5, {EF_NONE, DomCode::F5, DomKey::F5, VKEY_F5}},
  1575. {DomCode::DIGIT6, {EF_NONE, DomCode::F6, DomKey::F6, VKEY_F6}},
  1576. {DomCode::DIGIT7, {EF_NONE, DomCode::F7, DomKey::F7, VKEY_F7}},
  1577. {DomCode::DIGIT8, {EF_NONE, DomCode::F8, DomKey::F8, VKEY_F8}},
  1578. {DomCode::DIGIT9, {EF_NONE, DomCode::F9, DomKey::F9, VKEY_F9}},
  1579. {DomCode::DIGIT0, {EF_NONE, DomCode::F10, DomKey::F10, VKEY_F10}},
  1580. {DomCode::MINUS, {EF_NONE, DomCode::F11, DomKey::F11, VKEY_F11}},
  1581. {DomCode::EQUAL, {EF_NONE, DomCode::F12, DomKey::F12, VKEY_F12}}};
  1582. for (const auto& map : kNumberKeysToFkeys) {
  1583. if (state->code == map.input_dom_code) {
  1584. if (!::features::IsImprovedKeyboardShortcutsEnabled()) {
  1585. state->flags &= ~EF_COMMAND_DOWN;
  1586. ApplyRemapping(map.result, state);
  1587. RecordSearchPlusDigitFKeyRewrite(key_event.type(), state->key_code);
  1588. } else {
  1589. // Only trigger the notification for F1-F10.
  1590. //
  1591. // Because of this legacy remapping 2 virtual desk shortcuts
  1592. // implicitly used F11 and F12 because the shortcut included
  1593. // Search and either minus or equal. Do not trigger a
  1594. // notification for this case because it wasn't the users intent.
  1595. if (static_cast<int>(map.result.code) <=
  1596. static_cast<int>(DomCode::F10)) {
  1597. DCHECK_GE(static_cast<int>(map.result.code),
  1598. static_cast<int>(DomCode::F1));
  1599. delegate_->NotifyDeprecatedFKeyRewrite();
  1600. }
  1601. }
  1602. return;
  1603. }
  1604. }
  1605. }
  1606. }
  1607. }
  1608. int EventRewriterChromeOS::RewriteLocatedEvent(const Event& event) {
  1609. if (!delegate_)
  1610. return event.flags();
  1611. return GetRemappedModifierMasks(event, event.flags());
  1612. }
  1613. int EventRewriterChromeOS::RewriteModifierClick(const MouseEvent& mouse_event,
  1614. int* flags) {
  1615. // Note that this behavior is limited to mouse events coming from touchpad
  1616. // devices. https://crbug.com/890648.
  1617. // Remap either Alt+Button1 or Search+Button1 to Button3 based on
  1618. // flag/setting.
  1619. int matched_mask;
  1620. bool matched_alt_deprecation;
  1621. if (ShouldRemapToRightClick(mouse_event, *flags, &matched_mask,
  1622. &matched_alt_deprecation)) {
  1623. // If the rewrite matched the deprecation message should also not occur.
  1624. DCHECK(!matched_alt_deprecation);
  1625. *flags &= ~matched_mask;
  1626. *flags |= EF_RIGHT_MOUSE_BUTTON;
  1627. if (mouse_event.type() == ET_MOUSE_PRESSED) {
  1628. pressed_device_ids_.insert(mouse_event.source_device_id());
  1629. if (matched_mask == kSearchLeftButton) {
  1630. base::RecordAction(
  1631. base::UserMetricsAction("SearchClickMappedToRightClick"));
  1632. } else {
  1633. DCHECK(matched_mask == kAltLeftButton);
  1634. base::RecordAction(
  1635. base::UserMetricsAction("AltClickMappedToRightClick"));
  1636. }
  1637. } else {
  1638. pressed_device_ids_.erase(mouse_event.source_device_id());
  1639. }
  1640. return EF_RIGHT_MOUSE_BUTTON;
  1641. } else if (matched_alt_deprecation) {
  1642. delegate_->NotifyDeprecatedRightClickRewrite();
  1643. }
  1644. return EF_NONE;
  1645. }
  1646. EventDispatchDetails EventRewriterChromeOS::RewriteKeyEventInContext(
  1647. const KeyEvent& key_event,
  1648. std::unique_ptr<Event> rewritten_event,
  1649. EventRewriteStatus status,
  1650. const Continuation continuation) {
  1651. if (status == EventRewriteStatus::EVENT_REWRITE_DISCARD)
  1652. return DiscardEvent(continuation);
  1653. MutableKeyState current_key_state;
  1654. auto key_state_comparator =
  1655. [&current_key_state](
  1656. const std::pair<MutableKeyState, MutableKeyState>& key_state) {
  1657. return (current_key_state.code == key_state.first.code) &&
  1658. (current_key_state.key == key_state.first.key) &&
  1659. (current_key_state.key_code == key_state.first.key_code);
  1660. };
  1661. const int mapped_flag = ModifierDomKeyToEventFlag(key_event.GetDomKey());
  1662. if (key_event.type() == ET_KEY_PRESSED) {
  1663. current_key_state = MutableKeyState(
  1664. rewritten_event ? static_cast<const KeyEvent*>(rewritten_event.get())
  1665. : &key_event);
  1666. MutableKeyState original_key_state(&key_event);
  1667. auto iter = std::find_if(pressed_key_states_.begin(),
  1668. pressed_key_states_.end(), key_state_comparator);
  1669. // When a key is pressed, store |current_key_state| if it is not stored
  1670. // before.
  1671. if (iter == pressed_key_states_.end()) {
  1672. pressed_key_states_.push_back(
  1673. std::make_pair(current_key_state, original_key_state));
  1674. }
  1675. if (status == EventRewriteStatus::EVENT_REWRITE_CONTINUE)
  1676. return SendEvent(continuation, &key_event);
  1677. EventDispatchDetails details =
  1678. SendEventFinally(continuation, rewritten_event.get());
  1679. if (status == EventRewriteStatus::EVENT_REWRITE_DISPATCH_ANOTHER &&
  1680. !details.dispatcher_destroyed) {
  1681. return SendStickyKeysReleaseEvents(std::move(rewritten_event),
  1682. continuation);
  1683. }
  1684. return details;
  1685. }
  1686. DCHECK_EQ(key_event.type(), ET_KEY_RELEASED);
  1687. if (mapped_flag != EF_NONE) {
  1688. // The released key is a modifier
  1689. DomKey::Base current_key = key_event.GetDomKey();
  1690. auto key_state_iter = pressed_key_states_.begin();
  1691. int event_flags =
  1692. rewritten_event ? rewritten_event->flags() : key_event.flags();
  1693. rewritten_event.reset();
  1694. // Iterate the keys being pressed. Release the key events which satisfy one
  1695. // of the following conditions:
  1696. // (1) the key event's original key code (before key event rewriting if
  1697. // any) is the same with the key to be released.
  1698. // (2) the key event is rewritten and its original flags are influenced by
  1699. // the key to be released.
  1700. // Example: Press the Launcher button, Press the Up Arrow button, Release
  1701. // the Launcher button. When Launcher is released: the key event whose key
  1702. // code is Launcher should be released because it satisfies the condition 1;
  1703. // the key event whose key code is PageUp should be released because it
  1704. // satisfies the condition 2.
  1705. EventDispatchDetails details;
  1706. while (key_state_iter != pressed_key_states_.end() &&
  1707. !details.dispatcher_destroyed) {
  1708. const bool is_rewritten =
  1709. (key_state_iter->first.key != key_state_iter->second.key);
  1710. const bool flag_affected = key_state_iter->second.flags & mapped_flag;
  1711. const bool should_release = key_state_iter->second.key == current_key ||
  1712. (flag_affected && is_rewritten);
  1713. if (should_release) {
  1714. // If the key should be released, create a key event for it.
  1715. auto dispatched_event = std::make_unique<KeyEvent>(
  1716. key_event.type(), key_state_iter->first.key_code,
  1717. key_state_iter->first.code, event_flags, key_state_iter->first.key,
  1718. key_event.time_stamp());
  1719. dispatched_event->set_scan_code(key_event.scan_code());
  1720. details = SendEventFinally(continuation, dispatched_event.get());
  1721. key_state_iter = pressed_key_states_.erase(key_state_iter);
  1722. continue;
  1723. }
  1724. key_state_iter++;
  1725. }
  1726. return details;
  1727. }
  1728. // The released key is not a modifier
  1729. current_key_state = MutableKeyState(
  1730. rewritten_event ? static_cast<const KeyEvent*>(rewritten_event.get())
  1731. : &key_event);
  1732. auto iter = std::find_if(pressed_key_states_.begin(),
  1733. pressed_key_states_.end(), key_state_comparator);
  1734. if (iter != pressed_key_states_.end()) {
  1735. pressed_key_states_.erase(iter);
  1736. if (status == EventRewriteStatus::EVENT_REWRITE_CONTINUE)
  1737. return SendEvent(continuation, &key_event);
  1738. EventDispatchDetails details =
  1739. SendEventFinally(continuation, rewritten_event.get());
  1740. if (status == EventRewriteStatus::EVENT_REWRITE_DISPATCH_ANOTHER &&
  1741. !details.dispatcher_destroyed) {
  1742. return SendStickyKeysReleaseEvents(std::move(rewritten_event),
  1743. continuation);
  1744. }
  1745. return details;
  1746. }
  1747. // Event rewriting may create a meaningless key event.
  1748. // For example: press the Up Arrow button, press the Launcher button,
  1749. // release the Up Arrow. When the Up Arrow button is released, key event
  1750. // rewriting happens. However, the rewritten event is not among
  1751. // |pressed_key_states_|. So it should be blocked and the original event
  1752. // should be propagated.
  1753. return SendEvent(continuation, &key_event);
  1754. }
  1755. bool EventRewriterChromeOS::StoreCustomTopRowMapping(
  1756. const InputDevice& keyboard_device,
  1757. base::flat_map<uint32_t, EventRewriterChromeOS::MutableKeyState>
  1758. top_row_map) {
  1759. std::string layout;
  1760. if (!GetCustomTopRowLayout(keyboard_device, &layout)) {
  1761. LOG(WARNING) << "Could not read top row layout map for device "
  1762. << keyboard_device.id;
  1763. return false;
  1764. }
  1765. top_row_scan_code_map_[keyboard_device.id] = std::move(top_row_map);
  1766. return true;
  1767. }
  1768. // New CrOS keyboards differ from previous Chrome OS keyboards in a few
  1769. // ways. Previous keyboards always sent F1-Fxx keys and allowed Chrome to
  1770. // decide how to interpret them. New CrOS keyboards now always send action
  1771. // keys (eg. Back, Refresh, Overview). So while the default previously was
  1772. // to always expect to remap F-Key to action key, for these devices respect
  1773. // what the keyboard sends unless the user overrides with either the Search
  1774. // key or the "Top Row is always F-Key" setting.
  1775. //
  1776. // Additionally, these keyboards provide the mapping via sysfs so each
  1777. // new keyboard does not need to be explicitly special cased in the future.
  1778. //
  1779. // Search Force function keys Key code Result
  1780. // ------- ------------------- -------- ------
  1781. // No No Function Unchanged
  1782. // Yes No Function Unchanged
  1783. // No Yes Function Unchanged
  1784. // Yes Yes Function Unchanged
  1785. // No No Action Unchanged
  1786. // Yes No Action Action -> Fn
  1787. // No Yes Action Action -> Fn
  1788. // Yes Yes Action Unchanged
  1789. bool EventRewriterChromeOS::RewriteTopRowKeysForCustomLayout(
  1790. int device_id,
  1791. const KeyEvent& key_event,
  1792. bool search_is_pressed,
  1793. EventRewriterChromeOS::MutableKeyState* state) {
  1794. // Incoming function keys are never remapped.
  1795. if (IsCustomLayoutFunctionKey(key_event.key_code())) {
  1796. return true;
  1797. }
  1798. const auto& scan_code_map_iter = top_row_scan_code_map_.find(device_id);
  1799. if (scan_code_map_iter == top_row_scan_code_map_.end()) {
  1800. LOG(WARNING) << "Found no top row key mapping for device " << device_id;
  1801. return false;
  1802. }
  1803. const base::flat_map<uint32_t, MutableKeyState>& scan_code_map =
  1804. scan_code_map_iter->second;
  1805. const auto& key_iter = scan_code_map.find(key_event.scan_code());
  1806. // If the scan code appears in the top row mapping it is an action key.
  1807. const bool is_action_key = (key_iter != scan_code_map.end());
  1808. if (is_action_key) {
  1809. if (search_is_pressed != ForceTopRowAsFunctionKeys()) {
  1810. ApplyRemapping(key_iter->second, state);
  1811. }
  1812. // Clear command/search key if pressed. It's been consumed in the remapping
  1813. // or wasn't pressed.
  1814. state->flags &= ~EF_COMMAND_DOWN;
  1815. return true;
  1816. }
  1817. return false;
  1818. }
  1819. // The keyboard layout for Wilco has a slightly different top-row layout, emits
  1820. // both Fn and action keys from kernel and has key events with Dom codes and no
  1821. // VKey value == VKEY_UNKNOWN. Depending on the state of the search key and
  1822. // force-function-key preference, function keys have to be mapped to action keys
  1823. // or vice versa.
  1824. //
  1825. // Search force function keys key code Result
  1826. // ------- ------------------- -------- ------
  1827. // No No Function Unchanged
  1828. // Yes No Function Fn -> Action
  1829. // No Yes Function Unchanged
  1830. // Yes Yes Function Fn -> Action
  1831. // No No Action Unchanged
  1832. // Yes No Action Action -> Fn
  1833. // No Yes Action Action -> Fn
  1834. // Yes Yes Action Unchanged
  1835. bool EventRewriterChromeOS::RewriteTopRowKeysForLayoutWilco(
  1836. const KeyEvent& key_event,
  1837. bool search_is_pressed,
  1838. MutableKeyState* state,
  1839. KeyboardTopRowLayout layout) {
  1840. // When the kernel issues an function key (Fn modifier help down) and the
  1841. // search key is pressed, the function key needs to be mapped to its
  1842. // corresponding action key. This table defines those function-to-action
  1843. // mappings.
  1844. static const KeyboardRemapping kFnkeysToActionKeys[] = {
  1845. {{EF_NONE, VKEY_F1},
  1846. {EF_NONE, DomCode::BROWSER_BACK, DomKey::BROWSER_BACK,
  1847. VKEY_BROWSER_BACK}},
  1848. {{EF_NONE, VKEY_F2},
  1849. {EF_NONE, DomCode::BROWSER_REFRESH, DomKey::BROWSER_REFRESH,
  1850. VKEY_BROWSER_REFRESH}},
  1851. // Map F3 to VKEY_ZOOM + EF_NONE == toggle full screen:
  1852. {{EF_NONE, VKEY_F3},
  1853. {EF_NONE, DomCode::ZOOM_TOGGLE, DomKey::ZOOM_TOGGLE, VKEY_ZOOM}},
  1854. // Map F4 to VKEY_MEDIA_LAUNCH_APP1 + EF_NONE == overview:
  1855. {{EF_NONE, VKEY_F4},
  1856. {EF_NONE, DomCode::F4, DomKey::F4, VKEY_MEDIA_LAUNCH_APP1}},
  1857. {{EF_NONE, VKEY_F5},
  1858. {EF_NONE, DomCode::BRIGHTNESS_DOWN, DomKey::BRIGHTNESS_DOWN,
  1859. VKEY_BRIGHTNESS_DOWN}},
  1860. {{EF_NONE, VKEY_F6},
  1861. {EF_NONE, DomCode::BRIGHTNESS_UP, DomKey::BRIGHTNESS_UP,
  1862. VKEY_BRIGHTNESS_UP}},
  1863. {{EF_NONE, VKEY_F7},
  1864. {EF_NONE, DomCode::VOLUME_MUTE, DomKey::AUDIO_VOLUME_MUTE,
  1865. VKEY_VOLUME_MUTE}},
  1866. {{EF_NONE, VKEY_F8},
  1867. {EF_NONE, DomCode::VOLUME_DOWN, DomKey::AUDIO_VOLUME_DOWN,
  1868. VKEY_VOLUME_DOWN}},
  1869. {{EF_NONE, VKEY_F9},
  1870. {EF_NONE, DomCode::VOLUME_UP, DomKey::AUDIO_VOLUME_UP, VKEY_VOLUME_UP}},
  1871. // Note: F10 and F11 are left as-is since no action is associated with
  1872. // these keys.
  1873. {{EF_NONE, VKEY_F10}, {EF_NONE, DomCode::F10, DomKey::F10, VKEY_F10}},
  1874. {{EF_NONE, VKEY_F11}, {EF_NONE, DomCode::F11, DomKey::F11, VKEY_F11}},
  1875. {{EF_NONE, VKEY_F12},
  1876. // Map F12 to VKEY_ZOOM + EF_CONTROL_DOWN == toggle mirror
  1877. // mode:
  1878. {EF_CONTROL_DOWN, DomCode::F12, DomKey::F12, VKEY_ZOOM}},
  1879. };
  1880. // When the kernel issues an action key (default mode) and the search key is
  1881. // pressed, the action key needs to be mapped back to its corresponding
  1882. // action key. This table defines those action-to-function mappings. Note:
  1883. // this table is essentially the dual of kFnToActionLeys above.
  1884. static const KeyboardRemapping kActionToFnKeys[] = {
  1885. {{EF_NONE, VKEY_BROWSER_BACK},
  1886. {EF_NONE, DomCode::F1, DomKey::F1, VKEY_F1}},
  1887. {{EF_NONE, VKEY_BROWSER_REFRESH},
  1888. {EF_NONE, DomCode::F2, DomKey::F2, VKEY_F2}},
  1889. {{EF_NONE, VKEY_MEDIA_LAUNCH_APP1},
  1890. {EF_NONE, DomCode::F4, DomKey::F4, VKEY_F4}},
  1891. {{EF_NONE, VKEY_BRIGHTNESS_DOWN},
  1892. {EF_NONE, DomCode::F5, DomKey::F5, VKEY_F5}},
  1893. {{EF_NONE, VKEY_BRIGHTNESS_UP},
  1894. {EF_NONE, DomCode::F6, DomKey::F6, VKEY_F6}},
  1895. {{EF_NONE, VKEY_VOLUME_MUTE},
  1896. {EF_NONE, DomCode::F7, DomKey::F7, VKEY_F7}},
  1897. {{EF_NONE, VKEY_VOLUME_DOWN},
  1898. {EF_NONE, DomCode::F8, DomKey::F8, VKEY_F8}},
  1899. {{EF_NONE, VKEY_VOLUME_UP}, {EF_NONE, DomCode::F9, DomKey::F9, VKEY_F9}},
  1900. // Do not change the order of the next two entries. The remapping of
  1901. // VKEY_ZOOM with Control held down must appear before
  1902. // VKEY_ZOOM by itself to be considered.
  1903. {{EF_CONTROL_DOWN, VKEY_ZOOM},
  1904. {EF_NONE, DomCode::F12, DomKey::F12, VKEY_F12}},
  1905. {{EF_NONE, VKEY_ZOOM}, {EF_NONE, DomCode::F3, DomKey::F3, VKEY_F3}},
  1906. // VKEY_PRIVACY_SCREEN_TOGGLE shares a key with F12 on Drallion.
  1907. {{EF_NONE, VKEY_PRIVACY_SCREEN_TOGGLE},
  1908. {EF_NONE, DomCode::F12, DomKey::F12, VKEY_F12}},
  1909. };
  1910. MutableKeyState incoming_without_command = *state;
  1911. incoming_without_command.flags &= ~EF_COMMAND_DOWN;
  1912. if ((state->key_code >= VKEY_F1) && (state->key_code <= VKEY_F12)) {
  1913. // Incoming key code is a Fn key. Check if it needs to be mapped back to its
  1914. // corresponding action key.
  1915. if (search_is_pressed) {
  1916. // On some Drallion devices, F12 shares a key with privacy screen toggle.
  1917. // Account for this before rewriting for Wilco 1.0 layout.
  1918. if (layout == kKbdTopRowLayoutDrallion && state->key_code == VKEY_F12) {
  1919. if (privacy_screen_supported_) {
  1920. state->key_code = VKEY_PRIVACY_SCREEN_TOGGLE;
  1921. state->code = DomCode::PRIVACY_SCREEN_TOGGLE;
  1922. }
  1923. // Clear command flag before returning
  1924. state->flags = (state->flags & ~EF_COMMAND_DOWN);
  1925. return true;
  1926. }
  1927. return RewriteWithKeyboardRemappings(kFnkeysToActionKeys,
  1928. std::size(kFnkeysToActionKeys),
  1929. incoming_without_command, state);
  1930. }
  1931. return true;
  1932. } else if (IsKeyCodeInMappings(state->key_code, kActionToFnKeys,
  1933. std::size(kActionToFnKeys))) {
  1934. // Incoming key code is an action key. Check if it needs to be mapped back
  1935. // to its corresponding function key.
  1936. if (search_is_pressed != ForceTopRowAsFunctionKeys()) {
  1937. // On Drallion, mirror mode toggle is on its own key so don't remap it.
  1938. if (layout == kKbdTopRowLayoutDrallion &&
  1939. MatchKeyboardRemapping(*state, {EF_CONTROL_DOWN, VKEY_ZOOM})) {
  1940. // Clear command flag before returning
  1941. state->flags = (state->flags & ~EF_COMMAND_DOWN);
  1942. return true;
  1943. }
  1944. return RewriteWithKeyboardRemappings(kActionToFnKeys,
  1945. std::size(kActionToFnKeys),
  1946. incoming_without_command, state);
  1947. }
  1948. // Remap Privacy Screen Toggle to F12 on Drallion devices that do not have
  1949. // privacy screens.
  1950. if (layout == kKbdTopRowLayoutDrallion && !privacy_screen_supported_ &&
  1951. MatchKeyboardRemapping(*state, {EF_NONE, VKEY_PRIVACY_SCREEN_TOGGLE})) {
  1952. state->key_code = VKEY_F12;
  1953. state->code = DomCode::F12;
  1954. state->key = DomKey::F12;
  1955. }
  1956. // At this point we know search_is_pressed == ForceTopRowAsFunctionKeys().
  1957. // If they're both true, they cancel each other. Thus we can clear the
  1958. // search-key modifier flag.
  1959. state->flags &= ~EF_COMMAND_DOWN;
  1960. return true;
  1961. }
  1962. return false;
  1963. }
  1964. bool EventRewriterChromeOS::ForceTopRowAsFunctionKeys() const {
  1965. return delegate_ && delegate_->TopRowKeysAreFunctionKeys();
  1966. }
  1967. EventRewriterChromeOS::DeviceType EventRewriterChromeOS::KeyboardDeviceAdded(
  1968. int device_id) {
  1969. if (!DeviceDataManager::HasInstance())
  1970. return kDeviceUnknown;
  1971. const std::vector<InputDevice>& keyboard_devices =
  1972. DeviceDataManager::GetInstance()->GetKeyboardDevices();
  1973. for (const auto& keyboard : keyboard_devices) {
  1974. if (keyboard.id != device_id)
  1975. continue;
  1976. DeviceType type;
  1977. KeyboardTopRowLayout layout;
  1978. base::flat_map<uint32_t, EventRewriterChromeOS::MutableKeyState>
  1979. top_row_map;
  1980. // Don't store a device info when an error occurred while reading from
  1981. // udev. This gives a chance to reattempt reading from udev on
  1982. // subsequent key events, rather than being stuck in a bad state until
  1983. // next reboot. crbug.com/783166.
  1984. if (!IdentifyKeyboard(keyboard, &type, &layout, &top_row_map)) {
  1985. return type;
  1986. }
  1987. // For custom layouts, parse and save the top row mapping.
  1988. if (layout == EventRewriterChromeOS::kKbdTopRowLayoutCustom) {
  1989. if (!StoreCustomTopRowMapping(keyboard, std::move(top_row_map))) {
  1990. return type;
  1991. }
  1992. }
  1993. // Always overwrite the existing device_id since the X server may
  1994. // reuse a device id for an unattached device.
  1995. device_id_to_info_[keyboard.id] = {type, layout};
  1996. return type;
  1997. }
  1998. return kDeviceUnknown;
  1999. }
  2000. EventDispatchDetails EventRewriterChromeOS::SendStickyKeysReleaseEvents(
  2001. std::unique_ptr<Event> rewritten_event,
  2002. const Continuation continuation) {
  2003. EventDispatchDetails details;
  2004. std::unique_ptr<Event> last_sent_event = std::move(rewritten_event);
  2005. while (sticky_keys_controller_ && !details.dispatcher_destroyed) {
  2006. std::unique_ptr<Event> new_event;
  2007. EventRewriteStatus status = sticky_keys_controller_->NextDispatchEvent(
  2008. *last_sent_event, &new_event);
  2009. details = SendEventFinally(continuation, new_event.get());
  2010. last_sent_event = std::move(new_event);
  2011. if (status != EventRewriteStatus::EVENT_REWRITE_DISPATCH_ANOTHER)
  2012. return details;
  2013. }
  2014. return details;
  2015. }
  2016. } // namespace ui