1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "mozilla/Logging.h"
7 
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/MouseEvents.h"
11 #include "mozilla/MiscEvents.h"
12 #include "mozilla/TextEvents.h"
13 
14 #include "nsAlgorithm.h"
15 #include "nsExceptionHandler.h"
16 #include "nsGkAtoms.h"
17 #include "nsIIdleServiceInternal.h"
18 #include "nsIWindowsRegKey.h"
19 #include "nsMemory.h"
20 #include "nsPrintfCString.h"
21 #include "nsQuickSort.h"
22 #include "nsServiceManagerUtils.h"
23 #include "nsToolkit.h"
24 #include "nsUnicharUtils.h"
25 #include "nsWindowDbg.h"
26 
27 #include "KeyboardLayout.h"
28 #include "WidgetUtils.h"
29 #include "WinUtils.h"
30 
31 #include "npapi.h"
32 
33 #include <windows.h>
34 #include <winuser.h>
35 #include <algorithm>
36 
37 #ifndef WINABLEAPI
38 #include <winable.h>
39 #endif
40 
41 // In WinUser.h, MAPVK_VK_TO_VSC_EX is defined only when WINVER >= 0x0600
42 #ifndef MAPVK_VK_TO_VSC_EX
43 #define MAPVK_VK_TO_VSC_EX (4)
44 #endif
45 
46 namespace mozilla {
47 namespace widget {
48 
49 static const char* const kVirtualKeyName[] = {
50     "NULL",
51     "VK_LBUTTON",
52     "VK_RBUTTON",
53     "VK_CANCEL",
54     "VK_MBUTTON",
55     "VK_XBUTTON1",
56     "VK_XBUTTON2",
57     "0x07",
58     "VK_BACK",
59     "VK_TAB",
60     "0x0A",
61     "0x0B",
62     "VK_CLEAR",
63     "VK_RETURN",
64     "0x0E",
65     "0x0F",
66 
67     "VK_SHIFT",
68     "VK_CONTROL",
69     "VK_MENU",
70     "VK_PAUSE",
71     "VK_CAPITAL",
72     "VK_KANA, VK_HANGUL",
73     "0x16",
74     "VK_JUNJA",
75     "VK_FINAL",
76     "VK_HANJA, VK_KANJI",
77     "0x1A",
78     "VK_ESCAPE",
79     "VK_CONVERT",
80     "VK_NONCONVERT",
81     "VK_ACCEPT",
82     "VK_MODECHANGE",
83 
84     "VK_SPACE",
85     "VK_PRIOR",
86     "VK_NEXT",
87     "VK_END",
88     "VK_HOME",
89     "VK_LEFT",
90     "VK_UP",
91     "VK_RIGHT",
92     "VK_DOWN",
93     "VK_SELECT",
94     "VK_PRINT",
95     "VK_EXECUTE",
96     "VK_SNAPSHOT",
97     "VK_INSERT",
98     "VK_DELETE",
99     "VK_HELP",
100 
101     "VK_0",
102     "VK_1",
103     "VK_2",
104     "VK_3",
105     "VK_4",
106     "VK_5",
107     "VK_6",
108     "VK_7",
109     "VK_8",
110     "VK_9",
111     "0x3A",
112     "0x3B",
113     "0x3C",
114     "0x3D",
115     "0x3E",
116     "0x3F",
117 
118     "0x40",
119     "VK_A",
120     "VK_B",
121     "VK_C",
122     "VK_D",
123     "VK_E",
124     "VK_F",
125     "VK_G",
126     "VK_H",
127     "VK_I",
128     "VK_J",
129     "VK_K",
130     "VK_L",
131     "VK_M",
132     "VK_N",
133     "VK_O",
134 
135     "VK_P",
136     "VK_Q",
137     "VK_R",
138     "VK_S",
139     "VK_T",
140     "VK_U",
141     "VK_V",
142     "VK_W",
143     "VK_X",
144     "VK_Y",
145     "VK_Z",
146     "VK_LWIN",
147     "VK_RWIN",
148     "VK_APPS",
149     "0x5E",
150     "VK_SLEEP",
151 
152     "VK_NUMPAD0",
153     "VK_NUMPAD1",
154     "VK_NUMPAD2",
155     "VK_NUMPAD3",
156     "VK_NUMPAD4",
157     "VK_NUMPAD5",
158     "VK_NUMPAD6",
159     "VK_NUMPAD7",
160     "VK_NUMPAD8",
161     "VK_NUMPAD9",
162     "VK_MULTIPLY",
163     "VK_ADD",
164     "VK_SEPARATOR",
165     "VK_SUBTRACT",
166     "VK_DECIMAL",
167     "VK_DIVIDE",
168 
169     "VK_F1",
170     "VK_F2",
171     "VK_F3",
172     "VK_F4",
173     "VK_F5",
174     "VK_F6",
175     "VK_F7",
176     "VK_F8",
177     "VK_F9",
178     "VK_F10",
179     "VK_F11",
180     "VK_F12",
181     "VK_F13",
182     "VK_F14",
183     "VK_F15",
184     "VK_F16",
185 
186     "VK_F17",
187     "VK_F18",
188     "VK_F19",
189     "VK_F20",
190     "VK_F21",
191     "VK_F22",
192     "VK_F23",
193     "VK_F24",
194     "0x88",
195     "0x89",
196     "0x8A",
197     "0x8B",
198     "0x8C",
199     "0x8D",
200     "0x8E",
201     "0x8F",
202 
203     "VK_NUMLOCK",
204     "VK_SCROLL",
205     "VK_OEM_NEC_EQUAL, VK_OEM_FJ_JISHO",
206     "VK_OEM_FJ_MASSHOU",
207     "VK_OEM_FJ_TOUROKU",
208     "VK_OEM_FJ_LOYA",
209     "VK_OEM_FJ_ROYA",
210     "0x97",
211     "0x98",
212     "0x99",
213     "0x9A",
214     "0x9B",
215     "0x9C",
216     "0x9D",
217     "0x9E",
218     "0x9F",
219 
220     "VK_LSHIFT",
221     "VK_RSHIFT",
222     "VK_LCONTROL",
223     "VK_RCONTROL",
224     "VK_LMENU",
225     "VK_RMENU",
226     "VK_BROWSER_BACK",
227     "VK_BROWSER_FORWARD",
228     "VK_BROWSER_REFRESH",
229     "VK_BROWSER_STOP",
230     "VK_BROWSER_SEARCH",
231     "VK_BROWSER_FAVORITES",
232     "VK_BROWSER_HOME",
233     "VK_VOLUME_MUTE",
234     "VK_VOLUME_DOWN",
235     "VK_VOLUME_UP",
236 
237     "VK_MEDIA_NEXT_TRACK",
238     "VK_MEDIA_PREV_TRACK",
239     "VK_MEDIA_STOP",
240     "VK_MEDIA_PLAY_PAUSE",
241     "VK_LAUNCH_MAIL",
242     "VK_LAUNCH_MEDIA_SELECT",
243     "VK_LAUNCH_APP1",
244     "VK_LAUNCH_APP2",
245     "0xB8",
246     "0xB9",
247     "VK_OEM_1",
248     "VK_OEM_PLUS",
249     "VK_OEM_COMMA",
250     "VK_OEM_MINUS",
251     "VK_OEM_PERIOD",
252     "VK_OEM_2",
253 
254     "VK_OEM_3",
255     "VK_ABNT_C1",
256     "VK_ABNT_C2",
257     "0xC3",
258     "0xC4",
259     "0xC5",
260     "0xC6",
261     "0xC7",
262     "0xC8",
263     "0xC9",
264     "0xCA",
265     "0xCB",
266     "0xCC",
267     "0xCD",
268     "0xCE",
269     "0xCF",
270 
271     "0xD0",
272     "0xD1",
273     "0xD2",
274     "0xD3",
275     "0xD4",
276     "0xD5",
277     "0xD6",
278     "0xD7",
279     "0xD8",
280     "0xD9",
281     "0xDA",
282     "VK_OEM_4",
283     "VK_OEM_5",
284     "VK_OEM_6",
285     "VK_OEM_7",
286     "VK_OEM_8",
287 
288     "0xE0",
289     "VK_OEM_AX",
290     "VK_OEM_102",
291     "VK_ICO_HELP",
292     "VK_ICO_00",
293     "VK_PROCESSKEY",
294     "VK_ICO_CLEAR",
295     "VK_PACKET",
296     "0xE8",
297     "VK_OEM_RESET",
298     "VK_OEM_JUMP",
299     "VK_OEM_PA1",
300     "VK_OEM_PA2",
301     "VK_OEM_PA3",
302     "VK_OEM_WSCTRL",
303     "VK_OEM_CUSEL",
304 
305     "VK_OEM_ATTN",
306     "VK_OEM_FINISH",
307     "VK_OEM_COPY",
308     "VK_OEM_AUTO",
309     "VK_OEM_ENLW",
310     "VK_OEM_BACKTAB",
311     "VK_ATTN",
312     "VK_CRSEL",
313     "VK_EXSEL",
314     "VK_EREOF",
315     "VK_PLAY",
316     "VK_ZOOM",
317     "VK_NONAME",
318     "VK_PA1",
319     "VK_OEM_CLEAR",
320     "0xFF"};
321 
322 static_assert(sizeof(kVirtualKeyName) / sizeof(const char*) == 0x100,
323               "The virtual key name must be defined just 256 keys");
324 
GetBoolName(bool aBool)325 static const char* GetBoolName(bool aBool) { return aBool ? "true" : "false"; }
326 
GetCharacterCodeName(WPARAM aCharCode)327 static const nsCString GetCharacterCodeName(WPARAM aCharCode) {
328   switch (aCharCode) {
329     case 0x0000:
330       return NS_LITERAL_CSTRING("NULL (0x0000)");
331     case 0x0008:
332       return NS_LITERAL_CSTRING("BACKSPACE (0x0008)");
333     case 0x0009:
334       return NS_LITERAL_CSTRING("CHARACTER TABULATION (0x0009)");
335     case 0x000A:
336       return NS_LITERAL_CSTRING("LINE FEED (0x000A)");
337     case 0x000B:
338       return NS_LITERAL_CSTRING("LINE TABULATION (0x000B)");
339     case 0x000C:
340       return NS_LITERAL_CSTRING("FORM FEED (0x000C)");
341     case 0x000D:
342       return NS_LITERAL_CSTRING("CARRIAGE RETURN (0x000D)");
343     case 0x0018:
344       return NS_LITERAL_CSTRING("CANCEL (0x0018)");
345     case 0x001B:
346       return NS_LITERAL_CSTRING("ESCAPE (0x001B)");
347     case 0x0020:
348       return NS_LITERAL_CSTRING("SPACE (0x0020)");
349     case 0x007F:
350       return NS_LITERAL_CSTRING("DELETE (0x007F)");
351     case 0x00A0:
352       return NS_LITERAL_CSTRING("NO-BREAK SPACE (0x00A0)");
353     case 0x00AD:
354       return NS_LITERAL_CSTRING("SOFT HYPHEN (0x00AD)");
355     case 0x2000:
356       return NS_LITERAL_CSTRING("EN QUAD (0x2000)");
357     case 0x2001:
358       return NS_LITERAL_CSTRING("EM QUAD (0x2001)");
359     case 0x2002:
360       return NS_LITERAL_CSTRING("EN SPACE (0x2002)");
361     case 0x2003:
362       return NS_LITERAL_CSTRING("EM SPACE (0x2003)");
363     case 0x2004:
364       return NS_LITERAL_CSTRING("THREE-PER-EM SPACE (0x2004)");
365     case 0x2005:
366       return NS_LITERAL_CSTRING("FOUR-PER-EM SPACE (0x2005)");
367     case 0x2006:
368       return NS_LITERAL_CSTRING("SIX-PER-EM SPACE (0x2006)");
369     case 0x2007:
370       return NS_LITERAL_CSTRING("FIGURE SPACE (0x2007)");
371     case 0x2008:
372       return NS_LITERAL_CSTRING("PUNCTUATION SPACE (0x2008)");
373     case 0x2009:
374       return NS_LITERAL_CSTRING("THIN SPACE (0x2009)");
375     case 0x200A:
376       return NS_LITERAL_CSTRING("HAIR SPACE (0x200A)");
377     case 0x200B:
378       return NS_LITERAL_CSTRING("ZERO WIDTH SPACE (0x200B)");
379     case 0x200C:
380       return NS_LITERAL_CSTRING("ZERO WIDTH NON-JOINER (0x200C)");
381     case 0x200D:
382       return NS_LITERAL_CSTRING("ZERO WIDTH JOINER (0x200D)");
383     case 0x200E:
384       return NS_LITERAL_CSTRING("LEFT-TO-RIGHT MARK (0x200E)");
385     case 0x200F:
386       return NS_LITERAL_CSTRING("RIGHT-TO-LEFT MARK (0x200F)");
387     case 0x2029:
388       return NS_LITERAL_CSTRING("PARAGRAPH SEPARATOR (0x2029)");
389     case 0x202A:
390       return NS_LITERAL_CSTRING("LEFT-TO-RIGHT EMBEDDING (0x202A)");
391     case 0x202B:
392       return NS_LITERAL_CSTRING("RIGHT-TO-LEFT EMBEDDING (0x202B)");
393     case 0x202D:
394       return NS_LITERAL_CSTRING("LEFT-TO-RIGHT OVERRIDE (0x202D)");
395     case 0x202E:
396       return NS_LITERAL_CSTRING("RIGHT-TO-LEFT OVERRIDE (0x202E)");
397     case 0x202F:
398       return NS_LITERAL_CSTRING("NARROW NO-BREAK SPACE (0x202F)");
399     case 0x205F:
400       return NS_LITERAL_CSTRING("MEDIUM MATHEMATICAL SPACE (0x205F)");
401     case 0x2060:
402       return NS_LITERAL_CSTRING("WORD JOINER (0x2060)");
403     case 0x2066:
404       return NS_LITERAL_CSTRING("LEFT-TO-RIGHT ISOLATE (0x2066)");
405     case 0x2067:
406       return NS_LITERAL_CSTRING("RIGHT-TO-LEFT ISOLATE (0x2067)");
407     case 0x3000:
408       return NS_LITERAL_CSTRING("IDEOGRAPHIC SPACE (0x3000)");
409     case 0xFEFF:
410       return NS_LITERAL_CSTRING("ZERO WIDTH NO-BREAK SPACE (0xFEFF)");
411     default: {
412       if (aCharCode < ' ' || (aCharCode >= 0x80 && aCharCode < 0xA0)) {
413         return nsPrintfCString("control (0x%04X)", aCharCode);
414       }
415       if (NS_IS_HIGH_SURROGATE(aCharCode)) {
416         return nsPrintfCString("high surrogate (0x%04X)", aCharCode);
417       }
418       if (NS_IS_LOW_SURROGATE(aCharCode)) {
419         return nsPrintfCString("low surrogate (0x%04X)", aCharCode);
420       }
421       return IS_IN_BMP(aCharCode)
422                  ? nsPrintfCString(
423                        "'%s' (0x%04X)",
424                        NS_ConvertUTF16toUTF8(nsAutoString(aCharCode)).get(),
425                        aCharCode)
426                  : nsPrintfCString(
427                        "'%s' (0x%08X)",
428                        NS_ConvertUTF16toUTF8(nsAutoString(aCharCode)).get(),
429                        aCharCode);
430     }
431   }
432 }
433 
GetKeyLocationName(uint32_t aLocation)434 static const nsCString GetKeyLocationName(uint32_t aLocation) {
435   switch (aLocation) {
436     case eKeyLocationLeft:
437       return NS_LITERAL_CSTRING("KEY_LOCATION_LEFT");
438     case eKeyLocationRight:
439       return NS_LITERAL_CSTRING("KEY_LOCATION_RIGHT");
440     case eKeyLocationStandard:
441       return NS_LITERAL_CSTRING("KEY_LOCATION_STANDARD");
442     case eKeyLocationNumpad:
443       return NS_LITERAL_CSTRING("KEY_LOCATION_NUMPAD");
444     default:
445       return nsPrintfCString("Unknown (0x%04X)", aLocation);
446   }
447 }
448 
GetCharacterCodeName(char16_t * aChars,uint32_t aLength)449 static const nsCString GetCharacterCodeName(char16_t* aChars,
450                                             uint32_t aLength) {
451   if (!aLength) {
452     return NS_LITERAL_CSTRING("");
453   }
454   nsAutoCString result;
455   for (uint32_t i = 0; i < aLength; ++i) {
456     if (!result.IsEmpty()) {
457       result.AppendLiteral(", ");
458     } else {
459       result.AssignLiteral("\"");
460     }
461     result.Append(GetCharacterCodeName(aChars[i]));
462   }
463   result.AppendLiteral("\"");
464   return result;
465 }
466 
467 class MOZ_STACK_CLASS GetShiftStateName final : public nsAutoCString {
468  public:
GetShiftStateName(VirtualKey::ShiftState aShiftState)469   explicit GetShiftStateName(VirtualKey::ShiftState aShiftState) {
470     if (!aShiftState) {
471       AssignLiteral("none");
472       return;
473     }
474     if (aShiftState & VirtualKey::STATE_SHIFT) {
475       AssignLiteral("Shift");
476       aShiftState &= ~VirtualKey::STATE_SHIFT;
477     }
478     if (aShiftState & VirtualKey::STATE_CONTROL) {
479       MaybeAppendSeparator();
480       AssignLiteral("Ctrl");
481       aShiftState &= ~VirtualKey::STATE_CONTROL;
482     }
483     if (aShiftState & VirtualKey::STATE_ALT) {
484       MaybeAppendSeparator();
485       AssignLiteral("Alt");
486       aShiftState &= ~VirtualKey::STATE_ALT;
487     }
488     if (aShiftState & VirtualKey::STATE_CAPSLOCK) {
489       MaybeAppendSeparator();
490       AssignLiteral("CapsLock");
491       aShiftState &= ~VirtualKey::STATE_CAPSLOCK;
492     }
493     MOZ_ASSERT(!aShiftState);
494   }
495 
496  private:
MaybeAppendSeparator()497   void MaybeAppendSeparator() {
498     if (!IsEmpty()) {
499       AppendLiteral(" | ");
500     }
501   }
502 };
503 
GetMessageName(UINT aMessage)504 static const nsCString GetMessageName(UINT aMessage) {
505   switch (aMessage) {
506     case WM_NULL:
507       return NS_LITERAL_CSTRING("WM_NULL");
508     case WM_KEYDOWN:
509       return NS_LITERAL_CSTRING("WM_KEYDOWN");
510     case WM_KEYUP:
511       return NS_LITERAL_CSTRING("WM_KEYUP");
512     case WM_SYSKEYDOWN:
513       return NS_LITERAL_CSTRING("WM_SYSKEYDOWN");
514     case WM_SYSKEYUP:
515       return NS_LITERAL_CSTRING("WM_SYSKEYUP");
516     case WM_CHAR:
517       return NS_LITERAL_CSTRING("WM_CHAR");
518     case WM_UNICHAR:
519       return NS_LITERAL_CSTRING("WM_UNICHAR");
520     case WM_SYSCHAR:
521       return NS_LITERAL_CSTRING("WM_SYSCHAR");
522     case WM_DEADCHAR:
523       return NS_LITERAL_CSTRING("WM_DEADCHAR");
524     case WM_SYSDEADCHAR:
525       return NS_LITERAL_CSTRING("WM_SYSDEADCHAR");
526     case MOZ_WM_KEYDOWN:
527       return NS_LITERAL_CSTRING("MOZ_WM_KEYDOWN");
528     case MOZ_WM_KEYUP:
529       return NS_LITERAL_CSTRING("MOZ_WM_KEYUP");
530     case WM_APPCOMMAND:
531       return NS_LITERAL_CSTRING("WM_APPCOMMAND");
532     case WM_QUIT:
533       return NS_LITERAL_CSTRING("WM_QUIT");
534     default:
535       return nsPrintfCString("Unknown Message (0x%04X)", aMessage);
536   }
537 }
538 
GetVirtualKeyCodeName(WPARAM aVK)539 static const nsCString GetVirtualKeyCodeName(WPARAM aVK) {
540   if (aVK >= ArrayLength(kVirtualKeyName)) {
541     return nsPrintfCString("Invalid (0x%08X)", aVK);
542   }
543   return nsCString(kVirtualKeyName[aVK]);
544 }
545 
GetAppCommandName(WPARAM aCommand)546 static const nsCString GetAppCommandName(WPARAM aCommand) {
547   switch (aCommand) {
548     case APPCOMMAND_BASS_BOOST:
549       return NS_LITERAL_CSTRING("APPCOMMAND_BASS_BOOST");
550     case APPCOMMAND_BASS_DOWN:
551       return NS_LITERAL_CSTRING("APPCOMMAND_BASS_DOWN");
552     case APPCOMMAND_BASS_UP:
553       return NS_LITERAL_CSTRING("APPCOMMAND_BASS_UP");
554     case APPCOMMAND_BROWSER_BACKWARD:
555       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_BACKWARD");
556     case APPCOMMAND_BROWSER_FAVORITES:
557       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_FAVORITES");
558     case APPCOMMAND_BROWSER_FORWARD:
559       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_FORWARD");
560     case APPCOMMAND_BROWSER_HOME:
561       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_HOME");
562     case APPCOMMAND_BROWSER_REFRESH:
563       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_REFRESH");
564     case APPCOMMAND_BROWSER_SEARCH:
565       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_SEARCH");
566     case APPCOMMAND_BROWSER_STOP:
567       return NS_LITERAL_CSTRING("APPCOMMAND_BROWSER_STOP");
568     case APPCOMMAND_CLOSE:
569       return NS_LITERAL_CSTRING("APPCOMMAND_CLOSE");
570     case APPCOMMAND_COPY:
571       return NS_LITERAL_CSTRING("APPCOMMAND_COPY");
572     case APPCOMMAND_CORRECTION_LIST:
573       return NS_LITERAL_CSTRING("APPCOMMAND_CORRECTION_LIST");
574     case APPCOMMAND_CUT:
575       return NS_LITERAL_CSTRING("APPCOMMAND_CUT");
576     case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
577       return NS_LITERAL_CSTRING("APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE");
578     case APPCOMMAND_FIND:
579       return NS_LITERAL_CSTRING("APPCOMMAND_FIND");
580     case APPCOMMAND_FORWARD_MAIL:
581       return NS_LITERAL_CSTRING("APPCOMMAND_FORWARD_MAIL");
582     case APPCOMMAND_HELP:
583       return NS_LITERAL_CSTRING("APPCOMMAND_HELP");
584     case APPCOMMAND_LAUNCH_APP1:
585       return NS_LITERAL_CSTRING("APPCOMMAND_LAUNCH_APP1");
586     case APPCOMMAND_LAUNCH_APP2:
587       return NS_LITERAL_CSTRING("APPCOMMAND_LAUNCH_APP2");
588     case APPCOMMAND_LAUNCH_MAIL:
589       return NS_LITERAL_CSTRING("APPCOMMAND_LAUNCH_MAIL");
590     case APPCOMMAND_LAUNCH_MEDIA_SELECT:
591       return NS_LITERAL_CSTRING("APPCOMMAND_LAUNCH_MEDIA_SELECT");
592     case APPCOMMAND_MEDIA_CHANNEL_DOWN:
593       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_CHANNEL_DOWN");
594     case APPCOMMAND_MEDIA_CHANNEL_UP:
595       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_CHANNEL_UP");
596     case APPCOMMAND_MEDIA_FAST_FORWARD:
597       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_FAST_FORWARD");
598     case APPCOMMAND_MEDIA_NEXTTRACK:
599       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_NEXTTRACK");
600     case APPCOMMAND_MEDIA_PAUSE:
601       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_PAUSE");
602     case APPCOMMAND_MEDIA_PLAY:
603       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_PLAY");
604     case APPCOMMAND_MEDIA_PLAY_PAUSE:
605       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_PLAY_PAUSE");
606     case APPCOMMAND_MEDIA_PREVIOUSTRACK:
607       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_PREVIOUSTRACK");
608     case APPCOMMAND_MEDIA_RECORD:
609       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_RECORD");
610     case APPCOMMAND_MEDIA_REWIND:
611       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_REWIND");
612     case APPCOMMAND_MEDIA_STOP:
613       return NS_LITERAL_CSTRING("APPCOMMAND_MEDIA_STOP");
614     case APPCOMMAND_MIC_ON_OFF_TOGGLE:
615       return NS_LITERAL_CSTRING("APPCOMMAND_MIC_ON_OFF_TOGGLE");
616     case APPCOMMAND_MICROPHONE_VOLUME_DOWN:
617       return NS_LITERAL_CSTRING("APPCOMMAND_MICROPHONE_VOLUME_DOWN");
618     case APPCOMMAND_MICROPHONE_VOLUME_MUTE:
619       return NS_LITERAL_CSTRING("APPCOMMAND_MICROPHONE_VOLUME_MUTE");
620     case APPCOMMAND_MICROPHONE_VOLUME_UP:
621       return NS_LITERAL_CSTRING("APPCOMMAND_MICROPHONE_VOLUME_UP");
622     case APPCOMMAND_NEW:
623       return NS_LITERAL_CSTRING("APPCOMMAND_NEW");
624     case APPCOMMAND_OPEN:
625       return NS_LITERAL_CSTRING("APPCOMMAND_OPEN");
626     case APPCOMMAND_PASTE:
627       return NS_LITERAL_CSTRING("APPCOMMAND_PASTE");
628     case APPCOMMAND_PRINT:
629       return NS_LITERAL_CSTRING("APPCOMMAND_PRINT");
630     case APPCOMMAND_REDO:
631       return NS_LITERAL_CSTRING("APPCOMMAND_REDO");
632     case APPCOMMAND_REPLY_TO_MAIL:
633       return NS_LITERAL_CSTRING("APPCOMMAND_REPLY_TO_MAIL");
634     case APPCOMMAND_SAVE:
635       return NS_LITERAL_CSTRING("APPCOMMAND_SAVE");
636     case APPCOMMAND_SEND_MAIL:
637       return NS_LITERAL_CSTRING("APPCOMMAND_SEND_MAIL");
638     case APPCOMMAND_SPELL_CHECK:
639       return NS_LITERAL_CSTRING("APPCOMMAND_SPELL_CHECK");
640     case APPCOMMAND_TREBLE_DOWN:
641       return NS_LITERAL_CSTRING("APPCOMMAND_TREBLE_DOWN");
642     case APPCOMMAND_TREBLE_UP:
643       return NS_LITERAL_CSTRING("APPCOMMAND_TREBLE_UP");
644     case APPCOMMAND_UNDO:
645       return NS_LITERAL_CSTRING("APPCOMMAND_UNDO");
646     case APPCOMMAND_VOLUME_DOWN:
647       return NS_LITERAL_CSTRING("APPCOMMAND_VOLUME_DOWN");
648     case APPCOMMAND_VOLUME_MUTE:
649       return NS_LITERAL_CSTRING("APPCOMMAND_VOLUME_MUTE");
650     case APPCOMMAND_VOLUME_UP:
651       return NS_LITERAL_CSTRING("APPCOMMAND_VOLUME_UP");
652     default:
653       return nsPrintfCString("Unknown app command (0x%08X)", aCommand);
654   }
655 }
656 
GetAppCommandDeviceName(LPARAM aDevice)657 static const nsCString GetAppCommandDeviceName(LPARAM aDevice) {
658   switch (aDevice) {
659     case FAPPCOMMAND_KEY:
660       return NS_LITERAL_CSTRING("FAPPCOMMAND_KEY");
661     case FAPPCOMMAND_MOUSE:
662       return NS_LITERAL_CSTRING("FAPPCOMMAND_MOUSE");
663     case FAPPCOMMAND_OEM:
664       return NS_LITERAL_CSTRING("FAPPCOMMAND_OEM");
665     default:
666       return nsPrintfCString("Unknown app command device (0x%04X)", aDevice);
667   }
668 };
669 
670 class MOZ_STACK_CLASS GetAppCommandKeysName final : public nsAutoCString {
671  public:
GetAppCommandKeysName(WPARAM aKeys)672   explicit GetAppCommandKeysName(WPARAM aKeys) {
673     if (aKeys & MK_CONTROL) {
674       AppendLiteral("MK_CONTROL");
675       aKeys &= ~MK_CONTROL;
676     }
677     if (aKeys & MK_LBUTTON) {
678       MaybeAppendSeparator();
679       AppendLiteral("MK_LBUTTON");
680       aKeys &= ~MK_LBUTTON;
681     }
682     if (aKeys & MK_MBUTTON) {
683       MaybeAppendSeparator();
684       AppendLiteral("MK_MBUTTON");
685       aKeys &= ~MK_MBUTTON;
686     }
687     if (aKeys & MK_RBUTTON) {
688       MaybeAppendSeparator();
689       AppendLiteral("MK_RBUTTON");
690       aKeys &= ~MK_RBUTTON;
691     }
692     if (aKeys & MK_SHIFT) {
693       MaybeAppendSeparator();
694       AppendLiteral("MK_SHIFT");
695       aKeys &= ~MK_SHIFT;
696     }
697     if (aKeys & MK_XBUTTON1) {
698       MaybeAppendSeparator();
699       AppendLiteral("MK_XBUTTON1");
700       aKeys &= ~MK_XBUTTON1;
701     }
702     if (aKeys & MK_XBUTTON2) {
703       MaybeAppendSeparator();
704       AppendLiteral("MK_XBUTTON2");
705       aKeys &= ~MK_XBUTTON2;
706     }
707     if (aKeys) {
708       MaybeAppendSeparator();
709       AppendPrintf("Unknown Flags (0x%04X)", aKeys);
710     }
711     if (IsEmpty()) {
712       AssignLiteral("none (0x0000)");
713     }
714   }
715 
716  private:
MaybeAppendSeparator()717   void MaybeAppendSeparator() {
718     if (!IsEmpty()) {
719       AppendLiteral(" | ");
720     }
721   }
722 };
723 
ToString(const MSG & aMSG)724 static const nsCString ToString(const MSG& aMSG) {
725   nsAutoCString result;
726   result.AssignLiteral("{ message=");
727   result.Append(GetMessageName(aMSG.message).get());
728   result.AppendLiteral(", ");
729   switch (aMSG.message) {
730     case WM_KEYDOWN:
731     case WM_KEYUP:
732     case WM_SYSKEYDOWN:
733     case WM_SYSKEYUP:
734     case MOZ_WM_KEYDOWN:
735     case MOZ_WM_KEYUP:
736       result.AppendPrintf(
737           "virtual keycode=%s, repeat count=%d, "
738           "scancode=0x%02X, extended key=%s, "
739           "context code=%s, previous key state=%s, "
740           "transition state=%s",
741           GetVirtualKeyCodeName(aMSG.wParam).get(), aMSG.lParam & 0xFFFF,
742           WinUtils::GetScanCode(aMSG.lParam),
743           GetBoolName(WinUtils::IsExtendedScanCode(aMSG.lParam)),
744           GetBoolName((aMSG.lParam & (1 << 29)) != 0),
745           GetBoolName((aMSG.lParam & (1 << 30)) != 0),
746           GetBoolName((aMSG.lParam & (1 << 31)) != 0));
747       break;
748     case WM_CHAR:
749     case WM_DEADCHAR:
750     case WM_SYSCHAR:
751     case WM_SYSDEADCHAR:
752       result.AppendPrintf(
753           "character code=%s, repeat count=%d, "
754           "scancode=0x%02X, extended key=%s, "
755           "context code=%s, previous key state=%s, "
756           "transition state=%s",
757           GetCharacterCodeName(aMSG.wParam).get(), aMSG.lParam & 0xFFFF,
758           WinUtils::GetScanCode(aMSG.lParam),
759           GetBoolName(WinUtils::IsExtendedScanCode(aMSG.lParam)),
760           GetBoolName((aMSG.lParam & (1 << 29)) != 0),
761           GetBoolName((aMSG.lParam & (1 << 30)) != 0),
762           GetBoolName((aMSG.lParam & (1 << 31)) != 0));
763       break;
764     case WM_APPCOMMAND:
765       result.AppendPrintf(
766           "window handle=0x%p, app command=%s, device=%s, dwKeys=%s",
767           aMSG.wParam,
768           GetAppCommandName(GET_APPCOMMAND_LPARAM(aMSG.lParam)).get(),
769           GetAppCommandDeviceName(GET_DEVICE_LPARAM(aMSG.lParam)).get(),
770           GetAppCommandKeysName(GET_KEYSTATE_LPARAM(aMSG.lParam)).get());
771       break;
772     default:
773       result.AppendPrintf("wParam=%u, lParam=%u", aMSG.wParam, aMSG.lParam);
774       break;
775   }
776   result.AppendPrintf(", hwnd=0x%p", aMSG.hwnd);
777   return result;
778 }
779 
ToString(const UniCharsAndModifiers & aUniCharsAndModifiers)780 static const nsCString ToString(
781     const UniCharsAndModifiers& aUniCharsAndModifiers) {
782   if (aUniCharsAndModifiers.IsEmpty()) {
783     return NS_LITERAL_CSTRING("{}");
784   }
785   nsAutoCString result;
786   result.AssignLiteral("{ ");
787   result.Append(GetCharacterCodeName(aUniCharsAndModifiers.CharAt(0)));
788   for (size_t i = 1; i < aUniCharsAndModifiers.Length(); ++i) {
789     if (aUniCharsAndModifiers.ModifiersAt(i - 1) !=
790         aUniCharsAndModifiers.ModifiersAt(i)) {
791       result.AppendLiteral(" [");
792       result.Append(GetModifiersName(aUniCharsAndModifiers.ModifiersAt(0)));
793       result.AppendLiteral("]");
794     }
795     result.AppendLiteral(", ");
796     result.Append(GetCharacterCodeName(aUniCharsAndModifiers.CharAt(i)));
797   }
798   result.AppendLiteral(" [");
799   uint32_t lastIndex = aUniCharsAndModifiers.Length() - 1;
800   result.Append(GetModifiersName(aUniCharsAndModifiers.ModifiersAt(lastIndex)));
801   result.AppendLiteral("] }");
802   return result;
803 }
804 
ToString(const ModifierKeyState & aModifierKeyState)805 const nsCString ToString(const ModifierKeyState& aModifierKeyState) {
806   nsAutoCString result;
807   result.AssignLiteral("{ ");
808   result.Append(GetModifiersName(aModifierKeyState.GetModifiers()).get());
809   result.AppendLiteral(" }");
810   return result;
811 }
812 
813 // Unique id counter associated with a keydown / keypress events. Used in
814 // identifing keypress events for removal from async event dispatch queue
815 // in metrofx after preventDefault is called on keydown events.
816 static uint32_t sUniqueKeyEventId = 0;
817 
818 /*****************************************************************************
819  * mozilla::widget::ModifierKeyState
820  *****************************************************************************/
821 
ModifierKeyState()822 ModifierKeyState::ModifierKeyState() { Update(); }
823 
ModifierKeyState(bool aIsShiftDown,bool aIsControlDown,bool aIsAltDown)824 ModifierKeyState::ModifierKeyState(bool aIsShiftDown, bool aIsControlDown,
825                                    bool aIsAltDown) {
826   Update();
827   Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_ALTGRAPH);
828   Modifiers modifiers = 0;
829   if (aIsShiftDown) {
830     modifiers |= MODIFIER_SHIFT;
831   }
832   if (aIsControlDown) {
833     modifiers |= MODIFIER_CONTROL;
834   }
835   if (aIsAltDown) {
836     modifiers |= MODIFIER_ALT;
837   }
838   if (modifiers) {
839     Set(modifiers);
840   }
841 }
842 
ModifierKeyState(Modifiers aModifiers)843 ModifierKeyState::ModifierKeyState(Modifiers aModifiers)
844     : mModifiers(aModifiers) {
845   EnsureAltGr();
846 }
847 
Update()848 void ModifierKeyState::Update() {
849   mModifiers = 0;
850   if (IS_VK_DOWN(VK_SHIFT)) {
851     mModifiers |= MODIFIER_SHIFT;
852   }
853   if (IS_VK_DOWN(VK_CONTROL)) {
854     mModifiers |= MODIFIER_CONTROL;
855   }
856   if (IS_VK_DOWN(VK_MENU)) {
857     mModifiers |= MODIFIER_ALT;
858   }
859   if (IS_VK_DOWN(VK_LWIN) || IS_VK_DOWN(VK_RWIN)) {
860     mModifiers |= MODIFIER_OS;
861   }
862   if (::GetKeyState(VK_CAPITAL) & 1) {
863     mModifiers |= MODIFIER_CAPSLOCK;
864   }
865   if (::GetKeyState(VK_NUMLOCK) & 1) {
866     mModifiers |= MODIFIER_NUMLOCK;
867   }
868   if (::GetKeyState(VK_SCROLL) & 1) {
869     mModifiers |= MODIFIER_SCROLLLOCK;
870   }
871 
872   EnsureAltGr();
873 }
874 
Unset(Modifiers aRemovingModifiers)875 void ModifierKeyState::Unset(Modifiers aRemovingModifiers) {
876   mModifiers &= ~aRemovingModifiers;
877   // Note that we don't need to unset AltGr flag here automatically.
878   // For EditorBase, we need to remove Alt and Control flags but AltGr isn't
879   // checked in EditorBase, so, it can be kept.
880 }
881 
Set(Modifiers aAddingModifiers)882 void ModifierKeyState::Set(Modifiers aAddingModifiers) {
883   mModifiers |= aAddingModifiers;
884   EnsureAltGr();
885 }
886 
InitInputEvent(WidgetInputEvent & aInputEvent) const887 void ModifierKeyState::InitInputEvent(WidgetInputEvent& aInputEvent) const {
888   aInputEvent.mModifiers = mModifiers;
889 
890   switch (aInputEvent.mClass) {
891     case eMouseEventClass:
892     case eMouseScrollEventClass:
893     case eWheelEventClass:
894     case eDragEventClass:
895     case eSimpleGestureEventClass:
896       InitMouseEvent(aInputEvent);
897       break;
898     default:
899       break;
900   }
901 }
902 
InitMouseEvent(WidgetInputEvent & aMouseEvent) const903 void ModifierKeyState::InitMouseEvent(WidgetInputEvent& aMouseEvent) const {
904   NS_ASSERTION(aMouseEvent.mClass == eMouseEventClass ||
905                    aMouseEvent.mClass == eWheelEventClass ||
906                    aMouseEvent.mClass == eDragEventClass ||
907                    aMouseEvent.mClass == eSimpleGestureEventClass,
908                "called with non-mouse event");
909 
910   WidgetMouseEventBase& mouseEvent = *aMouseEvent.AsMouseEventBase();
911   mouseEvent.buttons = 0;
912   if (::GetKeyState(VK_LBUTTON) < 0) {
913     mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag;
914   }
915   if (::GetKeyState(VK_RBUTTON) < 0) {
916     mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag;
917   }
918   if (::GetKeyState(VK_MBUTTON) < 0) {
919     mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag;
920   }
921   if (::GetKeyState(VK_XBUTTON1) < 0) {
922     mouseEvent.buttons |= WidgetMouseEvent::e4thButtonFlag;
923   }
924   if (::GetKeyState(VK_XBUTTON2) < 0) {
925     mouseEvent.buttons |= WidgetMouseEvent::e5thButtonFlag;
926   }
927 }
928 
IsShift() const929 bool ModifierKeyState::IsShift() const {
930   return (mModifiers & MODIFIER_SHIFT) != 0;
931 }
932 
IsControl() const933 bool ModifierKeyState::IsControl() const {
934   return (mModifiers & MODIFIER_CONTROL) != 0;
935 }
936 
IsAlt() const937 bool ModifierKeyState::IsAlt() const {
938   return (mModifiers & MODIFIER_ALT) != 0;
939 }
940 
IsAltGr() const941 bool ModifierKeyState::IsAltGr() const { return IsControl() && IsAlt(); }
942 
IsWin() const943 bool ModifierKeyState::IsWin() const { return (mModifiers & MODIFIER_OS) != 0; }
944 
MaybeMatchShortcutKey() const945 bool ModifierKeyState::MaybeMatchShortcutKey() const {
946   // If Windows key is pressed, even if both Ctrl key and Alt key are pressed,
947   // it's possible to match a shortcut key.
948   if (IsWin()) {
949     return true;
950   }
951   // Otherwise, when both Ctrl key and Alt key are pressed, it shouldn't be
952   // a shortcut key for Windows since it means pressing AltGr key on
953   // some keyboard layouts.
954   if (IsControl() ^ IsAlt()) {
955     return true;
956   }
957   // If no modifier key is active except a lockable modifier nor Shift key,
958   // the key shouldn't match any shortcut keys (there are Space and
959   // Shift+Space, though, let's ignore these special case...).
960   return false;
961 }
962 
IsCapsLocked() const963 bool ModifierKeyState::IsCapsLocked() const {
964   return (mModifiers & MODIFIER_CAPSLOCK) != 0;
965 }
966 
IsNumLocked() const967 bool ModifierKeyState::IsNumLocked() const {
968   return (mModifiers & MODIFIER_NUMLOCK) != 0;
969 }
970 
IsScrollLocked() const971 bool ModifierKeyState::IsScrollLocked() const {
972   return (mModifiers & MODIFIER_SCROLLLOCK) != 0;
973 }
974 
EnsureAltGr()975 void ModifierKeyState::EnsureAltGr() {
976   // If both Control key and Alt key are pressed, it means AltGr is pressed.
977   // Ideally, we should check whether the current keyboard layout has AltGr
978   // or not.  However, setting AltGr flags for keyboard which doesn't have
979   // AltGr must not be serious bug.  So, it should be OK for now.
980   if (IsAltGr()) {
981     mModifiers |= MODIFIER_ALTGRAPH;
982   }
983 }
984 
985 /*****************************************************************************
986  * mozilla::widget::UniCharsAndModifiers
987  *****************************************************************************/
988 
Append(char16_t aUniChar,Modifiers aModifiers)989 void UniCharsAndModifiers::Append(char16_t aUniChar, Modifiers aModifiers) {
990   mChars.Append(aUniChar);
991   mModifiers.AppendElement(aModifiers);
992 }
993 
FillModifiers(Modifiers aModifiers)994 void UniCharsAndModifiers::FillModifiers(Modifiers aModifiers) {
995   for (size_t i = 0; i < Length(); i++) {
996     mModifiers[i] = aModifiers;
997   }
998 }
999 
OverwriteModifiersIfBeginsWith(const UniCharsAndModifiers & aOther)1000 void UniCharsAndModifiers::OverwriteModifiersIfBeginsWith(
1001     const UniCharsAndModifiers& aOther) {
1002   if (!BeginsWith(aOther)) {
1003     return;
1004   }
1005   for (size_t i = 0; i < aOther.Length(); ++i) {
1006     mModifiers[i] = aOther.mModifiers[i];
1007   }
1008 }
1009 
UniCharsEqual(const UniCharsAndModifiers & aOther) const1010 bool UniCharsAndModifiers::UniCharsEqual(
1011     const UniCharsAndModifiers& aOther) const {
1012   return mChars.Equals(aOther.mChars);
1013 }
1014 
UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers & aOther) const1015 bool UniCharsAndModifiers::UniCharsCaseInsensitiveEqual(
1016     const UniCharsAndModifiers& aOther) const {
1017   nsCaseInsensitiveStringComparator comp;
1018   return mChars.Equals(aOther.mChars, comp);
1019 }
1020 
BeginsWith(const UniCharsAndModifiers & aOther) const1021 bool UniCharsAndModifiers::BeginsWith(
1022     const UniCharsAndModifiers& aOther) const {
1023   return StringBeginsWith(mChars, aOther.mChars);
1024 }
1025 
operator +=(const UniCharsAndModifiers & aOther)1026 UniCharsAndModifiers& UniCharsAndModifiers::operator+=(
1027     const UniCharsAndModifiers& aOther) {
1028   mChars.Append(aOther.mChars);
1029   mModifiers.AppendElements(aOther.mModifiers);
1030   return *this;
1031 }
1032 
operator +(const UniCharsAndModifiers & aOther) const1033 UniCharsAndModifiers UniCharsAndModifiers::operator+(
1034     const UniCharsAndModifiers& aOther) const {
1035   UniCharsAndModifiers result(*this);
1036   result += aOther;
1037   return result;
1038 }
1039 
1040 /*****************************************************************************
1041  * mozilla::widget::VirtualKey
1042  *****************************************************************************/
1043 
1044 // static
ModifiersToShiftState(Modifiers aModifiers)1045 VirtualKey::ShiftState VirtualKey::ModifiersToShiftState(Modifiers aModifiers) {
1046   ShiftState state = 0;
1047   if (aModifiers & MODIFIER_SHIFT) {
1048     state |= STATE_SHIFT;
1049   }
1050   if (aModifiers & MODIFIER_CONTROL) {
1051     state |= STATE_CONTROL;
1052   }
1053   if (aModifiers & MODIFIER_ALT) {
1054     state |= STATE_ALT;
1055   }
1056   if (aModifiers & MODIFIER_CAPSLOCK) {
1057     state |= STATE_CAPSLOCK;
1058   }
1059   return state;
1060 }
1061 
1062 // static
ShiftStateToModifiers(ShiftState aShiftState)1063 Modifiers VirtualKey::ShiftStateToModifiers(ShiftState aShiftState) {
1064   Modifiers modifiers = 0;
1065   if (aShiftState & STATE_SHIFT) {
1066     modifiers |= MODIFIER_SHIFT;
1067   }
1068   if (aShiftState & STATE_CONTROL) {
1069     modifiers |= MODIFIER_CONTROL;
1070   }
1071   if (aShiftState & STATE_ALT) {
1072     modifiers |= MODIFIER_ALT;
1073   }
1074   if (aShiftState & STATE_CAPSLOCK) {
1075     modifiers |= MODIFIER_CAPSLOCK;
1076   }
1077   if ((modifiers & (MODIFIER_ALT | MODIFIER_CONTROL)) ==
1078       (MODIFIER_ALT | MODIFIER_CONTROL)) {
1079     modifiers |= MODIFIER_ALTGRAPH;
1080   }
1081   return modifiers;
1082 }
1083 
MatchingDeadKeyTable(const DeadKeyEntry * aDeadKeyArray,uint32_t aEntries) const1084 const DeadKeyTable* VirtualKey::MatchingDeadKeyTable(
1085     const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const {
1086   if (!mIsDeadKey) {
1087     return nullptr;
1088   }
1089 
1090   for (ShiftState shiftState = 0; shiftState < 16; shiftState++) {
1091     if (!IsDeadKey(shiftState)) {
1092       continue;
1093     }
1094     const DeadKeyTable* dkt = mShiftStates[shiftState].DeadKey.Table;
1095     if (dkt && dkt->IsEqual(aDeadKeyArray, aEntries)) {
1096       return dkt;
1097     }
1098   }
1099 
1100   return nullptr;
1101 }
1102 
SetNormalChars(ShiftState aShiftState,const char16_t * aChars,uint32_t aNumOfChars)1103 void VirtualKey::SetNormalChars(ShiftState aShiftState, const char16_t* aChars,
1104                                 uint32_t aNumOfChars) {
1105   NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
1106 
1107   SetDeadKey(aShiftState, false);
1108 
1109   for (uint32_t index = 0; index < aNumOfChars; index++) {
1110     // Ignore legacy non-printable control characters
1111     mShiftStates[aShiftState].Normal.Chars[index] =
1112         (aChars[index] >= 0x20) ? aChars[index] : 0;
1113   }
1114 
1115   uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
1116   for (uint32_t index = aNumOfChars; index < len; index++) {
1117     mShiftStates[aShiftState].Normal.Chars[index] = 0;
1118   }
1119 }
1120 
SetDeadChar(ShiftState aShiftState,char16_t aDeadChar)1121 void VirtualKey::SetDeadChar(ShiftState aShiftState, char16_t aDeadChar) {
1122   NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
1123 
1124   SetDeadKey(aShiftState, true);
1125 
1126   mShiftStates[aShiftState].DeadKey.DeadChar = aDeadChar;
1127   mShiftStates[aShiftState].DeadKey.Table = nullptr;
1128 }
1129 
GetUniChars(ShiftState aShiftState) const1130 UniCharsAndModifiers VirtualKey::GetUniChars(ShiftState aShiftState) const {
1131   UniCharsAndModifiers result = GetNativeUniChars(aShiftState);
1132 
1133   const ShiftState STATE_ALT_CONTROL = (STATE_ALT | STATE_CONTROL);
1134   if (!(aShiftState & STATE_ALT_CONTROL)) {
1135     return result;
1136   }
1137 
1138   if (result.IsEmpty()) {
1139     result = GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
1140     result.FillModifiers(ShiftStateToModifiers(aShiftState));
1141     return result;
1142   }
1143 
1144   if ((aShiftState & STATE_ALT_CONTROL) == STATE_ALT_CONTROL) {
1145     // Even if the shifted chars and the unshifted chars are same, we
1146     // should consume the Alt key state and the Ctrl key state when
1147     // AltGr key is pressed. Because if we don't consume them, the input
1148     // events are ignored on EditorBase. (I.e., Users cannot input the
1149     // characters with this key combination.)
1150     Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
1151     finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
1152     result.FillModifiers(finalModifiers);
1153     return result;
1154   }
1155 
1156   UniCharsAndModifiers unmodifiedReslt =
1157       GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
1158   if (!result.UniCharsEqual(unmodifiedReslt)) {
1159     // Otherwise, we should consume the Alt key state and the Ctrl key state
1160     // only when the shifted chars and unshifted chars are different.
1161     Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
1162     finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
1163     result.FillModifiers(finalModifiers);
1164   }
1165   return result;
1166 }
1167 
GetNativeUniChars(ShiftState aShiftState) const1168 UniCharsAndModifiers VirtualKey::GetNativeUniChars(
1169     ShiftState aShiftState) const {
1170 #ifdef DEBUG
1171   if (aShiftState >= ArrayLength(mShiftStates)) {
1172     nsPrintfCString warning(
1173         "Shift state is out of range: "
1174         "aShiftState=%d, ArrayLength(mShiftState)=%d",
1175         aShiftState, ArrayLength(mShiftStates));
1176     NS_WARNING(warning.get());
1177   }
1178 #endif
1179 
1180   UniCharsAndModifiers result;
1181   Modifiers modifiers = ShiftStateToModifiers(aShiftState);
1182   if (IsDeadKey(aShiftState)) {
1183     result.Append(mShiftStates[aShiftState].DeadKey.DeadChar, modifiers);
1184     return result;
1185   }
1186 
1187   uint32_t index;
1188   uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
1189   for (index = 0; index < len && mShiftStates[aShiftState].Normal.Chars[index];
1190        index++) {
1191     result.Append(mShiftStates[aShiftState].Normal.Chars[index], modifiers);
1192   }
1193   return result;
1194 }
1195 
1196 // static
FillKbdState(PBYTE aKbdState,const ShiftState aShiftState)1197 void VirtualKey::FillKbdState(PBYTE aKbdState, const ShiftState aShiftState) {
1198   NS_ASSERTION(aShiftState < 16, "aShiftState out of range");
1199 
1200   if (aShiftState & STATE_SHIFT) {
1201     aKbdState[VK_SHIFT] |= 0x80;
1202   } else {
1203     aKbdState[VK_SHIFT] &= ~0x80;
1204     aKbdState[VK_LSHIFT] &= ~0x80;
1205     aKbdState[VK_RSHIFT] &= ~0x80;
1206   }
1207 
1208   if (aShiftState & STATE_CONTROL) {
1209     aKbdState[VK_CONTROL] |= 0x80;
1210   } else {
1211     aKbdState[VK_CONTROL] &= ~0x80;
1212     aKbdState[VK_LCONTROL] &= ~0x80;
1213     aKbdState[VK_RCONTROL] &= ~0x80;
1214   }
1215 
1216   if (aShiftState & STATE_ALT) {
1217     aKbdState[VK_MENU] |= 0x80;
1218   } else {
1219     aKbdState[VK_MENU] &= ~0x80;
1220     aKbdState[VK_LMENU] &= ~0x80;
1221     aKbdState[VK_RMENU] &= ~0x80;
1222   }
1223 
1224   if (aShiftState & STATE_CAPSLOCK) {
1225     aKbdState[VK_CAPITAL] |= 0x01;
1226   } else {
1227     aKbdState[VK_CAPITAL] &= ~0x01;
1228   }
1229 }
1230 
1231 /*****************************************************************************
1232  * mozilla::widget::NativeKey
1233  *****************************************************************************/
1234 
1235 uint8_t NativeKey::sDispatchedKeyOfAppCommand = 0;
1236 NativeKey* NativeKey::sLatestInstance = nullptr;
1237 const MSG NativeKey::sEmptyMSG = {};
1238 MSG NativeKey::sLastKeyOrCharMSG = {};
1239 MSG NativeKey::sLastKeyMSG = {};
1240 
1241 LazyLogModule sNativeKeyLogger("NativeKeyWidgets");
1242 
NativeKey(nsWindowBase * aWidget,const MSG & aMessage,const ModifierKeyState & aModKeyState,HKL aOverrideKeyboardLayout,nsTArray<FakeCharMsg> * aFakeCharMsgs)1243 NativeKey::NativeKey(nsWindowBase* aWidget, const MSG& aMessage,
1244                      const ModifierKeyState& aModKeyState,
1245                      HKL aOverrideKeyboardLayout,
1246                      nsTArray<FakeCharMsg>* aFakeCharMsgs)
1247     : mLastInstance(sLatestInstance),
1248       mRemovingMsg(sEmptyMSG),
1249       mReceivedMsg(sEmptyMSG),
1250       mWidget(aWidget),
1251       mDispatcher(aWidget->GetTextEventDispatcher()),
1252       mMsg(aMessage),
1253       mFocusedWndBeforeDispatch(::GetFocus()),
1254       mDOMKeyCode(0),
1255       mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
1256       mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN),
1257       mModKeyState(aModKeyState),
1258       mVirtualKeyCode(0),
1259       mOriginalVirtualKeyCode(0),
1260       mShiftedLatinChar(0),
1261       mUnshiftedLatinChar(0),
1262       mScanCode(0),
1263       mIsExtended(false),
1264       mIsRepeat(false),
1265       mIsDeadKey(false),
1266       mIsPrintableKey(false),
1267       mIsSkippableInRemoteProcess(false),
1268       mCharMessageHasGone(false),
1269       mCanIgnoreModifierStateAtKeyPress(true),
1270       mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ? aFakeCharMsgs
1271                                                              : nullptr) {
1272   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
1273           ("%p NativeKey::NativeKey(aWidget=0x%p { GetWindowHandle()=0x%p }, "
1274            "aMessage=%s, aModKeyState=%s), sLatestInstance=0x%p",
1275            this, aWidget, aWidget->GetWindowHandle(), ToString(aMessage).get(),
1276            ToString(aModKeyState).get(), sLatestInstance));
1277 
1278   MOZ_ASSERT(aWidget);
1279   MOZ_ASSERT(mDispatcher);
1280   sLatestInstance = this;
1281   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
1282   mKeyboardLayout = keyboardLayout->GetLayout();
1283   if (aOverrideKeyboardLayout && mKeyboardLayout != aOverrideKeyboardLayout) {
1284     keyboardLayout->OverrideLayout(aOverrideKeyboardLayout);
1285     mKeyboardLayout = keyboardLayout->GetLayout();
1286     MOZ_ASSERT(mKeyboardLayout == aOverrideKeyboardLayout);
1287     mIsOverridingKeyboardLayout = true;
1288   } else {
1289     mIsOverridingKeyboardLayout = false;
1290     sLastKeyOrCharMSG = aMessage;
1291   }
1292 
1293   if (mMsg.message == WM_APPCOMMAND) {
1294     InitWithAppCommand();
1295   } else {
1296     InitWithKeyOrChar();
1297   }
1298 
1299   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
1300           ("%p   NativeKey::NativeKey(), mKeyboardLayout=0x%08X, "
1301            "mFocusedWndBeforeDispatch=0x%p, mDOMKeyCode=0x%04X, "
1302            "mKeyNameIndex=%s, mCodeNameIndex=%s, mModKeyState=%s, "
1303            "mVirtualKeyCode=%s, mOriginalVirtualKeyCode=%s, "
1304            "mCommittedCharsAndModifiers=%s, mInputtingStringAndModifiers=%s, "
1305            "mShiftedString=%s, mUnshiftedString=%s, mShiftedLatinChar=%s, "
1306            "mUnshiftedLatinChar=%s, mScanCode=0x%04X, mIsExtended=%s, "
1307            "mIsRepeat=%s, mIsDeadKey=%s, mIsPrintableKey=%s, "
1308            "mIsSkippableInRemoteProcess=%s, mCharMessageHasGone=%s, "
1309            "mIsOverridingKeyboardLayout=%s",
1310            this, mKeyboardLayout, mFocusedWndBeforeDispatch,
1311            GetDOMKeyCodeName(mDOMKeyCode).get(), ToString(mKeyNameIndex).get(),
1312            ToString(mCodeNameIndex).get(), ToString(mModKeyState).get(),
1313            GetVirtualKeyCodeName(mVirtualKeyCode).get(),
1314            GetVirtualKeyCodeName(mOriginalVirtualKeyCode).get(),
1315            ToString(mCommittedCharsAndModifiers).get(),
1316            ToString(mInputtingStringAndModifiers).get(),
1317            ToString(mShiftedString).get(), ToString(mUnshiftedString).get(),
1318            GetCharacterCodeName(mShiftedLatinChar).get(),
1319            GetCharacterCodeName(mUnshiftedLatinChar).get(), mScanCode,
1320            GetBoolName(mIsExtended), GetBoolName(mIsRepeat),
1321            GetBoolName(mIsDeadKey), GetBoolName(mIsPrintableKey),
1322            GetBoolName(mIsSkippableInRemoteProcess),
1323            GetBoolName(mCharMessageHasGone),
1324            GetBoolName(mIsOverridingKeyboardLayout)));
1325 }
1326 
InitIsSkippableForKeyOrChar(const MSG & aLastKeyMSG)1327 void NativeKey::InitIsSkippableForKeyOrChar(const MSG& aLastKeyMSG) {
1328   mIsSkippableInRemoteProcess = false;
1329 
1330   if (!mIsRepeat) {
1331     // If the message is not repeated key message, the event should be always
1332     // handled in remote process even if it's too old.
1333     return;
1334   }
1335 
1336   // Keyboard utilities may send us some generated messages and such messages
1337   // may be marked as "repeated", e.g., SendInput() calls with
1338   // KEYEVENTF_UNICODE but without KEYEVENTF_KEYUP.   However, key sequence
1339   // comes from such utilities may be really important.  For example, utilities
1340   // may send WM_KEYDOWN for VK_BACK to remove previous character and send
1341   // WM_KEYDOWN for VK_PACKET to insert a composite character.  Therefore, we
1342   // should check if current message and previous key message are caused by
1343   // same physical key.  If not, the message may be generated by such
1344   // utility.
1345   // XXX With this approach, if VK_BACK messages are generated with known
1346   //     scancode, we cannot distinguish whether coming VK_BACK message is
1347   //     actually repeated by the auto-repeat feature.  Currently, we need
1348   //     this hack only for "SinhalaTamil IME" and fortunately, it generates
1349   //     VK_BACK messages with odd scancode.  So, we don't need to handle
1350   //     VK_BACK specially at least for now.
1351 
1352   if (mCodeNameIndex == CODE_NAME_INDEX_UNKNOWN) {
1353     // If current event is not caused by physical key operation, it may be
1354     // caused by a keyboard utility.  If so, the event shouldn't be ignored by
1355     // TabChild since it want to insert the character, delete a character or
1356     // move caret.
1357     return;
1358   }
1359 
1360   if (mOriginalVirtualKeyCode == VK_PACKET) {
1361     // If the message is VK_PACKET, that means that a keyboard utility
1362     // tries to insert a character.
1363     return;
1364   }
1365 
1366   switch (mMsg.message) {
1367     case WM_KEYDOWN:
1368     case WM_SYSKEYDOWN:
1369     case MOZ_WM_KEYDOWN:
1370     case WM_CHAR:
1371     case WM_SYSCHAR:
1372     case WM_DEADCHAR:
1373     case WM_SYSDEADCHAR:
1374       // However, some keyboard layouts may send some keyboard messages with
1375       // activating the bit.  If we dispatch repeated keyboard events, they
1376       // may be ignored by TabChild due to performance reason.  So, we need
1377       // to check if actually a physical key is repeated by the auto-repeat
1378       // feature.
1379       switch (aLastKeyMSG.message) {
1380         case WM_KEYDOWN:
1381         case WM_SYSKEYDOWN:
1382         case MOZ_WM_KEYDOWN:
1383           if (aLastKeyMSG.wParam == VK_PACKET) {
1384             // If the last message was VK_PACKET, that means that a keyboard
1385             // utility tried to insert a character.  So, current message is
1386             // not repeated key event of the previous event.
1387             return;
1388           }
1389           // Let's check whether current message and previous message are
1390           // caused by same physical key.
1391           mIsSkippableInRemoteProcess =
1392               mScanCode == WinUtils::GetScanCode(aLastKeyMSG.lParam) &&
1393               mIsExtended == WinUtils::IsExtendedScanCode(aLastKeyMSG.lParam);
1394           return;
1395         default:
1396           // If previous message is not a keydown, this must not be generated
1397           // by the auto-repeat feature.
1398           return;
1399       }
1400       return;
1401     case WM_APPCOMMAND:
1402       MOZ_ASSERT_UNREACHABLE(
1403           "WM_APPCOMMAND should be handled in "
1404           "InitWithAppCommand()");
1405       return;
1406     default:
1407       // keyup message shouldn't be repeated by the auto-repeat feature.
1408       return;
1409   }
1410 }
1411 
InitWithKeyOrChar()1412 void NativeKey::InitWithKeyOrChar() {
1413   MSG lastKeyMSG = sLastKeyMSG;
1414   mScanCode = WinUtils::GetScanCode(mMsg.lParam);
1415   mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
1416   switch (mMsg.message) {
1417     case WM_KEYDOWN:
1418     case WM_SYSKEYDOWN:
1419     case WM_KEYUP:
1420     case WM_SYSKEYUP:
1421     case MOZ_WM_KEYDOWN:
1422     case MOZ_WM_KEYUP: {
1423       // Modify sLastKeyMSG now since retrieving following char messages may
1424       // cause sending another key message if odd tool hooks GetMessage(),
1425       // PeekMessage().
1426       sLastKeyMSG = mMsg;
1427       // First, resolve the IME converted virtual keycode to its original
1428       // keycode.
1429       if (mMsg.wParam == VK_PROCESSKEY) {
1430         mOriginalVirtualKeyCode =
1431             static_cast<uint8_t>(::ImmGetVirtualKey(mMsg.hwnd));
1432       } else {
1433         mOriginalVirtualKeyCode = static_cast<uint8_t>(mMsg.wParam);
1434       }
1435 
1436       // If the key message is sent from other application like a11y tools, the
1437       // scancode value might not be set proper value.  Then, probably the value
1438       // is 0.
1439       // NOTE: If the virtual keycode can be caused by both non-extended key
1440       //       and extended key, the API returns the non-extended key's
1441       //       scancode.  E.g., VK_LEFT causes "4" key on numpad.
1442       if (!mScanCode && mOriginalVirtualKeyCode != VK_PACKET) {
1443         uint16_t scanCodeEx = ComputeScanCodeExFromVirtualKeyCode(mMsg.wParam);
1444         if (scanCodeEx) {
1445           mScanCode = static_cast<uint8_t>(scanCodeEx & 0xFF);
1446           uint8_t extended = static_cast<uint8_t>((scanCodeEx & 0xFF00) >> 8);
1447           mIsExtended = (extended == 0xE0) || (extended == 0xE1);
1448         }
1449       }
1450 
1451       // Most keys are not distinguished as left or right keys.
1452       bool isLeftRightDistinguishedKey = false;
1453 
1454       // mOriginalVirtualKeyCode must not distinguish left or right of
1455       // Shift, Control or Alt.
1456       switch (mOriginalVirtualKeyCode) {
1457         case VK_SHIFT:
1458         case VK_CONTROL:
1459         case VK_MENU:
1460           isLeftRightDistinguishedKey = true;
1461           break;
1462         case VK_LSHIFT:
1463         case VK_RSHIFT:
1464           mVirtualKeyCode = mOriginalVirtualKeyCode;
1465           mOriginalVirtualKeyCode = VK_SHIFT;
1466           isLeftRightDistinguishedKey = true;
1467           break;
1468         case VK_LCONTROL:
1469         case VK_RCONTROL:
1470           mVirtualKeyCode = mOriginalVirtualKeyCode;
1471           mOriginalVirtualKeyCode = VK_CONTROL;
1472           isLeftRightDistinguishedKey = true;
1473           break;
1474         case VK_LMENU:
1475         case VK_RMENU:
1476           mVirtualKeyCode = mOriginalVirtualKeyCode;
1477           mOriginalVirtualKeyCode = VK_MENU;
1478           isLeftRightDistinguishedKey = true;
1479           break;
1480       }
1481 
1482       // If virtual keycode (left-right distinguished keycode) is already
1483       // computed, we don't need to do anymore.
1484       if (mVirtualKeyCode) {
1485         break;
1486       }
1487 
1488       // If the keycode doesn't have LR distinguished keycode, we just set
1489       // mOriginalVirtualKeyCode to mVirtualKeyCode.  Note that don't compute
1490       // it from MapVirtualKeyEx() because the scan code might be wrong if
1491       // the message is sent/posted by other application.  Then, we will compute
1492       // unexpected keycode from the scan code.
1493       if (!isLeftRightDistinguishedKey) {
1494         break;
1495       }
1496 
1497       NS_ASSERTION(!mVirtualKeyCode,
1498                    "mVirtualKeyCode has been computed already");
1499 
1500       // Otherwise, compute the virtual keycode with MapVirtualKeyEx().
1501       mVirtualKeyCode = ComputeVirtualKeyCodeFromScanCodeEx();
1502 
1503       // Following code shouldn't be used now because we compute scancode value
1504       // if we detect that the sender doesn't set proper scancode.
1505       // However, the detection might fail. Therefore, let's keep using this.
1506       switch (mOriginalVirtualKeyCode) {
1507         case VK_CONTROL:
1508           if (mVirtualKeyCode != VK_LCONTROL &&
1509               mVirtualKeyCode != VK_RCONTROL) {
1510             mVirtualKeyCode = mIsExtended ? VK_RCONTROL : VK_LCONTROL;
1511           }
1512           break;
1513         case VK_MENU:
1514           if (mVirtualKeyCode != VK_LMENU && mVirtualKeyCode != VK_RMENU) {
1515             mVirtualKeyCode = mIsExtended ? VK_RMENU : VK_LMENU;
1516           }
1517           break;
1518         case VK_SHIFT:
1519           if (mVirtualKeyCode != VK_LSHIFT && mVirtualKeyCode != VK_RSHIFT) {
1520             // Neither left shift nor right shift is an extended key,
1521             // let's use VK_LSHIFT for unknown mapping.
1522             mVirtualKeyCode = VK_LSHIFT;
1523           }
1524           break;
1525         default:
1526           MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
1527       }
1528       break;
1529     }
1530     case WM_CHAR:
1531     case WM_UNICHAR:
1532     case WM_SYSCHAR:
1533       // If there is another instance and it is trying to remove a char message
1534       // from the queue, this message should be handled in the old instance.
1535       if (IsAnotherInstanceRemovingCharMessage()) {
1536         // XXX Do we need to make mReceivedMsg an array?
1537         MOZ_ASSERT(IsEmptyMSG(mLastInstance->mReceivedMsg));
1538         MOZ_LOG(
1539             sNativeKeyLogger, LogLevel::Warning,
1540             ("%p   NativeKey::InitWithKeyOrChar(), WARNING, detecting another "
1541              "instance is trying to remove a char message, so, this instance "
1542              "should do nothing, mLastInstance=0x%p, mRemovingMsg=%s, "
1543              "mReceivedMsg=%s",
1544              this, mLastInstance, ToString(mLastInstance->mRemovingMsg).get(),
1545              ToString(mLastInstance->mReceivedMsg).get()));
1546         mLastInstance->mReceivedMsg = mMsg;
1547         return;
1548       }
1549 
1550       // NOTE: If other applications like a11y tools sends WM_*CHAR without
1551       //       scancode, we cannot compute virtual keycode.  I.e., with such
1552       //       applications, we cannot generate proper KeyboardEvent.code value.
1553 
1554       mVirtualKeyCode = mOriginalVirtualKeyCode =
1555           ComputeVirtualKeyCodeFromScanCodeEx();
1556       NS_ASSERTION(mVirtualKeyCode, "Failed to compute virtual keycode");
1557       break;
1558     default:
1559       MOZ_CRASH("Unsupported message");
1560   }
1561 
1562   if (!mVirtualKeyCode) {
1563     mVirtualKeyCode = mOriginalVirtualKeyCode;
1564   }
1565 
1566   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
1567   mDOMKeyCode =
1568       keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
1569   // Be aware, keyboard utilities can change non-printable keys to printable
1570   // keys.  In such case, we should make the key value as a printable key.
1571   // FYI: IsFollowedByPrintableCharMessage() returns true only when it's
1572   //      handling a keydown message.
1573   mKeyNameIndex = IsFollowedByPrintableCharMessage()
1574                       ? KEY_NAME_INDEX_USE_STRING
1575                       : keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(
1576                             mOriginalVirtualKeyCode);
1577   mCodeNameIndex = KeyboardLayout::ConvertScanCodeToCodeNameIndex(
1578       GetScanCodeWithExtendedFlag());
1579 
1580   // If next message of WM_(SYS)KEYDOWN is WM_*CHAR message and the key
1581   // combination is not reserved by the system, let's consume it now.
1582   // TODO: We cannot initialize mCommittedCharsAndModifiers for VK_PACKET
1583   //       if the message is WM_KEYUP because we don't have preceding
1584   //       WM_CHAR message.
1585   // TODO: Like Edge, we shouldn't dispatch two sets of keyboard events
1586   //       for a Unicode character in non-BMP because its key value looks
1587   //       broken and not good thing for our editor if only one keydown or
1588   //       keypress event's default is prevented.  I guess, we should store
1589   //       key message information globally and we should wait following
1590   //       WM_KEYDOWN if following WM_CHAR is a part of a Unicode character.
1591   if ((mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN) &&
1592       !IsReservedBySystem()) {
1593     MSG charMsg;
1594     while (GetFollowingCharMessage(charMsg)) {
1595       // Although, got message shouldn't be WM_NULL in desktop apps,
1596       // we should keep checking this.  FYI: This was added for Metrofox.
1597       if (charMsg.message == WM_NULL) {
1598         continue;
1599       }
1600       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
1601               ("%p   NativeKey::InitWithKeyOrChar(), removed char message, %s",
1602                this, ToString(charMsg).get()));
1603       Unused << NS_WARN_IF(charMsg.hwnd != mMsg.hwnd);
1604       mFollowingCharMsgs.AppendElement(charMsg);
1605     }
1606   }
1607 
1608   keyboardLayout->InitNativeKey(*this, mModKeyState);
1609 
1610   mIsDeadKey =
1611       (IsFollowedByDeadCharMessage() ||
1612        keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState));
1613   mIsPrintableKey = mKeyNameIndex == KEY_NAME_INDEX_USE_STRING ||
1614                     KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
1615   // The repeat count in mMsg.lParam isn't useful to check whether the event
1616   // is caused by the auto-repeat feature because it's not incremented even
1617   // if it's repeated twice or more (i.e., always 1).  Therefore, we need to
1618   // check previous key state (31th bit) instead.  If it's 1, the key was down
1619   // before the message was sent.
1620   mIsRepeat = (mMsg.lParam & (1 << 30)) != 0;
1621   InitIsSkippableForKeyOrChar(lastKeyMSG);
1622 
1623   if (IsKeyDownMessage()) {
1624     // Compute some strings which may be inputted by the key with various
1625     // modifier state if this key event won't cause text input actually.
1626     // They will be used for setting mAlternativeCharCodes in the callback
1627     // method which will be called by TextEventDispatcher.
1628     if (!IsFollowedByPrintableCharMessage()) {
1629       ComputeInputtingStringWithKeyboardLayout();
1630     }
1631     // Remove odd char messages if there are.
1632     RemoveFollowingOddCharMessages();
1633   }
1634 }
1635 
InitCommittedCharsAndModifiersWithFollowingCharMessages(const ModifierKeyState & aModKeyState)1636 void NativeKey::InitCommittedCharsAndModifiersWithFollowingCharMessages(
1637     const ModifierKeyState& aModKeyState) {
1638   mCommittedCharsAndModifiers.Clear();
1639   // This should cause inputting text in focused editor.  However, it
1640   // ignores keypress events whose altKey or ctrlKey is true.
1641   // Therefore, we need to remove these modifier state here.
1642   Modifiers modifiers = aModKeyState.GetModifiers();
1643   if (IsFollowedByPrintableCharMessage()) {
1644     modifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
1645   }
1646   // NOTE: This method assumes that WM_CHAR and WM_SYSCHAR are never retrieved
1647   //       at same time.
1648   for (size_t i = 0; i < mFollowingCharMsgs.Length(); ++i) {
1649     // Ignore non-printable char messages.
1650     if (!IsPrintableCharOrSysCharMessage(mFollowingCharMsgs[i])) {
1651       continue;
1652     }
1653     char16_t ch = static_cast<char16_t>(mFollowingCharMsgs[i].wParam);
1654     mCommittedCharsAndModifiers.Append(ch, modifiers);
1655   }
1656 }
1657 
~NativeKey()1658 NativeKey::~NativeKey() {
1659   MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
1660           ("%p   NativeKey::~NativeKey(), destroyed", this));
1661   if (mIsOverridingKeyboardLayout) {
1662     KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
1663     keyboardLayout->RestoreLayout();
1664   }
1665   sLatestInstance = mLastInstance;
1666 }
1667 
InitWithAppCommand()1668 void NativeKey::InitWithAppCommand() {
1669   if (GET_DEVICE_LPARAM(mMsg.lParam) != FAPPCOMMAND_KEY) {
1670     return;
1671   }
1672 
1673   uint32_t appCommand = GET_APPCOMMAND_LPARAM(mMsg.lParam);
1674   switch (GET_APPCOMMAND_LPARAM(mMsg.lParam)) {
1675 #undef NS_APPCOMMAND_TO_DOM_KEY_NAME_INDEX
1676 #define NS_APPCOMMAND_TO_DOM_KEY_NAME_INDEX(aAppCommand, aKeyNameIndex) \
1677   case aAppCommand:                                                     \
1678     mKeyNameIndex = aKeyNameIndex;                                      \
1679     break;
1680 
1681 #include "NativeKeyToDOMKeyName.h"
1682 
1683 #undef NS_APPCOMMAND_TO_DOM_KEY_NAME_INDEX
1684 
1685     default:
1686       mKeyNameIndex = KEY_NAME_INDEX_Unidentified;
1687   }
1688 
1689   // Guess the virtual keycode which caused this message.
1690   switch (appCommand) {
1691     case APPCOMMAND_BROWSER_BACKWARD:
1692       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_BACK;
1693       break;
1694     case APPCOMMAND_BROWSER_FORWARD:
1695       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_FORWARD;
1696       break;
1697     case APPCOMMAND_BROWSER_REFRESH:
1698       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_REFRESH;
1699       break;
1700     case APPCOMMAND_BROWSER_STOP:
1701       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_STOP;
1702       break;
1703     case APPCOMMAND_BROWSER_SEARCH:
1704       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_SEARCH;
1705       break;
1706     case APPCOMMAND_BROWSER_FAVORITES:
1707       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_FAVORITES;
1708       break;
1709     case APPCOMMAND_BROWSER_HOME:
1710       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_BROWSER_HOME;
1711       break;
1712     case APPCOMMAND_VOLUME_MUTE:
1713       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_VOLUME_MUTE;
1714       break;
1715     case APPCOMMAND_VOLUME_DOWN:
1716       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_VOLUME_DOWN;
1717       break;
1718     case APPCOMMAND_VOLUME_UP:
1719       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_VOLUME_UP;
1720       break;
1721     case APPCOMMAND_MEDIA_NEXTTRACK:
1722       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_MEDIA_NEXT_TRACK;
1723       break;
1724     case APPCOMMAND_MEDIA_PREVIOUSTRACK:
1725       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_MEDIA_PREV_TRACK;
1726       break;
1727     case APPCOMMAND_MEDIA_STOP:
1728       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_MEDIA_STOP;
1729       break;
1730     case APPCOMMAND_MEDIA_PLAY_PAUSE:
1731       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_MEDIA_PLAY_PAUSE;
1732       break;
1733     case APPCOMMAND_LAUNCH_MAIL:
1734       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_LAUNCH_MAIL;
1735       break;
1736     case APPCOMMAND_LAUNCH_MEDIA_SELECT:
1737       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_LAUNCH_MEDIA_SELECT;
1738       break;
1739     case APPCOMMAND_LAUNCH_APP1:
1740       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_LAUNCH_APP1;
1741       break;
1742     case APPCOMMAND_LAUNCH_APP2:
1743       mVirtualKeyCode = mOriginalVirtualKeyCode = VK_LAUNCH_APP2;
1744       break;
1745     default:
1746       return;
1747   }
1748 
1749   uint16_t scanCodeEx = ComputeScanCodeExFromVirtualKeyCode(mVirtualKeyCode);
1750   mScanCode = static_cast<uint8_t>(scanCodeEx & 0xFF);
1751   uint8_t extended = static_cast<uint8_t>((scanCodeEx & 0xFF00) >> 8);
1752   mIsExtended = (extended == 0xE0) || (extended == 0xE1);
1753   mDOMKeyCode = KeyboardLayout::GetInstance()->ConvertNativeKeyCodeToDOMKeyCode(
1754       mOriginalVirtualKeyCode);
1755   mCodeNameIndex = KeyboardLayout::ConvertScanCodeToCodeNameIndex(
1756       GetScanCodeWithExtendedFlag());
1757   // If we can map the WM_APPCOMMAND to a virtual keycode, we can trust
1758   // the result of GetKeyboardState().  Otherwise, we dispatch both
1759   // keydown and keyup events from WM_APPCOMMAND handler.  Therefore,
1760   // even if WM_APPCOMMAND is caused by auto key repeat, web apps receive
1761   // a pair of DOM keydown and keyup events.  I.e., KeyboardEvent.repeat
1762   // should be never true of such keys.
1763   // XXX Isn't the key state always true?  If the key press caused this
1764   //     WM_APPCOMMAND, that means it's pressed at that time.
1765   if (mVirtualKeyCode) {
1766     BYTE kbdState[256];
1767     memset(kbdState, 0, sizeof(kbdState));
1768     ::GetKeyboardState(kbdState);
1769     mIsSkippableInRemoteProcess = mIsRepeat = !!kbdState[mVirtualKeyCode];
1770   }
1771 }
1772 
1773 // static
IsControlChar(char16_t aChar)1774 bool NativeKey::IsControlChar(char16_t aChar) {
1775   static const char16_t U_SPACE = 0x20;
1776   static const char16_t U_DELETE = 0x7F;
1777   return aChar < U_SPACE || aChar == U_DELETE;
1778 }
1779 
IsFollowedByDeadCharMessage() const1780 bool NativeKey::IsFollowedByDeadCharMessage() const {
1781   if (mFollowingCharMsgs.IsEmpty()) {
1782     return false;
1783   }
1784   return IsDeadCharMessage(mFollowingCharMsgs[0]);
1785 }
1786 
IsFollowedByPrintableCharMessage() const1787 bool NativeKey::IsFollowedByPrintableCharMessage() const {
1788   for (size_t i = 0; i < mFollowingCharMsgs.Length(); ++i) {
1789     if (IsPrintableCharMessage(mFollowingCharMsgs[i])) {
1790       return true;
1791     }
1792   }
1793   return false;
1794 }
1795 
IsFollowedByPrintableCharOrSysCharMessage() const1796 bool NativeKey::IsFollowedByPrintableCharOrSysCharMessage() const {
1797   for (size_t i = 0; i < mFollowingCharMsgs.Length(); ++i) {
1798     if (IsPrintableCharOrSysCharMessage(mFollowingCharMsgs[i])) {
1799       return true;
1800     }
1801   }
1802   return false;
1803 }
1804 
IsReservedBySystem() const1805 bool NativeKey::IsReservedBySystem() const {
1806   // Alt+Space key is handled by OS, we shouldn't touch it.
1807   if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
1808       mVirtualKeyCode == VK_SPACE) {
1809     return true;
1810   }
1811 
1812   // XXX How about Alt+F4? We receive WM_SYSKEYDOWN for F4 before closing the
1813   //     window.  Although, we don't prevent to close the window but the key
1814   //     event shouldn't be exposed to the web.
1815 
1816   return false;
1817 }
1818 
IsIMEDoingKakuteiUndo() const1819 bool NativeKey::IsIMEDoingKakuteiUndo() const {
1820   // Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
1821   // ---------------------------------------------------------------------------
1822   // WM_KEYDOWN              * n (wParam = VK_BACK, lParam = 0x1)
1823   // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
1824   // WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
1825   // WM_IME_COMPOSITION      * 1 (wParam = 0x0, lParam = 0x1BF)
1826   // WM_CHAR                 * n (wParam = VK_BACK, lParam = 0x1)
1827   // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC00E0001)
1828   // ---------------------------------------------------------------------------
1829   // This doesn't match usual key message pattern such as:
1830   //   WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR -> ... -> WM_KEYUP
1831   // See following bugs for the detail.
1832   // https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese)
1833   // https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English)
1834   MSG startCompositionMsg, compositionMsg, charMsg;
1835   return WinUtils::PeekMessage(&startCompositionMsg, mMsg.hwnd,
1836                                WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION,
1837                                PM_NOREMOVE | PM_NOYIELD) &&
1838          WinUtils::PeekMessage(&compositionMsg, mMsg.hwnd, WM_IME_COMPOSITION,
1839                                WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) &&
1840          WinUtils::PeekMessage(&charMsg, mMsg.hwnd, WM_CHAR, WM_CHAR,
1841                                PM_NOREMOVE | PM_NOYIELD) &&
1842          startCompositionMsg.wParam == 0x0 &&
1843          startCompositionMsg.lParam == 0x0 && compositionMsg.wParam == 0x0 &&
1844          compositionMsg.lParam == 0x1BF && charMsg.wParam == VK_BACK &&
1845          charMsg.lParam == 0x1 &&
1846          startCompositionMsg.time <= compositionMsg.time &&
1847          compositionMsg.time <= charMsg.time;
1848 }
1849 
RemoveFollowingOddCharMessages()1850 void NativeKey::RemoveFollowingOddCharMessages() {
1851   MOZ_ASSERT(IsKeyDownMessage());
1852 
1853   // If the keydown message is synthesized for automated tests, there is
1854   // nothing to do here.
1855   if (mFakeCharMsgs) {
1856     return;
1857   }
1858 
1859   // If there are some following char messages before another key message,
1860   // there is nothing to do here.
1861   if (!mFollowingCharMsgs.IsEmpty()) {
1862     return;
1863   }
1864 
1865   // If the handling key isn't Backspace, there is nothing to do here.
1866   if (mOriginalVirtualKeyCode != VK_BACK) {
1867     return;
1868   }
1869 
1870   // If we don't see the odd message pattern, there is nothing to do here.
1871   if (!IsIMEDoingKakuteiUndo()) {
1872     return;
1873   }
1874 
1875   // Otherwise, we need to remove odd WM_CHAR messages for ATOK or WXG (both
1876   // of them are Japanese IME).
1877   MSG msg;
1878   while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
1879                                PM_REMOVE | PM_NOYIELD)) {
1880     if (msg.message != WM_CHAR) {
1881       MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
1882                          "Unexpected message was removed");
1883       continue;
1884     }
1885     MOZ_LOG(
1886         sNativeKeyLogger, LogLevel::Info,
1887         ("%p   NativeKey::RemoveFollowingOddCharMessages(), removed odd char "
1888          "message, %s",
1889          this, ToString(msg).get()));
1890     mRemovedOddCharMsgs.AppendElement(msg);
1891   }
1892 }
1893 
GetScanCodeWithExtendedFlag() const1894 UINT NativeKey::GetScanCodeWithExtendedFlag() const {
1895   if (!mIsExtended) {
1896     return mScanCode;
1897   }
1898   return (0xE000 | mScanCode);
1899 }
1900 
GetKeyLocation() const1901 uint32_t NativeKey::GetKeyLocation() const {
1902   switch (mVirtualKeyCode) {
1903     case VK_LSHIFT:
1904     case VK_LCONTROL:
1905     case VK_LMENU:
1906     case VK_LWIN:
1907       return eKeyLocationLeft;
1908 
1909     case VK_RSHIFT:
1910     case VK_RCONTROL:
1911     case VK_RMENU:
1912     case VK_RWIN:
1913       return eKeyLocationRight;
1914 
1915     case VK_RETURN:
1916       // XXX This code assumes that all keyboard drivers use same mapping.
1917       return !mIsExtended ? eKeyLocationStandard : eKeyLocationNumpad;
1918 
1919     case VK_INSERT:
1920     case VK_DELETE:
1921     case VK_END:
1922     case VK_DOWN:
1923     case VK_NEXT:
1924     case VK_LEFT:
1925     case VK_CLEAR:
1926     case VK_RIGHT:
1927     case VK_HOME:
1928     case VK_UP:
1929     case VK_PRIOR:
1930       // XXX This code assumes that all keyboard drivers use same mapping.
1931       return mIsExtended ? eKeyLocationStandard : eKeyLocationNumpad;
1932 
1933     // NumLock key isn't included due to IE9's behavior.
1934     case VK_NUMPAD0:
1935     case VK_NUMPAD1:
1936     case VK_NUMPAD2:
1937     case VK_NUMPAD3:
1938     case VK_NUMPAD4:
1939     case VK_NUMPAD5:
1940     case VK_NUMPAD6:
1941     case VK_NUMPAD7:
1942     case VK_NUMPAD8:
1943     case VK_NUMPAD9:
1944     case VK_DECIMAL:
1945     case VK_DIVIDE:
1946     case VK_MULTIPLY:
1947     case VK_SUBTRACT:
1948     case VK_ADD:
1949     // Separator key of Brazilian keyboard or JIS keyboard for Mac
1950     case VK_ABNT_C2:
1951       return eKeyLocationNumpad;
1952 
1953     case VK_SHIFT:
1954     case VK_CONTROL:
1955     case VK_MENU:
1956       NS_WARNING("Failed to decide the key location?");
1957 
1958     default:
1959       return eKeyLocationStandard;
1960   }
1961 }
1962 
ComputeVirtualKeyCodeFromScanCode() const1963 uint8_t NativeKey::ComputeVirtualKeyCodeFromScanCode() const {
1964   return static_cast<uint8_t>(
1965       ::MapVirtualKeyEx(mScanCode, MAPVK_VSC_TO_VK, mKeyboardLayout));
1966 }
1967 
ComputeVirtualKeyCodeFromScanCodeEx() const1968 uint8_t NativeKey::ComputeVirtualKeyCodeFromScanCodeEx() const {
1969   // MapVirtualKeyEx() has been improved for supporting extended keys since
1970   // Vista.  When we call it for mapping a scancode of an extended key and
1971   // a virtual keycode, we need to add 0xE000 to the scancode.
1972   return static_cast<uint8_t>(::MapVirtualKeyEx(
1973       GetScanCodeWithExtendedFlag(), MAPVK_VSC_TO_VK_EX, mKeyboardLayout));
1974 }
1975 
ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const1976 uint16_t NativeKey::ComputeScanCodeExFromVirtualKeyCode(
1977     UINT aVirtualKeyCode) const {
1978   return static_cast<uint16_t>(
1979       ::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC_EX, mKeyboardLayout));
1980 }
1981 
ComputeUnicharFromScanCode() const1982 char16_t NativeKey::ComputeUnicharFromScanCode() const {
1983   return static_cast<char16_t>(::MapVirtualKeyEx(
1984       ComputeVirtualKeyCodeFromScanCode(), MAPVK_VK_TO_CHAR, mKeyboardLayout));
1985 }
1986 
InitKeyEvent(WidgetKeyboardEvent & aKeyEvent,const MSG * aMsgSentToPlugin) const1987 nsEventStatus NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
1988                                       const MSG* aMsgSentToPlugin) const {
1989   return InitKeyEvent(aKeyEvent, mModKeyState, aMsgSentToPlugin);
1990 }
1991 
InitKeyEvent(WidgetKeyboardEvent & aKeyEvent,const ModifierKeyState & aModKeyState,const MSG * aMsgSentToPlugin) const1992 nsEventStatus NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
1993                                       const ModifierKeyState& aModKeyState,
1994                                       const MSG* aMsgSentToPlugin) const {
1995   if (mWidget->Destroyed()) {
1996     MOZ_CRASH("NativeKey tries to dispatch a key event on destroyed widget");
1997   }
1998 
1999   LayoutDeviceIntPoint point(0, 0);
2000   mWidget->InitEvent(aKeyEvent, &point);
2001 
2002   switch (aKeyEvent.mMessage) {
2003     case eKeyDown:
2004       // If it was followed by a char message but it was consumed by somebody,
2005       // we should mark it as consumed because somebody must have handled it
2006       // and we should prevent to do "double action" for the key operation.
2007       if (mCharMessageHasGone) {
2008         aKeyEvent.PreventDefaultBeforeDispatch();
2009       }
2010       MOZ_FALLTHROUGH;
2011     case eKeyDownOnPlugin:
2012       aKeyEvent.mKeyCode = mDOMKeyCode;
2013       // Unique id for this keydown event and its associated keypress.
2014       sUniqueKeyEventId++;
2015       aKeyEvent.mUniqueId = sUniqueKeyEventId;
2016       break;
2017     case eKeyUp:
2018     case eKeyUpOnPlugin:
2019       aKeyEvent.mKeyCode = mDOMKeyCode;
2020       // Set defaultPrevented of the key event if the VK_MENU is not a system
2021       // key release, so that the menu bar does not trigger.  This helps avoid
2022       // triggering the menu bar for ALT key accelerators used in assistive
2023       // technologies such as Window-Eyes and ZoomText or for switching open
2024       // state of IME.
2025       if (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP) {
2026         aKeyEvent.PreventDefaultBeforeDispatch();
2027       }
2028       break;
2029     case eKeyPress:
2030       MOZ_ASSERT(!mCharMessageHasGone,
2031                  "If following char message was consumed by somebody, "
2032                  "keydown event should be consumed above");
2033       aKeyEvent.mUniqueId = sUniqueKeyEventId;
2034       break;
2035     default:
2036       MOZ_CRASH("Invalid event message");
2037   }
2038 
2039   aKeyEvent.mIsRepeat = mIsRepeat;
2040   aKeyEvent.mMaybeSkippableInRemoteProcess = mIsSkippableInRemoteProcess;
2041   aKeyEvent.mKeyNameIndex = mKeyNameIndex;
2042   if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
2043     aKeyEvent.mKeyValue = mCommittedCharsAndModifiers.ToString();
2044   }
2045   aKeyEvent.mCodeNameIndex = mCodeNameIndex;
2046   MOZ_ASSERT(mCodeNameIndex != CODE_NAME_INDEX_USE_STRING);
2047   aKeyEvent.mLocation = GetKeyLocation();
2048   aModKeyState.InitInputEvent(aKeyEvent);
2049 
2050   if (aMsgSentToPlugin) {
2051     MaybeInitPluginEventOfKeyEvent(aKeyEvent, *aMsgSentToPlugin);
2052   }
2053 
2054   KeyboardLayout::NotifyIdleServiceOfUserActivity();
2055 
2056   MOZ_LOG(
2057       sNativeKeyLogger, LogLevel::Info,
2058       ("%p   NativeKey::InitKeyEvent(), initialized, aKeyEvent={ "
2059        "mMessage=%s, mKeyNameIndex=%s, mKeyValue=\"%s\", mCodeNameIndex=%s, "
2060        "mKeyCode=%s, mLocation=%s, mModifiers=%s, DefaultPrevented()=%s }",
2061        this, ToChar(aKeyEvent.mMessage),
2062        ToString(aKeyEvent.mKeyNameIndex).get(),
2063        NS_ConvertUTF16toUTF8(aKeyEvent.mKeyValue).get(),
2064        ToString(aKeyEvent.mCodeNameIndex).get(),
2065        GetDOMKeyCodeName(aKeyEvent.mKeyCode).get(),
2066        GetKeyLocationName(aKeyEvent.mLocation).get(),
2067        GetModifiersName(aKeyEvent.mModifiers).get(),
2068        GetBoolName(aKeyEvent.DefaultPrevented())));
2069 
2070   return aKeyEvent.DefaultPrevented() ? nsEventStatus_eConsumeNoDefault
2071                                       : nsEventStatus_eIgnore;
2072 }
2073 
MaybeInitPluginEventOfKeyEvent(WidgetKeyboardEvent & aKeyEvent,const MSG & aMsgSentToPlugin) const2074 void NativeKey::MaybeInitPluginEventOfKeyEvent(
2075     WidgetKeyboardEvent& aKeyEvent, const MSG& aMsgSentToPlugin) const {
2076   if (mWidget->GetInputContext().mIMEState.mEnabled != IMEState::PLUGIN) {
2077     return;
2078   }
2079   NPEvent pluginEvent;
2080   pluginEvent.event = aMsgSentToPlugin.message;
2081   pluginEvent.wParam = aMsgSentToPlugin.wParam;
2082   pluginEvent.lParam = aMsgSentToPlugin.lParam;
2083   aKeyEvent.mPluginEvent.Copy(pluginEvent);
2084 }
2085 
DispatchCommandEvent(uint32_t aEventCommand) const2086 bool NativeKey::DispatchCommandEvent(uint32_t aEventCommand) const {
2087   RefPtr<nsAtom> command;
2088   switch (aEventCommand) {
2089     case APPCOMMAND_BROWSER_BACKWARD:
2090       command = nsGkAtoms::Back;
2091       break;
2092     case APPCOMMAND_BROWSER_FORWARD:
2093       command = nsGkAtoms::Forward;
2094       break;
2095     case APPCOMMAND_BROWSER_REFRESH:
2096       command = nsGkAtoms::Reload;
2097       break;
2098     case APPCOMMAND_BROWSER_STOP:
2099       command = nsGkAtoms::Stop;
2100       break;
2101     case APPCOMMAND_BROWSER_SEARCH:
2102       command = nsGkAtoms::Search;
2103       break;
2104     case APPCOMMAND_BROWSER_FAVORITES:
2105       command = nsGkAtoms::Bookmarks;
2106       break;
2107     case APPCOMMAND_BROWSER_HOME:
2108       command = nsGkAtoms::Home;
2109       break;
2110     case APPCOMMAND_CLOSE:
2111       command = nsGkAtoms::Close;
2112       break;
2113     case APPCOMMAND_FIND:
2114       command = nsGkAtoms::Find;
2115       break;
2116     case APPCOMMAND_HELP:
2117       command = nsGkAtoms::Help;
2118       break;
2119     case APPCOMMAND_NEW:
2120       command = nsGkAtoms::New;
2121       break;
2122     case APPCOMMAND_OPEN:
2123       command = nsGkAtoms::Open;
2124       break;
2125     case APPCOMMAND_PRINT:
2126       command = nsGkAtoms::Print;
2127       break;
2128     case APPCOMMAND_SAVE:
2129       command = nsGkAtoms::Save;
2130       break;
2131     case APPCOMMAND_FORWARD_MAIL:
2132       command = nsGkAtoms::ForwardMail;
2133       break;
2134     case APPCOMMAND_REPLY_TO_MAIL:
2135       command = nsGkAtoms::ReplyToMail;
2136       break;
2137     case APPCOMMAND_SEND_MAIL:
2138       command = nsGkAtoms::SendMail;
2139       break;
2140     case APPCOMMAND_MEDIA_NEXTTRACK:
2141       command = nsGkAtoms::NextTrack;
2142       break;
2143     case APPCOMMAND_MEDIA_PREVIOUSTRACK:
2144       command = nsGkAtoms::PreviousTrack;
2145       break;
2146     case APPCOMMAND_MEDIA_STOP:
2147       command = nsGkAtoms::MediaStop;
2148       break;
2149     case APPCOMMAND_MEDIA_PLAY_PAUSE:
2150       command = nsGkAtoms::PlayPause;
2151       break;
2152     default:
2153       MOZ_LOG(
2154           sNativeKeyLogger, LogLevel::Info,
2155           ("%p   NativeKey::DispatchCommandEvent(), doesn't dispatch command "
2156            "event",
2157            this));
2158       return false;
2159   }
2160   WidgetCommandEvent commandEvent(true, nsGkAtoms::onAppCommand, command,
2161                                   mWidget);
2162 
2163   mWidget->InitEvent(commandEvent);
2164   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2165           ("%p   NativeKey::DispatchCommandEvent(), dispatching %s command "
2166            "event...",
2167            this, nsAtomCString(command).get()));
2168   bool ok = mWidget->DispatchWindowEvent(&commandEvent) || mWidget->Destroyed();
2169   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2170           ("%p   NativeKey::DispatchCommandEvent(), dispatched command event, "
2171            "result=%s, mWidget->Destroyed()=%s",
2172            this, GetBoolName(ok), GetBoolName(mWidget->Destroyed())));
2173   return ok;
2174 }
2175 
HandleAppCommandMessage() const2176 bool NativeKey::HandleAppCommandMessage() const {
2177   // If the widget has gone, we should do nothing.
2178   if (mWidget->Destroyed()) {
2179     MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
2180             ("%p   NativeKey::HandleAppCommandMessage(), WARNING, not handled "
2181              "due to "
2182              "destroyed the widget",
2183              this));
2184     return false;
2185   }
2186 
2187   // NOTE: Typical behavior of WM_APPCOMMAND caused by key is, WM_APPCOMMAND
2188   //       message is _sent_ first.  Then, the DefaultWndProc will _post_
2189   //       WM_KEYDOWN message and WM_KEYUP message if the keycode for the
2190   //       command is available (i.e., mVirtualKeyCode is not 0).
2191 
2192   // NOTE: IntelliType (Microsoft's keyboard utility software) always consumes
2193   //       WM_KEYDOWN and WM_KEYUP.
2194 
2195   // Let's dispatch keydown message before our chrome handles the command
2196   // when the message is caused by a keypress.  This behavior makes handling
2197   // WM_APPCOMMAND be a default action of the keydown event.  This means that
2198   // web applications can handle multimedia keys and prevent our default action.
2199   // This allow web applications to provide better UX for multimedia keyboard
2200   // users.
2201   bool dispatchKeyEvent = (GET_DEVICE_LPARAM(mMsg.lParam) == FAPPCOMMAND_KEY);
2202   if (dispatchKeyEvent) {
2203     // If a plug-in window has focus but it didn't consume the message, our
2204     // window receive WM_APPCOMMAND message.  In this case, we shouldn't
2205     // dispatch KeyboardEvents because an event handler may access the
2206     // plug-in process synchronously.
2207     dispatchKeyEvent =
2208         WinUtils::IsOurProcessWindow(reinterpret_cast<HWND>(mMsg.wParam));
2209   }
2210 
2211   bool consumed = false;
2212 
2213   if (dispatchKeyEvent) {
2214     nsresult rv = mDispatcher->BeginNativeInputTransaction();
2215     if (NS_WARN_IF(NS_FAILED(rv))) {
2216       MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
2217               ("%p   NativeKey::HandleAppCommandMessage(), FAILED due to "
2218                "BeginNativeInputTransaction() failure",
2219                this));
2220       return true;
2221     }
2222     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2223             ("%p   NativeKey::HandleAppCommandMessage(), initializing keydown "
2224              "event...",
2225              this));
2226     WidgetKeyboardEvent keydownEvent(true, eKeyDown, mWidget);
2227     nsEventStatus status = InitKeyEvent(keydownEvent, mModKeyState, &mMsg);
2228     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2229             ("%p   NativeKey::HandleAppCommandMessage(), tries to dispatch "
2230              "keydown event...",
2231              this));
2232     // NOTE: If the keydown event is consumed by web contents, we shouldn't
2233     //       continue to handle the command.
2234     if (!mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, status,
2235                                             const_cast<NativeKey*>(this))) {
2236       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2237               ("%p   NativeKey::HandleAppCommandMessage(), keydown event isn't "
2238                "dispatched",
2239                this));
2240       // If keyboard event wasn't fired, there must be composition.
2241       // So, we don't need to dispatch a command event.
2242       return true;
2243     }
2244     consumed = status == nsEventStatus_eConsumeNoDefault;
2245     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2246             ("%p   NativeKey::HandleAppCommandMessage(), keydown event was "
2247              "dispatched, consumed=%s",
2248              this, GetBoolName(consumed)));
2249     sDispatchedKeyOfAppCommand = mVirtualKeyCode;
2250     if (mWidget->Destroyed()) {
2251       MOZ_LOG(
2252           sNativeKeyLogger, LogLevel::Info,
2253           ("%p   NativeKey::HandleAppCommandMessage(), keydown event caused "
2254            "destroying the widget",
2255            this));
2256       return true;
2257     }
2258   }
2259 
2260   // Dispatch a command event or a content command event if the command is
2261   // supported.
2262   if (!consumed) {
2263     uint32_t appCommand = GET_APPCOMMAND_LPARAM(mMsg.lParam);
2264     EventMessage contentCommandMessage = eVoidEvent;
2265     switch (appCommand) {
2266       case APPCOMMAND_BROWSER_BACKWARD:
2267       case APPCOMMAND_BROWSER_FORWARD:
2268       case APPCOMMAND_BROWSER_REFRESH:
2269       case APPCOMMAND_BROWSER_STOP:
2270       case APPCOMMAND_BROWSER_SEARCH:
2271       case APPCOMMAND_BROWSER_FAVORITES:
2272       case APPCOMMAND_BROWSER_HOME:
2273       case APPCOMMAND_CLOSE:
2274       case APPCOMMAND_FIND:
2275       case APPCOMMAND_HELP:
2276       case APPCOMMAND_NEW:
2277       case APPCOMMAND_OPEN:
2278       case APPCOMMAND_PRINT:
2279       case APPCOMMAND_SAVE:
2280       case APPCOMMAND_FORWARD_MAIL:
2281       case APPCOMMAND_REPLY_TO_MAIL:
2282       case APPCOMMAND_SEND_MAIL:
2283       case APPCOMMAND_MEDIA_NEXTTRACK:
2284       case APPCOMMAND_MEDIA_PREVIOUSTRACK:
2285       case APPCOMMAND_MEDIA_STOP:
2286       case APPCOMMAND_MEDIA_PLAY_PAUSE:
2287         // We shouldn't consume the message always because if we don't handle
2288         // the message, the sender (typically, utility of keyboard or mouse)
2289         // may send other key messages which indicate well known shortcut key.
2290         consumed = DispatchCommandEvent(appCommand);
2291         break;
2292 
2293       // Use content command for following commands:
2294       case APPCOMMAND_COPY:
2295         contentCommandMessage = eContentCommandCopy;
2296         break;
2297       case APPCOMMAND_CUT:
2298         contentCommandMessage = eContentCommandCut;
2299         break;
2300       case APPCOMMAND_PASTE:
2301         contentCommandMessage = eContentCommandPaste;
2302         break;
2303       case APPCOMMAND_REDO:
2304         contentCommandMessage = eContentCommandRedo;
2305         break;
2306       case APPCOMMAND_UNDO:
2307         contentCommandMessage = eContentCommandUndo;
2308         break;
2309     }
2310 
2311     if (contentCommandMessage) {
2312       MOZ_ASSERT(!mWidget->Destroyed());
2313       WidgetContentCommandEvent contentCommandEvent(true, contentCommandMessage,
2314                                                     mWidget);
2315       MOZ_LOG(
2316           sNativeKeyLogger, LogLevel::Info,
2317           ("%p   NativeKey::HandleAppCommandMessage(), dispatching %s event...",
2318            this, ToChar(contentCommandMessage)));
2319       mWidget->DispatchWindowEvent(&contentCommandEvent);
2320       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2321               ("%p   NativeKey::HandleAppCommandMessage(), dispatched %s event",
2322                this, ToChar(contentCommandMessage)));
2323       consumed = true;
2324 
2325       if (mWidget->Destroyed()) {
2326         MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2327                 ("%p   NativeKey::HandleAppCommandMessage(), %s event caused "
2328                  "destroying the widget",
2329                  this, ToChar(contentCommandMessage)));
2330         return true;
2331       }
2332     } else {
2333       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2334               ("%p   NativeKey::HandleAppCommandMessage(), doesn't dispatch "
2335                "content "
2336                "command event",
2337                this));
2338     }
2339   }
2340 
2341   // Dispatch a keyup event if the command is caused by pressing a key and
2342   // the key isn't mapped to a virtual keycode.
2343   if (dispatchKeyEvent && !mVirtualKeyCode) {
2344     MOZ_ASSERT(!mWidget->Destroyed());
2345     nsresult rv = mDispatcher->BeginNativeInputTransaction();
2346     if (NS_WARN_IF(NS_FAILED(rv))) {
2347       MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
2348               ("%p   NativeKey::HandleAppCommandMessage(), FAILED due to "
2349                "BeginNativeInputTransaction() failure",
2350                this));
2351       return true;
2352     }
2353     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2354             ("%p   NativeKey::HandleAppCommandMessage(), initializing keyup "
2355              "event...",
2356              this));
2357     WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget);
2358     nsEventStatus status = InitKeyEvent(keyupEvent, mModKeyState, &mMsg);
2359     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2360             ("%p   NativeKey::HandleAppCommandMessage(), dispatching keyup "
2361              "event...",
2362              this));
2363     // NOTE: Ignore if the keyup event is consumed because keyup event
2364     //       represents just a physical key event state change.
2365     mDispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, status,
2366                                        const_cast<NativeKey*>(this));
2367     MOZ_LOG(
2368         sNativeKeyLogger, LogLevel::Info,
2369         ("%p   NativeKey::HandleAppCommandMessage(), dispatched keyup event",
2370          this));
2371     if (mWidget->Destroyed()) {
2372       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2373               ("%p   NativeKey::HandleAppCommandMessage(), %s event caused "
2374                "destroying the widget",
2375                this));
2376       return true;
2377     }
2378   }
2379 
2380   return consumed;
2381 }
2382 
HandleKeyDownMessage(bool * aEventDispatched) const2383 bool NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const {
2384   MOZ_ASSERT(IsKeyDownMessage());
2385 
2386   if (aEventDispatched) {
2387     *aEventDispatched = false;
2388   }
2389 
2390   if (sDispatchedKeyOfAppCommand &&
2391       sDispatchedKeyOfAppCommand == mOriginalVirtualKeyCode) {
2392     // The multimedia key event has already been dispatch from
2393     // HandleAppCommandMessage().
2394     sDispatchedKeyOfAppCommand = 0;
2395     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2396             ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keydown "
2397              "event due to already dispatched from HandleAppCommandMessage(), ",
2398              this));
2399     if (RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
2400       RedirectedKeyDownMessageManager::Forget();
2401     }
2402     return true;
2403   }
2404 
2405   if (IsReservedBySystem()) {
2406     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2407             ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keydown "
2408              "event because the key combination is reserved by the system",
2409              this));
2410     if (RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
2411       RedirectedKeyDownMessageManager::Forget();
2412     }
2413     return false;
2414   }
2415 
2416   // If the widget has gone, we should do nothing.
2417   if (mWidget->Destroyed()) {
2418     MOZ_LOG(
2419         sNativeKeyLogger, LogLevel::Warning,
2420         ("%p   NativeKey::HandleKeyDownMessage(), WARNING, not handled due to "
2421          "destroyed the widget",
2422          this));
2423     if (RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
2424       RedirectedKeyDownMessageManager::Forget();
2425     }
2426     return false;
2427   }
2428 
2429   bool defaultPrevented = false;
2430   if (mFakeCharMsgs || IsKeyMessageOnPlugin() ||
2431       !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
2432     nsresult rv = mDispatcher->BeginNativeInputTransaction();
2433     if (NS_WARN_IF(NS_FAILED(rv))) {
2434       MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
2435               ("%p   NativeKey::HandleKeyDownMessage(), FAILED due to "
2436                "BeginNativeInputTransaction() failure",
2437                this));
2438       return true;
2439     }
2440 
2441     bool isIMEEnabled = WinUtils::IsIMEEnabled(mWidget->GetInputContext());
2442 
2443     MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
2444             ("%p   NativeKey::HandleKeyDownMessage(), initializing keydown "
2445              "event...",
2446              this));
2447 
2448     EventMessage keyDownMessage =
2449         IsKeyMessageOnPlugin() ? eKeyDownOnPlugin : eKeyDown;
2450     WidgetKeyboardEvent keydownEvent(true, keyDownMessage, mWidget);
2451     nsEventStatus status = InitKeyEvent(keydownEvent, mModKeyState, &mMsg);
2452     MOZ_LOG(
2453         sNativeKeyLogger, LogLevel::Info,
2454         ("%p   NativeKey::HandleKeyDownMessage(), dispatching keydown event...",
2455          this));
2456     bool dispatched = mDispatcher->DispatchKeyboardEvent(
2457         keyDownMessage, keydownEvent, status, const_cast<NativeKey*>(this));
2458     if (aEventDispatched) {
2459       *aEventDispatched = dispatched;
2460     }
2461     if (!dispatched) {
2462       // If the keydown event wasn't fired, there must be composition.
2463       // we don't need to do anything anymore.
2464       MOZ_LOG(
2465           sNativeKeyLogger, LogLevel::Info,
2466           ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keypress "
2467            "event(s) because keydown event isn't dispatched actually",
2468            this));
2469       return false;
2470     }
2471     defaultPrevented = status == nsEventStatus_eConsumeNoDefault;
2472 
2473     // We don't need to handle key messages on plugin for eKeyPress since
2474     // eKeyDownOnPlugin is handled as both eKeyDown and eKeyPress.
2475     if (IsKeyMessageOnPlugin()) {
2476       MOZ_LOG(
2477           sNativeKeyLogger, LogLevel::Info,
2478           ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keypress "
2479            "event(s) because it's a keydown message on windowed plugin, "
2480            "defaultPrevented=%s",
2481            this, GetBoolName(defaultPrevented)));
2482       return defaultPrevented;
2483     }
2484 
2485     if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
2486       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2487               ("%p   NativeKey::HandleKeyDownMessage(), keydown event caused "
2488                "destroying the widget",
2489                this));
2490       return true;
2491     }
2492 
2493     MOZ_LOG(
2494         sNativeKeyLogger, LogLevel::Info,
2495         ("%p   NativeKey::HandleKeyDownMessage(), dispatched keydown event, "
2496          "dispatched=%s, defaultPrevented=%s",
2497          this, GetBoolName(dispatched), GetBoolName(defaultPrevented)));
2498 
2499     // If IMC wasn't associated to the window but is associated it now (i.e.,
2500     // focus is moved from a non-editable editor to an editor by keydown
2501     // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
2502     // inputting if IME is opened.  But then, we should redirect the native
2503     // keydown message to IME.
2504     // However, note that if focus has been already moved to another
2505     // application, we shouldn't redirect the message to it because the keydown
2506     // message is processed by us, so, nobody shouldn't process it.
2507     HWND focusedWnd = ::GetFocus();
2508     if (!defaultPrevented && !mFakeCharMsgs && !IsKeyMessageOnPlugin() &&
2509         focusedWnd && !mWidget->PluginHasFocus() && !isIMEEnabled &&
2510         WinUtils::IsIMEEnabled(mWidget->GetInputContext())) {
2511       RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd);
2512 
2513       INPUT keyinput;
2514       keyinput.type = INPUT_KEYBOARD;
2515       keyinput.ki.wVk = mOriginalVirtualKeyCode;
2516       keyinput.ki.wScan = mScanCode;
2517       keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
2518       if (mIsExtended) {
2519         keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
2520       }
2521       keyinput.ki.time = 0;
2522       keyinput.ki.dwExtraInfo = 0;
2523 
2524       RedirectedKeyDownMessageManager::WillRedirect(mMsg, defaultPrevented);
2525 
2526       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2527               ("%p   NativeKey::HandleKeyDownMessage(), redirecting %s...",
2528                this, ToString(mMsg).get()));
2529 
2530       ::SendInput(1, &keyinput, sizeof(keyinput));
2531 
2532       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2533               ("%p   NativeKey::HandleKeyDownMessage(), redirected %s", this,
2534                ToString(mMsg).get()));
2535 
2536       // Return here.  We shouldn't dispatch keypress event for this WM_KEYDOWN.
2537       // If it's needed, it will be dispatched after next (redirected)
2538       // WM_KEYDOWN.
2539       return true;
2540     }
2541   } else {
2542     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2543             ("%p   NativeKey::HandleKeyDownMessage(), received a redirected %s",
2544              this, ToString(mMsg).get()));
2545 
2546     defaultPrevented = RedirectedKeyDownMessageManager::DefaultPrevented();
2547     // If this is redirected keydown message, we have dispatched the keydown
2548     // event already.
2549     if (aEventDispatched) {
2550       *aEventDispatched = true;
2551     }
2552   }
2553 
2554   RedirectedKeyDownMessageManager::Forget();
2555 
2556   MOZ_ASSERT(!mWidget->Destroyed());
2557 
2558   // If the key was processed by IME and didn't cause WM_(SYS)CHAR messages, we
2559   // shouldn't dispatch keypress event.
2560   if (mOriginalVirtualKeyCode == VK_PROCESSKEY &&
2561       !IsFollowedByPrintableCharOrSysCharMessage()) {
2562     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2563             ("%p   NativeKey::HandleKeyDownMessage(), not dispatching keypress "
2564              "event because the key was already handled by IME, "
2565              "defaultPrevented=%s",
2566              this, GetBoolName(defaultPrevented)));
2567     return defaultPrevented;
2568   }
2569 
2570   if (defaultPrevented) {
2571     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2572             ("%p   NativeKey::HandleKeyDownMessage(), not dispatching keypress "
2573              "event because preceding keydown event was consumed",
2574              this));
2575     MaybeDispatchPluginEventsForRemovedCharMessages();
2576     return true;
2577   }
2578 
2579   MOZ_ASSERT(!mCharMessageHasGone,
2580              "If following char message was consumed by somebody, "
2581              "keydown event should have been consumed before dispatch");
2582 
2583   // If mCommittedCharsAndModifiers was initialized with following char
2584   // messages, we should dispatch keypress events with its information.
2585   if (IsFollowedByPrintableCharOrSysCharMessage()) {
2586     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2587             ("%p   NativeKey::HandleKeyDownMessage(), tries to be dispatching "
2588              "keypress events with retrieved char messages...",
2589              this));
2590     return DispatchKeyPressEventsWithRetrievedCharMessages();
2591   }
2592 
2593   // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a
2594   // keypress for almost all keys
2595   if (NeedsToHandleWithoutFollowingCharMessages()) {
2596     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2597             ("%p   NativeKey::HandleKeyDownMessage(), tries to be dispatching "
2598              "keypress events...",
2599              this));
2600     return (MaybeDispatchPluginEventsForRemovedCharMessages() ||
2601             DispatchKeyPressEventsWithoutCharMessage());
2602   }
2603 
2604   // If WM_KEYDOWN of VK_PACKET isn't followed by WM_CHAR, we don't need to
2605   // dispatch keypress events.
2606   if (mVirtualKeyCode == VK_PACKET) {
2607     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2608             ("%p   NativeKey::HandleKeyDownMessage(), not dispatching keypress "
2609              "event "
2610              "because the key is VK_PACKET and there are no char messages",
2611              this));
2612     return false;
2613   }
2614 
2615   if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
2616       !mModKeyState.IsWin() && mIsPrintableKey) {
2617     // If this is simple KeyDown event but next message is not WM_CHAR,
2618     // this event may not input text, so we should ignore this event.
2619     // See bug 314130.
2620     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2621             ("%p   NativeKey::HandleKeyDownMessage(), not dispatching keypress "
2622              "event "
2623              "because the key event is simple printable key's event but not "
2624              "followed "
2625              "by char messages",
2626              this));
2627     return false;
2628   }
2629 
2630   if (mIsDeadKey) {
2631     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2632             ("%p   NativeKey::HandleKeyDownMessage(), not dispatching keypress "
2633              "event "
2634              "because the key is a dead key and not followed by char messages",
2635              this));
2636     return false;
2637   }
2638 
2639   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2640           ("%p   NativeKey::HandleKeyDownMessage(), tries to be dispatching "
2641            "keypress events due to no following char messages...",
2642            this));
2643   return DispatchKeyPressEventsWithoutCharMessage();
2644 }
2645 
HandleCharMessage(bool * aEventDispatched) const2646 bool NativeKey::HandleCharMessage(bool* aEventDispatched) const {
2647   MOZ_ASSERT(IsCharOrSysCharMessage(mMsg));
2648   return HandleCharMessage(mMsg, aEventDispatched);
2649 }
2650 
HandleCharMessage(const MSG & aCharMsg,bool * aEventDispatched) const2651 bool NativeKey::HandleCharMessage(const MSG& aCharMsg,
2652                                   bool* aEventDispatched) const {
2653   MOZ_ASSERT(IsKeyDownMessage() || IsCharOrSysCharMessage(mMsg));
2654   MOZ_ASSERT(IsCharOrSysCharMessage(aCharMsg.message));
2655 
2656   if (aEventDispatched) {
2657     *aEventDispatched = false;
2658   }
2659 
2660   if ((IsCharOrSysCharMessage(mMsg) || IsEnterKeyPressCharMessage(mMsg)) &&
2661       IsAnotherInstanceRemovingCharMessage()) {
2662     MOZ_LOG(
2663         sNativeKeyLogger, LogLevel::Warning,
2664         ("%p   NativeKey::HandleCharMessage(), WARNING, does nothing because "
2665          "the message should be handled in another instance removing this "
2666          "message",
2667          this));
2668     // Consume this for now because it will be handled by another instance.
2669     return true;
2670   }
2671 
2672   // If the key combinations is reserved by the system, we shouldn't dispatch
2673   // eKeyPress event for it and passes the message to next wndproc.
2674   if (IsReservedBySystem()) {
2675     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2676             ("%p   NativeKey::HandleCharMessage(), doesn't dispatch keypress "
2677              "event because the key combination is reserved by the system",
2678              this));
2679     return false;
2680   }
2681 
2682   // If the widget has gone, we should do nothing.
2683   if (mWidget->Destroyed()) {
2684     MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
2685             ("%p   NativeKey::HandleCharMessage(), WARNING, not handled due to "
2686              "destroyed the widget",
2687              this));
2688     return false;
2689   }
2690 
2691   // When a control key is inputted by a key, it should be handled without
2692   // WM_*CHAR messages at receiving WM_*KEYDOWN message.  So, when we receive
2693   // WM_*CHAR message directly, we see a control character here.
2694   // Note that when the char is '\r', it means that the char message should
2695   // cause "Enter" keypress event for inserting a line break.
2696   if (IsControlCharMessage(aCharMsg) && !IsEnterKeyPressCharMessage(aCharMsg)) {
2697     // In this case, we don't need to dispatch eKeyPress event because:
2698     // 1. We're the only browser which dispatches "keypress" event for
2699     //    non-printable characters (Although, both Chrome and Edge dispatch
2700     //    "keypress" event for some keys accidentally.  For example, "IntlRo"
2701     //    key with Ctrl of Japanese keyboard layout).
2702     // 2. Currently, we may handle shortcut keys with "keydown" event if
2703     //    it's reserved or something.  So, we shouldn't dispatch "keypress"
2704     //    event without it.
2705     // Note that this does NOT mean we stop dispatching eKeyPress event for
2706     // key presses causes a control character when Ctrl is pressed.  In such
2707     // case, DispatchKeyPressEventsWithoutCharMessage() dispatches eKeyPress
2708     // instead of this method.
2709     MOZ_LOG(
2710         sNativeKeyLogger, LogLevel::Info,
2711         ("%p   NativeKey::HandleCharMessage(), doesn't dispatch keypress "
2712          "event because received a control character input without WM_KEYDOWN",
2713          this));
2714     return false;
2715   }
2716 
2717   // XXXmnakano I think that if mMsg is WM_CHAR, i.e., it comes without
2718   //            preceding WM_KEYDOWN, we should should dispatch composition
2719   //            events instead of eKeyPress because they are not caused by
2720   //            actual keyboard operation.
2721 
2722   // First, handle normal text input or non-printable key case here.
2723   WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget);
2724   if (IsEnterKeyPressCharMessage(aCharMsg)) {
2725     keypressEvent.mKeyCode = NS_VK_RETURN;
2726   } else {
2727     keypressEvent.mCharCode = static_cast<uint32_t>(aCharMsg.wParam);
2728   }
2729   nsresult rv = mDispatcher->BeginNativeInputTransaction();
2730   if (NS_WARN_IF(NS_FAILED(rv))) {
2731     MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
2732             ("%p   NativeKey::HandleCharMessage(), FAILED due to "
2733              "BeginNativeInputTransaction() failure",
2734              this));
2735     return true;
2736   }
2737 
2738   MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
2739           ("%p   NativeKey::HandleCharMessage(), initializing keypress "
2740            "event...",
2741            this));
2742 
2743   ModifierKeyState modKeyState(mModKeyState);
2744   // When AltGr is pressed, both Alt and Ctrl are active.  However, when they
2745   // are active, EditorBase won't treat the keypress event as inputting a
2746   // character.  Therefore, when AltGr is pressed and the key tries to input
2747   // a character, let's set them to false.
2748   if (modKeyState.IsAltGr() && IsPrintableCharMessage(aCharMsg)) {
2749     modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
2750   }
2751   nsEventStatus status = InitKeyEvent(keypressEvent, modKeyState, &aCharMsg);
2752   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2753           ("%p   NativeKey::HandleCharMessage(), dispatching keypress event...",
2754            this));
2755   bool dispatched = mDispatcher->MaybeDispatchKeypressEvents(
2756       keypressEvent, status, const_cast<NativeKey*>(this));
2757   if (aEventDispatched) {
2758     *aEventDispatched = dispatched;
2759   }
2760   if (mWidget->Destroyed()) {
2761     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2762             ("%p   NativeKey::HandleCharMessage(), keypress event caused "
2763              "destroying the widget",
2764              this));
2765     return true;
2766   }
2767   bool consumed = status == nsEventStatus_eConsumeNoDefault;
2768   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2769           ("%p   NativeKey::HandleCharMessage(), dispatched keypress event, "
2770            "dispatched=%s, consumed=%s",
2771            this, GetBoolName(dispatched), GetBoolName(consumed)));
2772   return consumed;
2773 }
2774 
HandleKeyUpMessage(bool * aEventDispatched) const2775 bool NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const {
2776   MOZ_ASSERT(IsKeyUpMessage());
2777 
2778   if (aEventDispatched) {
2779     *aEventDispatched = false;
2780   }
2781 
2782   // If the key combinations is reserved by the system, we shouldn't dispatch
2783   // eKeyUp event for it and passes the message to next wndproc.
2784   if (IsReservedBySystem()) {
2785     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2786             ("%p   NativeKey::HandleKeyUpMessage(), doesn't dispatch keyup "
2787              "event because the key combination is reserved by the system",
2788              this));
2789     return false;
2790   }
2791 
2792   // If the widget has gone, we should do nothing.
2793   if (mWidget->Destroyed()) {
2794     MOZ_LOG(
2795         sNativeKeyLogger, LogLevel::Warning,
2796         ("%p   NativeKey::HandleKeyUpMessage(), WARNING, not handled due to "
2797          "destroyed the widget",
2798          this));
2799     return false;
2800   }
2801 
2802   nsresult rv = mDispatcher->BeginNativeInputTransaction();
2803   if (NS_WARN_IF(NS_FAILED(rv))) {
2804     MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
2805             ("%p   NativeKey::HandleKeyUpMessage(), FAILED due to "
2806              "BeginNativeInputTransaction() failure",
2807              this));
2808     return true;
2809   }
2810 
2811   MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
2812           ("%p   NativeKey::HandleKeyUpMessage(), initializing keyup event...",
2813            this));
2814   EventMessage keyUpMessage = IsKeyMessageOnPlugin() ? eKeyUpOnPlugin : eKeyUp;
2815   WidgetKeyboardEvent keyupEvent(true, keyUpMessage, mWidget);
2816   nsEventStatus status = InitKeyEvent(keyupEvent, mModKeyState, &mMsg);
2817   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2818           ("%p   NativeKey::HandleKeyUpMessage(), dispatching keyup event...",
2819            this));
2820   bool dispatched = mDispatcher->DispatchKeyboardEvent(
2821       keyUpMessage, keyupEvent, status, const_cast<NativeKey*>(this));
2822   if (aEventDispatched) {
2823     *aEventDispatched = dispatched;
2824   }
2825   if (mWidget->Destroyed()) {
2826     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2827             ("%p   NativeKey::HandleKeyUpMessage(), keyup event caused "
2828              "destroying the widget",
2829              this));
2830     return true;
2831   }
2832   bool consumed = status == nsEventStatus_eConsumeNoDefault;
2833   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
2834           ("%p   NativeKey::HandleKeyUpMessage(), dispatched keyup event, "
2835            "dispatched=%s, consumed=%s",
2836            this, GetBoolName(dispatched), GetBoolName(consumed)));
2837   return consumed;
2838 }
2839 
NeedsToHandleWithoutFollowingCharMessages() const2840 bool NativeKey::NeedsToHandleWithoutFollowingCharMessages() const {
2841   MOZ_ASSERT(IsKeyDownMessage());
2842 
2843   // We cannot know following char messages of key messages in a plugin
2844   // process.  So, let's compute the character to be inputted with every
2845   // printable key should be computed with the keyboard layout.
2846   if (IsKeyMessageOnPlugin()) {
2847     return true;
2848   }
2849 
2850   // If the key combination is reserved by the system, the caller shouldn't
2851   // do anything with following WM_*CHAR messages.  So, let's return true here.
2852   if (IsReservedBySystem()) {
2853     return true;
2854   }
2855 
2856   // If the keydown message is generated for inputting some Unicode characters
2857   // via SendInput() API, we need to handle it only with WM_*CHAR messages.
2858   if (mVirtualKeyCode == VK_PACKET) {
2859     return false;
2860   }
2861 
2862   // If following char message is for a control character, it should be handled
2863   // without WM_CHAR message.  This is typically Ctrl + [a-z].
2864   if (mFollowingCharMsgs.Length() == 1 &&
2865       IsControlCharMessage(mFollowingCharMsgs[0])) {
2866     return true;
2867   }
2868 
2869   // If keydown message is followed by WM_CHAR or WM_SYSCHAR whose wParam isn't
2870   // a control character, we should dispatch keypress event with the char
2871   // message even with any modifier state.
2872   if (IsFollowedByPrintableCharOrSysCharMessage()) {
2873     return false;
2874   }
2875 
2876   // If any modifier keys which may cause printable keys becoming non-printable
2877   // are not pressed, we don't need special handling for the key.
2878   if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
2879       !mModKeyState.IsWin()) {
2880     return false;
2881   }
2882 
2883   // If the key event causes dead key event, we don't need to dispatch keypress
2884   // event.
2885   if (mIsDeadKey && mCommittedCharsAndModifiers.IsEmpty()) {
2886     return false;
2887   }
2888 
2889   // Even if the key is a printable key, it might cause non-printable character
2890   // input with modifier key(s).
2891   return mIsPrintableKey;
2892 }
2893 
GetResultOfInSendMessageEx()2894 static nsCString GetResultOfInSendMessageEx() {
2895   DWORD ret = ::InSendMessageEx(nullptr);
2896   if (!ret) {
2897     return NS_LITERAL_CSTRING("ISMEX_NOSEND");
2898   }
2899   nsAutoCString result;
2900   if (ret & ISMEX_CALLBACK) {
2901     result = "ISMEX_CALLBACK";
2902   }
2903   if (ret & ISMEX_NOTIFY) {
2904     if (!result.IsEmpty()) {
2905       result += " | ";
2906     }
2907     result += "ISMEX_NOTIFY";
2908   }
2909   if (ret & ISMEX_REPLIED) {
2910     if (!result.IsEmpty()) {
2911       result += " | ";
2912     }
2913     result += "ISMEX_REPLIED";
2914   }
2915   if (ret & ISMEX_SEND) {
2916     if (!result.IsEmpty()) {
2917       result += " | ";
2918     }
2919     result += "ISMEX_SEND";
2920   }
2921   return result;
2922 }
2923 
MayBeSameCharMessage(const MSG & aCharMsg1,const MSG & aCharMsg2) const2924 bool NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1,
2925                                      const MSG& aCharMsg2) const {
2926   // NOTE: Although, we don't know when this case occurs, the scan code value
2927   //       in lParam may be changed from 0 to something.  The changed value
2928   //       is different from the scan code of handling keydown message.
2929   static const LPARAM kScanCodeMask = 0x00FF0000;
2930   return aCharMsg1.message == aCharMsg2.message &&
2931          aCharMsg1.wParam == aCharMsg2.wParam &&
2932          (aCharMsg1.lParam & ~kScanCodeMask) ==
2933              (aCharMsg2.lParam & ~kScanCodeMask);
2934 }
2935 
IsSamePhysicalKeyMessage(const MSG & aKeyOrCharMsg1,const MSG & aKeyOrCharMsg2) const2936 bool NativeKey::IsSamePhysicalKeyMessage(const MSG& aKeyOrCharMsg1,
2937                                          const MSG& aKeyOrCharMsg2) const {
2938   if (NS_WARN_IF(aKeyOrCharMsg1.message < WM_KEYFIRST) ||
2939       NS_WARN_IF(aKeyOrCharMsg1.message > WM_KEYLAST) ||
2940       NS_WARN_IF(aKeyOrCharMsg2.message < WM_KEYFIRST) ||
2941       NS_WARN_IF(aKeyOrCharMsg2.message > WM_KEYLAST)) {
2942     return false;
2943   }
2944   return WinUtils::GetScanCode(aKeyOrCharMsg1.lParam) ==
2945              WinUtils::GetScanCode(aKeyOrCharMsg2.lParam) &&
2946          WinUtils::IsExtendedScanCode(aKeyOrCharMsg1.lParam) ==
2947              WinUtils::IsExtendedScanCode(aKeyOrCharMsg2.lParam);
2948 }
2949 
GetFollowingCharMessage(MSG & aCharMsg)2950 bool NativeKey::GetFollowingCharMessage(MSG& aCharMsg) {
2951   MOZ_ASSERT(IsKeyDownMessage());
2952   MOZ_ASSERT(!IsKeyMessageOnPlugin());
2953 
2954   aCharMsg.message = WM_NULL;
2955 
2956   if (mFakeCharMsgs) {
2957     for (size_t i = 0; i < mFakeCharMsgs->Length(); i++) {
2958       FakeCharMsg& fakeCharMsg = mFakeCharMsgs->ElementAt(i);
2959       if (fakeCharMsg.mConsumed) {
2960         continue;
2961       }
2962       MSG charMsg = fakeCharMsg.GetCharMsg(mMsg.hwnd);
2963       fakeCharMsg.mConsumed = true;
2964       if (!IsCharMessage(charMsg)) {
2965         return false;
2966       }
2967       aCharMsg = charMsg;
2968       return true;
2969     }
2970     return false;
2971   }
2972 
2973   // If next key message is not char message, we should give up to find a
2974   // related char message for the handling keydown event for now.
2975   // Note that it's possible other applications may send other key message
2976   // after we call TranslateMessage(). That may cause PeekMessage() failing
2977   // to get char message for the handling keydown message.
2978   MSG nextKeyMsg;
2979   if (!WinUtils::PeekMessage(&nextKeyMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
2980                              PM_NOREMOVE | PM_NOYIELD) ||
2981       !IsCharMessage(nextKeyMsg)) {
2982     MOZ_LOG(sNativeKeyLogger, LogLevel::Verbose,
2983             ("%p   NativeKey::GetFollowingCharMessage(), there are no char "
2984              "messages",
2985              this));
2986     return false;
2987   }
2988   const MSG kFoundCharMsg = nextKeyMsg;
2989 
2990   AutoRestore<MSG> saveLastRemovingMsg(mRemovingMsg);
2991   mRemovingMsg = nextKeyMsg;
2992 
2993   mReceivedMsg = sEmptyMSG;
2994   AutoRestore<MSG> ensureToClearRecivedMsg(mReceivedMsg);
2995 
2996   // On Metrofox, PeekMessage() sometimes returns WM_NULL even if we specify
2997   // the message range.  So, if it returns WM_NULL, we should retry to get
2998   // the following char message it was found above.
2999   for (uint32_t i = 0; i < 50; i++) {
3000     MSG removedMsg, nextKeyMsgInAllWindows;
3001     bool doCrash = false;
3002     if (!WinUtils::PeekMessage(&removedMsg, mMsg.hwnd, nextKeyMsg.message,
3003                                nextKeyMsg.message, PM_REMOVE | PM_NOYIELD)) {
3004       // We meets unexpected case.  We should collect the message queue state
3005       // and crash for reporting the bug.
3006       doCrash = true;
3007 
3008       // If another instance was created for the removing message during trying
3009       // to remove a char message, the instance didn't handle it for preventing
3010       // recursive handling.  So, let's handle it in this instance.
3011       if (!IsEmptyMSG(mReceivedMsg)) {
3012         // If focus is moved to different window, we shouldn't handle it on
3013         // the widget.  Let's discard it for now.
3014         if (mReceivedMsg.hwnd != nextKeyMsg.hwnd) {
3015           MOZ_LOG(
3016               sNativeKeyLogger, LogLevel::Warning,
3017               ("%p   NativeKey::GetFollowingCharMessage(), WARNING, received a "
3018                "char message during removing it from the queue, but it's for "
3019                "different window, mReceivedMsg=%s, nextKeyMsg=%s, "
3020                "kFoundCharMsg=%s",
3021                this, ToString(mReceivedMsg).get(), ToString(nextKeyMsg).get(),
3022                ToString(kFoundCharMsg).get()));
3023           // There might still exist char messages, the loop of calling
3024           // this method should be continued.
3025           aCharMsg.message = WM_NULL;
3026           return true;
3027         }
3028         // Even if the received message is different from what we tried to
3029         // remove from the queue, let's take the received message as a part of
3030         // the result of this key sequence.
3031         if (mReceivedMsg.message != nextKeyMsg.message ||
3032             mReceivedMsg.wParam != nextKeyMsg.wParam ||
3033             mReceivedMsg.lParam != nextKeyMsg.lParam) {
3034           MOZ_LOG(
3035               sNativeKeyLogger, LogLevel::Warning,
3036               ("%p   NativeKey::GetFollowingCharMessage(), WARNING, received a "
3037                "char message during removing it from the queue, but it's "
3038                "differnt from what trying to remove from the queue, "
3039                "aCharMsg=%s, nextKeyMsg=%s, kFoundCharMsg=%s",
3040                this, ToString(mReceivedMsg).get(), ToString(nextKeyMsg).get(),
3041                ToString(kFoundCharMsg).get()));
3042         } else {
3043           MOZ_LOG(sNativeKeyLogger, LogLevel::Verbose,
3044                   ("%p   NativeKey::GetFollowingCharMessage(), succeeded to "
3045                    "retrieve "
3046                    "next char message via another instance, aCharMsg=%s, "
3047                    "kFoundCharMsg=%s",
3048                    this, ToString(mReceivedMsg).get(),
3049                    ToString(kFoundCharMsg).get()));
3050         }
3051         aCharMsg = mReceivedMsg;
3052         return true;
3053       }
3054 
3055       // The char message is redirected to different thread's window by focus
3056       // move or something or just cancelled by external application.
3057       if (!WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0, WM_KEYFIRST,
3058                                  WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD)) {
3059         MOZ_LOG(
3060             sNativeKeyLogger, LogLevel::Warning,
3061             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3062              "remove a char message, but it's already gone from all message "
3063              "queues, nextKeyMsg=%s, kFoundCharMsg=%s",
3064              this, ToString(nextKeyMsg).get(), ToString(kFoundCharMsg).get()));
3065         return true;  // XXX should return false in this case
3066       }
3067       // The next key message is redirected to different window created by our
3068       // thread, we should do nothing because we must not have focus.
3069       if (nextKeyMsgInAllWindows.hwnd != mMsg.hwnd) {
3070         aCharMsg = nextKeyMsgInAllWindows;
3071         MOZ_LOG(
3072             sNativeKeyLogger, LogLevel::Warning,
3073             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3074              "remove a char message, but found in another message queue, "
3075              "nextKeyMsgInAllWindows=%s, nextKeyMsg=%s, kFoundCharMsg=%s",
3076              this, ToString(nextKeyMsgInAllWindows).get(),
3077              ToString(nextKeyMsg).get(), ToString(kFoundCharMsg).get()));
3078         return true;
3079       }
3080       // If next key message becomes non-char message, this key operation
3081       // may have already been consumed or canceled.
3082       if (!IsCharMessage(nextKeyMsgInAllWindows)) {
3083         MOZ_LOG(
3084             sNativeKeyLogger, LogLevel::Warning,
3085             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3086              "remove a char message and next key message becomes non-char "
3087              "message, nextKeyMsgInAllWindows=%s, nextKeyMsg=%s, "
3088              "kFoundCharMsg=%s",
3089              this, ToString(nextKeyMsgInAllWindows).get(),
3090              ToString(nextKeyMsg).get(), ToString(kFoundCharMsg).get()));
3091         MOZ_ASSERT(!mCharMessageHasGone);
3092         mFollowingCharMsgs.Clear();
3093         mCharMessageHasGone = true;
3094         return false;
3095       }
3096       // If next key message is still a char message but different key message,
3097       // we should treat current key operation is consumed or canceled and
3098       // next char message should be handled as an orphan char message later.
3099       if (!IsSamePhysicalKeyMessage(nextKeyMsgInAllWindows, kFoundCharMsg)) {
3100         MOZ_LOG(
3101             sNativeKeyLogger, LogLevel::Warning,
3102             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3103              "remove a char message and next key message becomes differnt "
3104              "key's "
3105              "char message, nextKeyMsgInAllWindows=%s, nextKeyMsg=%s, "
3106              "kFoundCharMsg=%s",
3107              this, ToString(nextKeyMsgInAllWindows).get(),
3108              ToString(nextKeyMsg).get(), ToString(kFoundCharMsg).get()));
3109         MOZ_ASSERT(!mCharMessageHasGone);
3110         mFollowingCharMsgs.Clear();
3111         mCharMessageHasGone = true;
3112         return false;
3113       }
3114       // If next key message is still a char message but the message is changed,
3115       // we should retry to remove the new message with PeekMessage() again.
3116       if (nextKeyMsgInAllWindows.message != nextKeyMsg.message) {
3117         MOZ_LOG(
3118             sNativeKeyLogger, LogLevel::Warning,
3119             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3120              "remove a char message due to message change, let's retry to "
3121              "remove the message with newly found char message, ",
3122              "nextKeyMsgInAllWindows=%s, nextKeyMsg=%s, kFoundCharMsg=%s", this,
3123              ToString(nextKeyMsgInAllWindows).get(), ToString(nextKeyMsg).get(),
3124              ToString(kFoundCharMsg).get()));
3125         nextKeyMsg = nextKeyMsgInAllWindows;
3126         continue;
3127       }
3128       // If there is still existing a char message caused by same physical key
3129       // in the queue but PeekMessage(PM_REMOVE) failed to remove it from the
3130       // queue, it might be possible that the odd keyboard layout or utility
3131       // hooks only PeekMessage(PM_NOREMOVE) and GetMessage().  So, let's try
3132       // remove the char message with GetMessage() again.
3133       // FYI: The wParam might be different from the found message, but it's
3134       //      okay because we assume that odd keyboard layouts return actual
3135       //      inputting character at removing the char message.
3136       if (WinUtils::GetMessage(&removedMsg, mMsg.hwnd, nextKeyMsg.message,
3137                                nextKeyMsg.message)) {
3138         MOZ_LOG(
3139             sNativeKeyLogger, LogLevel::Warning,
3140             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3141              "remove a char message, but succeeded with GetMessage(), "
3142              "removedMsg=%s, kFoundCharMsg=%s",
3143              this, ToString(removedMsg).get(), ToString(kFoundCharMsg).get()));
3144         // Cancel to crash, but we need to check the removed message value.
3145         doCrash = false;
3146       }
3147       // If we've already removed some WM_NULL messages from the queue and
3148       // the found message has already gone from the queue, let's treat the key
3149       // as inputting no characters and already consumed.
3150       else if (i > 0) {
3151         MOZ_LOG(
3152             sNativeKeyLogger, LogLevel::Warning,
3153             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3154              "remove a char message, but removed %d WM_NULL messages",
3155              this, i));
3156         // If the key is a printable key or a control key but tried to input
3157         // a character, mark mCharMessageHasGone true for handling the keydown
3158         // event as inputting empty string.
3159         MOZ_ASSERT(!mCharMessageHasGone);
3160         mFollowingCharMsgs.Clear();
3161         mCharMessageHasGone = true;
3162         return false;
3163       }
3164       MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
3165               ("%p   NativeKey::GetFollowingCharMessage(), FAILED, lost target "
3166                "message to remove, nextKeyMsg=%s",
3167                this, ToString(nextKeyMsg).get()));
3168     }
3169 
3170     if (doCrash) {
3171       nsPrintfCString info(
3172           "\nPeekMessage() failed to remove char message! "
3173           "\nActive keyboard layout=0x%08X (%s), "
3174           "\nHandling message: %s, InSendMessageEx()=%s, "
3175           "\nFound message: %s, "
3176           "\nWM_NULL has been removed: %d, "
3177           "\nNext key message in all windows: %s, "
3178           "time=%d, ",
3179           KeyboardLayout::GetActiveLayout(),
3180           KeyboardLayout::GetActiveLayoutName().get(), ToString(mMsg).get(),
3181           GetResultOfInSendMessageEx().get(), ToString(kFoundCharMsg).get(), i,
3182           ToString(nextKeyMsgInAllWindows).get(), nextKeyMsgInAllWindows.time);
3183       CrashReporter::AppendAppNotesToCrashReport(info);
3184       MSG nextMsg;
3185       if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD)) {
3186         nsPrintfCString info("\nNext message in all windows: %s, time=%d",
3187                              ToString(nextMsg).get(), nextMsg.time);
3188         CrashReporter::AppendAppNotesToCrashReport(info);
3189       } else {
3190         CrashReporter::AppendAppNotesToCrashReport(
3191             NS_LITERAL_CSTRING("\nThere is no message in any window"));
3192       }
3193 
3194       MOZ_CRASH("We lost the following char message");
3195     }
3196 
3197     // We're still not sure why ::PeekMessage() may return WM_NULL even with
3198     // its first message and its last message are same message.  However,
3199     // at developing Metrofox, we met this case even with usual keyboard
3200     // layouts.  So, it might be possible in desktop application or it really
3201     // occurs with some odd keyboard layouts which perhaps hook API.
3202     if (removedMsg.message == WM_NULL) {
3203       MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
3204               ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3205                "remove a char message, instead, removed WM_NULL message, ",
3206                "removedMsg=%s", this, ToString(removedMsg).get()));
3207       // Check if there is the message which we're trying to remove.
3208       MSG newNextKeyMsg;
3209       if (!WinUtils::PeekMessage(&newNextKeyMsg, mMsg.hwnd, WM_KEYFIRST,
3210                                  WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD)) {
3211         // If there is no key message, we should mark this keydown as consumed
3212         // because the key operation may have already been handled or canceled.
3213         MOZ_LOG(
3214             sNativeKeyLogger, LogLevel::Warning,
3215             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3216              "remove a char message because it's gone during removing it from "
3217              "the queue, nextKeyMsg=%s, kFoundCharMsg=%s",
3218              this, ToString(nextKeyMsg).get(), ToString(kFoundCharMsg).get()));
3219         MOZ_ASSERT(!mCharMessageHasGone);
3220         mFollowingCharMsgs.Clear();
3221         mCharMessageHasGone = true;
3222         return false;
3223       }
3224       if (!IsCharMessage(newNextKeyMsg)) {
3225         // If next key message becomes a non-char message, we should mark this
3226         // keydown as consumed because the key operation may have already been
3227         // handled or canceled.
3228         MOZ_LOG(
3229             sNativeKeyLogger, LogLevel::Warning,
3230             ("%p   NativeKey::GetFollowingCharMessage(), WARNING, failed to "
3231              "remove a char message because it's gone during removing it from "
3232              "the queue, nextKeyMsg=%s, newNextKeyMsg=%s, kFoundCharMsg=%s",
3233              this, ToString(nextKeyMsg).get(), ToString(newNextKeyMsg).get(),
3234              ToString(kFoundCharMsg).get()));
3235         MOZ_ASSERT(!mCharMessageHasGone);
3236         mFollowingCharMsgs.Clear();
3237         mCharMessageHasGone = true;
3238         return false;
3239       }
3240       MOZ_LOG(
3241           sNativeKeyLogger, LogLevel::Debug,
3242           ("%p   NativeKey::GetFollowingCharMessage(), there is the message "
3243            "which is being tried to be removed from the queue, trying again...",
3244            this));
3245       continue;
3246     }
3247 
3248     // Typically, this case occurs with WM_DEADCHAR.  If the removed message's
3249     // wParam becomes 0, that means that the key event shouldn't cause text
3250     // input.  So, let's ignore the strange char message.
3251     if (removedMsg.message == nextKeyMsg.message && !removedMsg.wParam) {
3252       MOZ_LOG(
3253           sNativeKeyLogger, LogLevel::Warning,
3254           ("%p   NativeKey::GetFollowingCharMessage(), WARNING, succeeded to "
3255            "remove a char message, but the removed message's wParam is 0, "
3256            "removedMsg=%s",
3257            this, ToString(removedMsg).get()));
3258       return false;
3259     }
3260 
3261     // This is normal case.
3262     if (MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
3263       aCharMsg = removedMsg;
3264       MOZ_LOG(
3265           sNativeKeyLogger, LogLevel::Verbose,
3266           ("%p   NativeKey::GetFollowingCharMessage(), succeeded to retrieve "
3267            "next char message, aCharMsg=%s",
3268            this, ToString(aCharMsg).get()));
3269       return true;
3270     }
3271 
3272     // Even if removed message is different char message from the found char
3273     // message, when the scan code is same, we can assume that the message
3274     // is overwritten by somebody who hooks API.  See bug 1336028 comment 0 for
3275     // the possible scenarios.
3276     if (IsCharMessage(removedMsg) &&
3277         IsSamePhysicalKeyMessage(removedMsg, nextKeyMsg)) {
3278       aCharMsg = removedMsg;
3279       MOZ_LOG(
3280           sNativeKeyLogger, LogLevel::Warning,
3281           ("%p   NativeKey::GetFollowingCharMessage(), WARNING, succeeded to "
3282            "remove a char message, but the removed message was changed from "
3283            "the found message except their scancode, aCharMsg=%s, "
3284            "nextKeyMsg=%s, kFoundCharMsg=%s",
3285            this, ToString(aCharMsg).get(), ToString(nextKeyMsg).get(),
3286            ToString(kFoundCharMsg).get()));
3287       return true;
3288     }
3289 
3290     // When found message's wParam is 0 and its scancode is 0xFF, we may remove
3291     // usual char message actually.  In such case, we should use the removed
3292     // char message.
3293     if (IsCharMessage(removedMsg) && !nextKeyMsg.wParam &&
3294         WinUtils::GetScanCode(nextKeyMsg.lParam) == 0xFF) {
3295       aCharMsg = removedMsg;
3296       MOZ_LOG(
3297           sNativeKeyLogger, LogLevel::Warning,
3298           ("%p   NativeKey::GetFollowingCharMessage(), WARNING, succeeded to "
3299            "remove a char message, but the removed message was changed from "
3300            "the found message but the found message was odd, so, ignoring the "
3301            "odd found message and respecting the removed message, aCharMsg=%s, "
3302            "nextKeyMsg=%s, kFoundCharMsg=%s",
3303            this, ToString(aCharMsg).get(), ToString(nextKeyMsg).get(),
3304            ToString(kFoundCharMsg).get()));
3305       return true;
3306     }
3307 
3308     // NOTE: Although, we don't know when this case occurs, the scan code value
3309     //       in lParam may be changed from 0 to something.  The changed value
3310     //       is different from the scan code of handling keydown message.
3311     MOZ_LOG(
3312         sNativeKeyLogger, LogLevel::Error,
3313         ("%p   NativeKey::GetFollowingCharMessage(), FAILED, removed message "
3314          "is really different from what we have already found, removedMsg=%s, "
3315          "nextKeyMsg=%s, kFoundCharMsg=%s",
3316          this, ToString(removedMsg).get(), ToString(nextKeyMsg).get(),
3317          ToString(kFoundCharMsg).get()));
3318     nsPrintfCString info(
3319         "\nPeekMessage() removed unexpcted char message! "
3320         "\nActive keyboard layout=0x%08X (%s), "
3321         "\nHandling message: %s, InSendMessageEx()=%s, "
3322         "\nFound message: %s, "
3323         "\nRemoved message: %s, ",
3324         KeyboardLayout::GetActiveLayout(),
3325         KeyboardLayout::GetActiveLayoutName().get(), ToString(mMsg).get(),
3326         GetResultOfInSendMessageEx().get(), ToString(kFoundCharMsg).get(),
3327         ToString(removedMsg).get());
3328     CrashReporter::AppendAppNotesToCrashReport(info);
3329     // What's the next key message?
3330     MSG nextKeyMsgAfter;
3331     if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd, WM_KEYFIRST,
3332                               WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD)) {
3333       nsPrintfCString info(
3334           "\nNext key message after unexpected char message "
3335           "removed: %s, ",
3336           ToString(nextKeyMsgAfter).get());
3337       CrashReporter::AppendAppNotesToCrashReport(info);
3338     } else {
3339       CrashReporter::AppendAppNotesToCrashReport(
3340           NS_LITERAL_CSTRING("\nThere is no key message after unexpected char "
3341                              "message removed, "));
3342     }
3343     // Another window has a key message?
3344     if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0, WM_KEYFIRST,
3345                               WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD)) {
3346       nsPrintfCString info("\nNext key message in all windows: %s.",
3347                            ToString(nextKeyMsgInAllWindows).get());
3348       CrashReporter::AppendAppNotesToCrashReport(info);
3349     } else {
3350       CrashReporter::AppendAppNotesToCrashReport(
3351           NS_LITERAL_CSTRING("\nThere is no key message in any windows."));
3352     }
3353 
3354     MOZ_CRASH("PeekMessage() removed unexpected message");
3355   }
3356   MOZ_LOG(
3357       sNativeKeyLogger, LogLevel::Error,
3358       ("%p   NativeKey::GetFollowingCharMessage(), FAILED, removed messages "
3359        "are all WM_NULL, nextKeyMsg=%s",
3360        this, ToString(nextKeyMsg).get()));
3361   nsPrintfCString info(
3362       "\nWe lost following char message! "
3363       "\nActive keyboard layout=0x%08X (%s), "
3364       "\nHandling message: %s, InSendMessageEx()=%s, \n"
3365       "Found message: %s, removed a lot of WM_NULL",
3366       KeyboardLayout::GetActiveLayout(),
3367       KeyboardLayout::GetActiveLayoutName().get(), ToString(mMsg).get(),
3368       GetResultOfInSendMessageEx().get(), ToString(kFoundCharMsg).get());
3369   CrashReporter::AppendAppNotesToCrashReport(info);
3370   MOZ_CRASH("We lost the following char message");
3371   return false;
3372 }
3373 
MaybeDispatchPluginEventsForRemovedCharMessages() const3374 bool NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages() const {
3375   MOZ_ASSERT(IsKeyDownMessage());
3376   MOZ_ASSERT(!IsKeyMessageOnPlugin());
3377 
3378   for (size_t i = 0;
3379        i < mFollowingCharMsgs.Length() && mWidget->ShouldDispatchPluginEvent();
3380        ++i) {
3381     MOZ_LOG(
3382         sNativeKeyLogger, LogLevel::Info,
3383         ("%p   NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages(), "
3384          "dispatching %uth plugin event for %s...",
3385          this, i + 1, ToString(mFollowingCharMsgs[i]).get()));
3386     MOZ_RELEASE_ASSERT(
3387         !mWidget->Destroyed(),
3388         "NativeKey tries to dispatch a plugin event on destroyed widget");
3389     mWidget->DispatchPluginEvent(mFollowingCharMsgs[i]);
3390     if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
3391       MOZ_LOG(
3392           sNativeKeyLogger, LogLevel::Info,
3393           ("%p   NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages(), "
3394            "%uth plugin event caused %s",
3395            this, i + 1,
3396            mWidget->Destroyed() ? "destroying the widget" : "focus change"));
3397       return true;
3398     }
3399     MOZ_LOG(
3400         sNativeKeyLogger, LogLevel::Info,
3401         ("%p   NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages(), "
3402          "dispatched %uth plugin event",
3403          this, i + 1));
3404   }
3405 
3406   // Dispatch odd char messages which are caused by ATOK or WXG (both of them
3407   // are Japanese IME) and removed by RemoveFollowingOddCharMessages().
3408   for (size_t i = 0;
3409        i < mRemovedOddCharMsgs.Length() && mWidget->ShouldDispatchPluginEvent();
3410        ++i) {
3411     MOZ_LOG(
3412         sNativeKeyLogger, LogLevel::Info,
3413         ("%p   NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages(), "
3414          "dispatching %uth plugin event for odd char message, %s...",
3415          this, i + 1, ToString(mFollowingCharMsgs[i]).get()));
3416     MOZ_RELEASE_ASSERT(
3417         !mWidget->Destroyed(),
3418         "NativeKey tries to dispatch a plugin event on destroyed widget");
3419     mWidget->DispatchPluginEvent(mRemovedOddCharMsgs[i]);
3420     if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
3421       MOZ_LOG(
3422           sNativeKeyLogger, LogLevel::Info,
3423           ("%p   NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages(), "
3424            "%uth plugin event for odd char message caused %s",
3425            this, i + 1,
3426            mWidget->Destroyed() ? "destroying the widget" : "focus change"));
3427       return true;
3428     }
3429     MOZ_LOG(
3430         sNativeKeyLogger, LogLevel::Info,
3431         ("%p   NativeKey::MaybeDispatchPluginEventsForRemovedCharMessages(), "
3432          "dispatched %uth plugin event for odd char message",
3433          this, i + 1));
3434   }
3435 
3436   return false;
3437 }
3438 
ComputeInputtingStringWithKeyboardLayout()3439 void NativeKey::ComputeInputtingStringWithKeyboardLayout() {
3440   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
3441 
3442   if (KeyboardLayout::IsPrintableCharKey(mVirtualKeyCode) ||
3443       mCharMessageHasGone) {
3444     mInputtingStringAndModifiers = mCommittedCharsAndModifiers;
3445   } else {
3446     mInputtingStringAndModifiers.Clear();
3447   }
3448   mShiftedString.Clear();
3449   mUnshiftedString.Clear();
3450   mShiftedLatinChar = mUnshiftedLatinChar = 0;
3451 
3452   // XXX How about when Win key is pressed?
3453   if (mModKeyState.IsControl() == mModKeyState.IsAlt()) {
3454     return;
3455   }
3456 
3457   ModifierKeyState capsLockState(mModKeyState.GetModifiers() &
3458                                  MODIFIER_CAPSLOCK);
3459 
3460   mUnshiftedString =
3461       keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
3462   capsLockState.Set(MODIFIER_SHIFT);
3463   mShiftedString =
3464       keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
3465 
3466   // The current keyboard cannot input alphabets or numerics,
3467   // we should append them for Shortcut/Access keys.
3468   // E.g., for Cyrillic keyboard layout.
3469   capsLockState.Unset(MODIFIER_SHIFT);
3470   WidgetUtils::GetLatinCharCodeForKeyCode(
3471       mDOMKeyCode, capsLockState.GetModifiers(), &mUnshiftedLatinChar,
3472       &mShiftedLatinChar);
3473 
3474   // If the mShiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
3475   if (mShiftedLatinChar) {
3476     // If the produced characters of the key on current keyboard layout
3477     // are same as computed Latin characters, we shouldn't append the
3478     // Latin characters to alternativeCharCode.
3479     if (mUnshiftedLatinChar == mUnshiftedString.CharAt(0) &&
3480         mShiftedLatinChar == mShiftedString.CharAt(0)) {
3481       mShiftedLatinChar = mUnshiftedLatinChar = 0;
3482     }
3483   } else if (mUnshiftedLatinChar) {
3484     // If the mShiftedLatinChar is 0, the mKeyCode doesn't produce
3485     // alphabet character.  At that time, the character may be produced
3486     // with Shift key.  E.g., on French keyboard layout, NS_VK_PERCENT
3487     // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
3488     // Shift key but with Shift key, it produces '%'.
3489     // If the mUnshiftedLatinChar is produced by the key on current
3490     // keyboard layout, we shouldn't append it to alternativeCharCode.
3491     if (mUnshiftedLatinChar == mUnshiftedString.CharAt(0) ||
3492         mUnshiftedLatinChar == mShiftedString.CharAt(0)) {
3493       mUnshiftedLatinChar = 0;
3494     }
3495   }
3496 
3497   if (!mModKeyState.IsControl()) {
3498     return;
3499   }
3500 
3501   // If the mCharCode is not ASCII character, we should replace the
3502   // mCharCode with ASCII character only when Ctrl is pressed.
3503   // But don't replace the mCharCode when the mCharCode is not same as
3504   // unmodified characters. In such case, Ctrl is sometimes used for a
3505   // part of character inputting key combination like Shift.
3506   uint32_t ch =
3507       mModKeyState.IsShift() ? mShiftedLatinChar : mUnshiftedLatinChar;
3508   if (!ch) {
3509     return;
3510   }
3511   if (mInputtingStringAndModifiers.IsEmpty() ||
3512       mInputtingStringAndModifiers.UniCharsCaseInsensitiveEqual(
3513           mModKeyState.IsShift() ? mShiftedString : mUnshiftedString)) {
3514     mInputtingStringAndModifiers.Clear();
3515     mInputtingStringAndModifiers.Append(ch, mModKeyState.GetModifiers());
3516   }
3517 }
3518 
DispatchKeyPressEventsWithRetrievedCharMessages() const3519 bool NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages() const {
3520   MOZ_ASSERT(IsKeyDownMessage());
3521   MOZ_ASSERT(IsFollowedByPrintableCharOrSysCharMessage());
3522   MOZ_ASSERT(!mWidget->Destroyed());
3523 
3524   nsresult rv = mDispatcher->BeginNativeInputTransaction();
3525   if (NS_WARN_IF(NS_FAILED(rv))) {
3526     MOZ_LOG(
3527         sNativeKeyLogger, LogLevel::Error,
3528         ("%p   NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages(), "
3529          "FAILED due to BeginNativeInputTransaction() failure",
3530          this));
3531     return true;
3532   }
3533   WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget);
3534   MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
3535           ("%p   NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages(), "
3536            "initializing keypress event...",
3537            this));
3538   ModifierKeyState modKeyState(mModKeyState);
3539   if (mCanIgnoreModifierStateAtKeyPress && IsFollowedByPrintableCharMessage()) {
3540     // If eKeyPress event should cause inputting text in focused editor,
3541     // we need to remove Alt and Ctrl state.
3542     modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
3543   }
3544   // We don't need to send char message here if there are two or more retrieved
3545   // messages because we need to set each message to each eKeyPress event.
3546   bool needsCallback = mFollowingCharMsgs.Length() > 1;
3547   nsEventStatus status =
3548       InitKeyEvent(keypressEvent, modKeyState,
3549                    !needsCallback ? &mFollowingCharMsgs[0] : nullptr);
3550   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3551           ("%p   NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages(), "
3552            "dispatching keypress event(s)...",
3553            this));
3554   bool dispatched = mDispatcher->MaybeDispatchKeypressEvents(
3555       keypressEvent, status, const_cast<NativeKey*>(this), needsCallback);
3556   if (mWidget->Destroyed()) {
3557     MOZ_LOG(
3558         sNativeKeyLogger, LogLevel::Info,
3559         ("%p   NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages(), "
3560          "keypress event(s) caused destroying the widget",
3561          this));
3562     return true;
3563   }
3564   bool consumed = status == nsEventStatus_eConsumeNoDefault;
3565   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3566           ("%p   NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages(), "
3567            "dispatched keypress event(s), dispatched=%s, consumed=%s",
3568            this, GetBoolName(dispatched), GetBoolName(consumed)));
3569   return consumed;
3570 }
3571 
DispatchKeyPressEventsWithoutCharMessage() const3572 bool NativeKey::DispatchKeyPressEventsWithoutCharMessage() const {
3573   MOZ_ASSERT(IsKeyDownMessage());
3574   MOZ_ASSERT(!mIsDeadKey || !mCommittedCharsAndModifiers.IsEmpty());
3575   MOZ_ASSERT(!mWidget->Destroyed());
3576 
3577   nsresult rv = mDispatcher->BeginNativeInputTransaction();
3578   if (NS_WARN_IF(NS_FAILED(rv))) {
3579     MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
3580             ("%p   NativeKey::DispatchKeyPressEventsWithoutCharMessage(), "
3581              "FAILED due "
3582              "to BeginNativeInputTransaction() failure",
3583              this));
3584     return true;
3585   }
3586 
3587   WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget);
3588   if (mInputtingStringAndModifiers.IsEmpty() && mShiftedString.IsEmpty() &&
3589       mUnshiftedString.IsEmpty()) {
3590     keypressEvent.mKeyCode = mDOMKeyCode;
3591   }
3592   MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
3593           ("%p   NativeKey::DispatchKeyPressEventsWithoutCharMessage(), "
3594            "initializing "
3595            "keypress event...",
3596            this));
3597   nsEventStatus status = InitKeyEvent(keypressEvent, mModKeyState);
3598   MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3599           ("%p   NativeKey::DispatchKeyPressEventsWithoutCharMessage(), "
3600            "dispatching "
3601            "keypress event(s)...",
3602            this));
3603   bool dispatched = mDispatcher->MaybeDispatchKeypressEvents(
3604       keypressEvent, status, const_cast<NativeKey*>(this));
3605   if (mWidget->Destroyed()) {
3606     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3607             ("%p   NativeKey::DispatchKeyPressEventsWithoutCharMessage(), "
3608              "keypress event(s) caused destroying the widget",
3609              this));
3610     return true;
3611   }
3612   bool consumed = status == nsEventStatus_eConsumeNoDefault;
3613   MOZ_LOG(
3614       sNativeKeyLogger, LogLevel::Info,
3615       ("%p   NativeKey::DispatchKeyPressEventsWithoutCharMessage(), dispatched "
3616        "keypress event(s), dispatched=%s, consumed=%s",
3617        this, GetBoolName(dispatched), GetBoolName(consumed)));
3618   return consumed;
3619 }
3620 
WillDispatchKeyboardEvent(WidgetKeyboardEvent & aKeyboardEvent,uint32_t aIndex)3621 void NativeKey::WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent,
3622                                           uint32_t aIndex) {
3623   // If it's an eKeyPress event and it's generated from retrieved char message,
3624   // we need to set raw message information for plugins.
3625   if (aKeyboardEvent.mMessage == eKeyPress &&
3626       IsFollowedByPrintableCharOrSysCharMessage()) {
3627     MOZ_RELEASE_ASSERT(aIndex < mCommittedCharsAndModifiers.Length());
3628     uint32_t foundPrintableCharMessages = 0;
3629     for (size_t i = 0; i < mFollowingCharMsgs.Length(); ++i) {
3630       if (!IsPrintableCharOrSysCharMessage(mFollowingCharMsgs[i])) {
3631         // XXX Should we dispatch a plugin event for WM_*DEADCHAR messages and
3632         //     WM_CHAR with a control character here?  But we're not sure
3633         //     how can we create such message queue (i.e., WM_CHAR or
3634         //     WM_SYSCHAR with a printable character and such message are
3635         //     generated by a keydown).  So, let's ignore such case until
3636         //     we'd get some bug reports.
3637         MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
3638                 ("%p   NativeKey::WillDispatchKeyboardEvent(), WARNING, "
3639                  "ignoring %uth message due to non-printable char message, %s",
3640                  this, i + 1, ToString(mFollowingCharMsgs[i]).get()));
3641         continue;
3642       }
3643       if (foundPrintableCharMessages++ == aIndex) {
3644         // Found message which caused the eKeyPress event.  Let's set the
3645         // message for plugin if it's necessary.
3646         MaybeInitPluginEventOfKeyEvent(aKeyboardEvent, mFollowingCharMsgs[i]);
3647         break;
3648       }
3649     }
3650     // Set modifier state from mCommittedCharsAndModifiers because some of them
3651     // might be different.  For example, Shift key was pressed at inputting
3652     // dead char but Shift key was released before inputting next character.
3653     if (mCanIgnoreModifierStateAtKeyPress) {
3654       ModifierKeyState modKeyState(mModKeyState);
3655       modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT |
3656                         MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK);
3657       modKeyState.Set(mCommittedCharsAndModifiers.ModifiersAt(aIndex));
3658       modKeyState.InitInputEvent(aKeyboardEvent);
3659       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3660               ("%p   NativeKey::WillDispatchKeyboardEvent(), "
3661                "setting %uth modifier state to %s",
3662                this, aIndex + 1, ToString(modKeyState).get()));
3663     }
3664   }
3665   size_t longestLength =
3666       std::max(mInputtingStringAndModifiers.Length(),
3667                std::max(mShiftedString.Length(), mUnshiftedString.Length()));
3668   size_t skipUniChars = longestLength - mInputtingStringAndModifiers.Length();
3669   size_t skipShiftedChars = longestLength - mShiftedString.Length();
3670   size_t skipUnshiftedChars = longestLength - mUnshiftedString.Length();
3671   if (aIndex >= longestLength) {
3672     MOZ_LOG(
3673         sNativeKeyLogger, LogLevel::Info,
3674         ("%p   NativeKey::WillDispatchKeyboardEvent(), does nothing for %uth "
3675          "%s event",
3676          this, aIndex + 1, ToChar(aKeyboardEvent.mMessage)));
3677     return;
3678   }
3679 
3680   // Check if aKeyboardEvent is the last event for a key press.
3681   // So, if it's not an eKeyPress event, it's always the last event.
3682   // Otherwise, check if the index is the last character of
3683   // mCommittedCharsAndModifiers.
3684   bool isLastIndex = aKeyboardEvent.mMessage != eKeyPress ||
3685                      mCommittedCharsAndModifiers.IsEmpty() ||
3686                      mCommittedCharsAndModifiers.Length() - 1 == aIndex;
3687 
3688   nsTArray<AlternativeCharCode>& altArray =
3689       aKeyboardEvent.mAlternativeCharCodes;
3690 
3691   // Set charCode and adjust modifier state for every eKeyPress event.
3692   // This is not necessary for the other keyboard events because the other
3693   // keyboard events shouldn't have non-zero charCode value and should have
3694   // current modifier state.
3695   if (aKeyboardEvent.mMessage == eKeyPress && skipUniChars <= aIndex) {
3696     // XXX Modifying modifier state of aKeyboardEvent is illegal, but no way
3697     //     to set different modifier state per keypress event except this
3698     //     hack.  Note that ideally, dead key should cause composition events
3699     //     instead of keypress events, though.
3700     if (aIndex - skipUniChars < mInputtingStringAndModifiers.Length()) {
3701       ModifierKeyState modKeyState(mModKeyState);
3702       // If key in combination with Alt and/or Ctrl produces a different
3703       // character than without them then do not report these flags
3704       // because it is separate keyboard layout shift state. If dead-key
3705       // and base character does not produce a valid composite character
3706       // then both produced dead-key character and following base
3707       // character may have different modifier flags, too.
3708       modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT |
3709                         MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK);
3710       modKeyState.Set(
3711           mInputtingStringAndModifiers.ModifiersAt(aIndex - skipUniChars));
3712       modKeyState.InitInputEvent(aKeyboardEvent);
3713       MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3714               ("%p   NativeKey::WillDispatchKeyboardEvent(), "
3715                "setting %uth modifier state to %s",
3716                this, aIndex + 1, ToString(modKeyState).get()));
3717     }
3718     uint16_t uniChar =
3719         mInputtingStringAndModifiers.CharAt(aIndex - skipUniChars);
3720 
3721     // The mCharCode was set from mKeyValue. However, for example, when Ctrl key
3722     // is pressed, its value should indicate an ASCII character for backward
3723     // compatibility rather than inputting character without the modifiers.
3724     // Therefore, we need to modify mCharCode value here.
3725     aKeyboardEvent.SetCharCode(uniChar);
3726     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
3727             ("%p   NativeKey::WillDispatchKeyboardEvent(), "
3728              "setting %uth charCode to %s",
3729              this, aIndex + 1, GetCharacterCodeName(uniChar).get()));
3730   }
3731 
3732   // We need to append alterntaive charCode values:
3733   //   - if the event is eKeyPress, we need to append for the index because
3734   //     eKeyPress event is dispatched for every character inputted by a
3735   //     key press.
3736   //   - if the event is not eKeyPress, we need to append for all characters
3737   //     inputted by the key press because the other keyboard events (e.g.,
3738   //     eKeyDown are eKeyUp) are fired only once for a key press.
3739   size_t count;
3740   if (aKeyboardEvent.mMessage == eKeyPress) {
3741     // Basically, append alternative charCode values only for the index.
3742     count = 1;
3743     // However, if it's the last eKeyPress event but different shift state
3744     // can input longer string, the last eKeyPress event should have all
3745     // remaining alternative charCode values.
3746     if (isLastIndex) {
3747       count = longestLength - aIndex;
3748     }
3749   } else {
3750     count = longestLength;
3751   }
3752   for (size_t i = 0; i < count; ++i) {
3753     uint16_t shiftedChar = 0, unshiftedChar = 0;
3754     if (skipShiftedChars <= aIndex + i) {
3755       shiftedChar = mShiftedString.CharAt(aIndex + i - skipShiftedChars);
3756     }
3757     if (skipUnshiftedChars <= aIndex + i) {
3758       unshiftedChar = mUnshiftedString.CharAt(aIndex + i - skipUnshiftedChars);
3759     }
3760 
3761     if (shiftedChar || unshiftedChar) {
3762       AlternativeCharCode chars(unshiftedChar, shiftedChar);
3763       altArray.AppendElement(chars);
3764     }
3765 
3766     if (!isLastIndex) {
3767       continue;
3768     }
3769 
3770     if (mUnshiftedLatinChar || mShiftedLatinChar) {
3771       AlternativeCharCode chars(mUnshiftedLatinChar, mShiftedLatinChar);
3772       altArray.AppendElement(chars);
3773     }
3774 
3775     // Typically, following virtual keycodes are used for a key which can
3776     // input the character.  However, these keycodes are also used for
3777     // other keys on some keyboard layout.  E.g., in spite of Shift+'1'
3778     // inputs '+' on Thai keyboard layout, a key which is at '=/+'
3779     // key on ANSI keyboard layout is VK_OEM_PLUS.  Native applications
3780     // handle it as '+' key if Ctrl key is pressed.
3781     char16_t charForOEMKeyCode = 0;
3782     switch (mVirtualKeyCode) {
3783       case VK_OEM_PLUS:
3784         charForOEMKeyCode = '+';
3785         break;
3786       case VK_OEM_COMMA:
3787         charForOEMKeyCode = ',';
3788         break;
3789       case VK_OEM_MINUS:
3790         charForOEMKeyCode = '-';
3791         break;
3792       case VK_OEM_PERIOD:
3793         charForOEMKeyCode = '.';
3794         break;
3795     }
3796     if (charForOEMKeyCode && charForOEMKeyCode != mUnshiftedString.CharAt(0) &&
3797         charForOEMKeyCode != mShiftedString.CharAt(0) &&
3798         charForOEMKeyCode != mUnshiftedLatinChar &&
3799         charForOEMKeyCode != mShiftedLatinChar) {
3800       AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
3801       altArray.AppendElement(OEMChars);
3802     }
3803   }
3804 }
3805 
3806 /*****************************************************************************
3807  * mozilla::widget::KeyboardLayout
3808  *****************************************************************************/
3809 
3810 KeyboardLayout* KeyboardLayout::sInstance = nullptr;
3811 nsIIdleServiceInternal* KeyboardLayout::sIdleService = nullptr;
3812 
3813 // This log is very noisy if you don't want to retrieve the mapping table
3814 // of specific keyboard layout.  LogLevel::Debug and LogLevel::Verbose are
3815 // used to log the layout mapping.  If you need to log some behavior of
3816 // KeyboardLayout class, you should use LogLevel::Info or lower level.
3817 LazyLogModule sKeyboardLayoutLogger("KeyboardLayoutWidgets");
3818 
3819 // static
GetInstance()3820 KeyboardLayout* KeyboardLayout::GetInstance() {
3821   if (!sInstance) {
3822     sInstance = new KeyboardLayout();
3823     nsCOMPtr<nsIIdleServiceInternal> idleService =
3824         do_GetService("@mozilla.org/widget/idleservice;1");
3825     // The refcount will be decreased at shut down.
3826     sIdleService = idleService.forget().take();
3827   }
3828   return sInstance;
3829 }
3830 
3831 // static
Shutdown()3832 void KeyboardLayout::Shutdown() {
3833   delete sInstance;
3834   sInstance = nullptr;
3835   NS_IF_RELEASE(sIdleService);
3836 }
3837 
3838 // static
NotifyIdleServiceOfUserActivity()3839 void KeyboardLayout::NotifyIdleServiceOfUserActivity() {
3840   sIdleService->ResetIdleTimeOut(0);
3841 }
3842 
KeyboardLayout()3843 KeyboardLayout::KeyboardLayout()
3844     : mKeyboardLayout(0),
3845       mIsOverridden(false),
3846       mIsPendingToRestoreKeyboardLayout(false) {
3847   mDeadKeyTableListHead = nullptr;
3848   // A dead key sequence should be made from up to 5 keys.  Therefore, 4 is
3849   // enough and makes sense because the item is uint8_t.
3850   // (Although, even if it's possible to be 6 keys or more in a sequence,
3851   // this array will be re-allocated).
3852   mActiveDeadKeys.SetCapacity(4);
3853   mDeadKeyShiftStates.SetCapacity(4);
3854 
3855   // NOTE: LoadLayout() should be called via OnLayoutChange().
3856 }
3857 
~KeyboardLayout()3858 KeyboardLayout::~KeyboardLayout() { ReleaseDeadKeyTables(); }
3859 
IsPrintableCharKey(uint8_t aVirtualKey)3860 bool KeyboardLayout::IsPrintableCharKey(uint8_t aVirtualKey) {
3861   return GetKeyIndex(aVirtualKey) >= 0;
3862 }
3863 
ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const3864 WORD KeyboardLayout::ComputeScanCodeForVirtualKeyCode(
3865     uint8_t aVirtualKeyCode) const {
3866   return static_cast<WORD>(
3867       ::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC, GetLayout()));
3868 }
3869 
IsDeadKey(uint8_t aVirtualKey,const ModifierKeyState & aModKeyState) const3870 bool KeyboardLayout::IsDeadKey(uint8_t aVirtualKey,
3871                                const ModifierKeyState& aModKeyState) const {
3872   int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey);
3873 
3874   // XXX KeyboardLayout class doesn't support unusual keyboard layout which
3875   //     maps some function keys as dead keys.
3876   if (virtualKeyIndex < 0) {
3877     return false;
3878   }
3879 
3880   return mVirtualKeys[virtualKeyIndex].IsDeadKey(
3881       VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
3882 }
3883 
IsSysKey(uint8_t aVirtualKey,const ModifierKeyState & aModKeyState) const3884 bool KeyboardLayout::IsSysKey(uint8_t aVirtualKey,
3885                               const ModifierKeyState& aModKeyState) const {
3886   // If Alt key is not pressed, it's never a system key combination.
3887   // Additionally, if Ctrl key is pressed, it's never a system key combination
3888   // too.
3889   // FYI: Windows logo key state won't affect if it's a system key.
3890   if (!aModKeyState.IsAlt() || aModKeyState.IsControl()) {
3891     return false;
3892   }
3893 
3894   int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey);
3895   if (virtualKeyIndex < 0) {
3896     return true;
3897   }
3898 
3899   UniCharsAndModifiers inputCharsAndModifiers =
3900       GetUniCharsAndModifiers(aVirtualKey, aModKeyState);
3901   if (inputCharsAndModifiers.IsEmpty()) {
3902     return true;
3903   }
3904 
3905   // If the Alt key state isn't consumed, that means that the key with Alt
3906   // doesn't cause text input.  So, the combination is a system key.
3907   return !!(inputCharsAndModifiers.ModifiersAt(0) & MODIFIER_ALT);
3908 }
3909 
InitNativeKey(NativeKey & aNativeKey,const ModifierKeyState & aModKeyState)3910 void KeyboardLayout::InitNativeKey(NativeKey& aNativeKey,
3911                                    const ModifierKeyState& aModKeyState) {
3912   if (mIsPendingToRestoreKeyboardLayout) {
3913     LoadLayout(::GetKeyboardLayout(0));
3914   }
3915 
3916   // If the aNativeKey is initialized with WM_CHAR, the key information
3917   // should be discarded because mKeyValue should have the string to be
3918   // inputted.
3919   if (aNativeKey.mMsg.message == WM_CHAR) {
3920     char16_t ch = static_cast<char16_t>(aNativeKey.mMsg.wParam);
3921     // But don't set key value as printable key if the character is a control
3922     // character such as 0x0D at pressing Enter key.
3923     if (!NativeKey::IsControlChar(ch)) {
3924       aNativeKey.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
3925       Modifiers modifiers =
3926           aModKeyState.GetModifiers() & ~(MODIFIER_ALT | MODIFIER_CONTROL);
3927       aNativeKey.mCommittedCharsAndModifiers.Append(ch, modifiers);
3928       return;
3929     }
3930   }
3931 
3932   // When it's followed by non-dead char message(s) for printable character(s),
3933   // aNativeKey should dispatch eKeyPress events for them rather than
3934   // information from keyboard layout because respecting WM_(SYS)CHAR messages
3935   // guarantees that we can always input characters which is expected by
3936   // the user even if the user uses odd keyboard layout.
3937   // Or, when it was followed by non-dead char message for a printable character
3938   // but it's gone at removing the message from the queue, let's treat it
3939   // as a key inputting empty string.
3940   if (aNativeKey.IsFollowedByPrintableCharOrSysCharMessage() ||
3941       aNativeKey.mCharMessageHasGone) {
3942     MOZ_ASSERT(!aNativeKey.IsCharMessage(aNativeKey.mMsg));
3943     if (aNativeKey.IsFollowedByPrintableCharOrSysCharMessage()) {
3944       // Initialize mCommittedCharsAndModifiers with following char messages.
3945       aNativeKey.InitCommittedCharsAndModifiersWithFollowingCharMessages(
3946           aModKeyState);
3947       MOZ_ASSERT(!aNativeKey.mCommittedCharsAndModifiers.IsEmpty());
3948 
3949       // Currently, we are doing a ugly hack to keypress events to cause
3950       // inputting character even if Ctrl or Alt key is pressed, that is, we
3951       // remove Ctrl and Alt modifier state from keypress event.  However, for
3952       // example, Ctrl+Space which causes ' ' of WM_CHAR message never causes
3953       // keypress event whose ctrlKey is true.  For preventing this problem,
3954       // we should mark as not removable if Ctrl or Alt key does not cause
3955       // changing inputting character.
3956       if (IsPrintableCharKey(aNativeKey.mOriginalVirtualKeyCode) &&
3957           !aModKeyState.IsAltGr() &&
3958           (aModKeyState.IsControl() || aModKeyState.IsAlt())) {
3959         ModifierKeyState state = aModKeyState;
3960         state.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
3961         UniCharsAndModifiers charsWithoutModifier =
3962             GetUniCharsAndModifiers(aNativeKey.mOriginalVirtualKeyCode, state);
3963         aNativeKey.mCanIgnoreModifierStateAtKeyPress =
3964             !charsWithoutModifier.UniCharsEqual(
3965                 aNativeKey.mCommittedCharsAndModifiers);
3966       }
3967     } else {
3968       aNativeKey.mCommittedCharsAndModifiers.Clear();
3969     }
3970     aNativeKey.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
3971 
3972     // If it's not in dead key sequence, we don't need to do anymore here.
3973     if (!IsInDeadKeySequence()) {
3974       return;
3975     }
3976 
3977     // If it's in dead key sequence and dead char is inputted as is, we need to
3978     // set the previous modifier state which is stored when preceding dead key
3979     // is pressed.
3980     UniCharsAndModifiers deadChars = GetDeadUniCharsAndModifiers();
3981     aNativeKey.mCommittedCharsAndModifiers.OverwriteModifiersIfBeginsWith(
3982         deadChars);
3983     // Finish the dead key sequence.
3984     DeactivateDeadKeyState();
3985     return;
3986   }
3987 
3988   // If it's a dead key, aNativeKey will be initialized by
3989   // MaybeInitNativeKeyAsDeadKey().
3990   if (MaybeInitNativeKeyAsDeadKey(aNativeKey, aModKeyState)) {
3991     return;
3992   }
3993 
3994   // If the key is not a usual printable key, KeyboardLayout class assume that
3995   // it's not cause dead char nor printable char.  Therefore, there are nothing
3996   // to do here fore such keys (e.g., function keys).
3997   // However, this should keep dead key state even if non-printable key is
3998   // pressed during a dead key sequence.
3999   if (!IsPrintableCharKey(aNativeKey.mOriginalVirtualKeyCode)) {
4000     return;
4001   }
4002 
4003   MOZ_ASSERT(aNativeKey.mOriginalVirtualKeyCode != VK_PACKET,
4004              "At handling VK_PACKET, we shouldn't refer keyboard layout");
4005   MOZ_ASSERT(
4006       aNativeKey.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING,
4007       "Printable key's key name index must be KEY_NAME_INDEX_USE_STRING");
4008 
4009   // If it's in dead key handling and the pressed key causes a composite
4010   // character, aNativeKey will be initialized by
4011   // MaybeInitNativeKeyWithCompositeChar().
4012   if (MaybeInitNativeKeyWithCompositeChar(aNativeKey, aModKeyState)) {
4013     return;
4014   }
4015 
4016   UniCharsAndModifiers baseChars =
4017       GetUniCharsAndModifiers(aNativeKey.mOriginalVirtualKeyCode, aModKeyState);
4018 
4019   // If the key press isn't related to any dead keys, initialize aNativeKey
4020   // with the characters which should be caused by the key.
4021   if (!IsInDeadKeySequence()) {
4022     aNativeKey.mCommittedCharsAndModifiers = baseChars;
4023     return;
4024   }
4025 
4026   // If the key doesn't cause a composite character with preceding dead key,
4027   // initialize aNativeKey with the dead-key character followed by current
4028   // key's character.
4029   UniCharsAndModifiers deadChars = GetDeadUniCharsAndModifiers();
4030   aNativeKey.mCommittedCharsAndModifiers = deadChars + baseChars;
4031   if (aNativeKey.IsKeyDownMessage()) {
4032     DeactivateDeadKeyState();
4033   }
4034 }
4035 
MaybeInitNativeKeyAsDeadKey(NativeKey & aNativeKey,const ModifierKeyState & aModKeyState)4036 bool KeyboardLayout::MaybeInitNativeKeyAsDeadKey(
4037     NativeKey& aNativeKey, const ModifierKeyState& aModKeyState) {
4038   // Only when it's not in dead key sequence, we can trust IsDeadKey() result.
4039   if (!IsInDeadKeySequence() &&
4040       !IsDeadKey(aNativeKey.mOriginalVirtualKeyCode, aModKeyState)) {
4041     return false;
4042   }
4043 
4044   // When keydown message is followed by a dead char message, it should be
4045   // initialized as dead key.
4046   bool isDeadKeyDownEvent =
4047       aNativeKey.IsKeyDownMessage() && aNativeKey.IsFollowedByDeadCharMessage();
4048 
4049   // When keyup message is received, let's check if it's one of preceding
4050   // dead keys because keydown message order and keyup message order may be
4051   // different.
4052   bool isDeadKeyUpEvent =
4053       !aNativeKey.IsKeyDownMessage() &&
4054       mActiveDeadKeys.Contains(aNativeKey.mOriginalVirtualKeyCode);
4055 
4056   if (isDeadKeyDownEvent || isDeadKeyUpEvent) {
4057     ActivateDeadKeyState(aNativeKey, aModKeyState);
4058     // Any dead key events don't generate characters.  So, a dead key should
4059     // cause only keydown event and keyup event whose KeyboardEvent.key
4060     // values are "Dead".
4061     aNativeKey.mCommittedCharsAndModifiers.Clear();
4062     aNativeKey.mKeyNameIndex = KEY_NAME_INDEX_Dead;
4063     return true;
4064   }
4065 
4066   // At keydown message handling, we need to forget the first dead key
4067   // because there is no guarantee coming WM_KEYUP for the second dead
4068   // key before next WM_KEYDOWN.  E.g., due to auto key repeat or pressing
4069   // another dead key before releasing current key.  Therefore, we can
4070   // set only a character for current key for keyup event.
4071   if (!IsInDeadKeySequence()) {
4072     aNativeKey.mCommittedCharsAndModifiers = GetUniCharsAndModifiers(
4073         aNativeKey.mOriginalVirtualKeyCode, aModKeyState);
4074     return true;
4075   }
4076 
4077   // When non-printable key event comes during a dead key sequence, that must
4078   // be a modifier key event.  So, such events shouldn't be handled as a part
4079   // of the dead key sequence.
4080   if (!IsDeadKey(aNativeKey.mOriginalVirtualKeyCode, aModKeyState)) {
4081     return false;
4082   }
4083 
4084   // FYI: Following code may run when the user doesn't input text actually
4085   //      but the key sequence is a dead key sequence.  For example,
4086   //      ` -> Ctrl+` with Spanish keyboard layout.  Let's keep using this
4087   //      complicated code for now because this runs really rarely.
4088 
4089   // Dead key followed by another dead key may cause a composed character
4090   // (e.g., "Russian - Mnemonic" keyboard layout's 's' -> 'c').
4091   if (MaybeInitNativeKeyWithCompositeChar(aNativeKey, aModKeyState)) {
4092     return true;
4093   }
4094 
4095   // Otherwise, dead key followed by another dead key causes inputting both
4096   // character.
4097   UniCharsAndModifiers prevDeadChars = GetDeadUniCharsAndModifiers();
4098   UniCharsAndModifiers newChars =
4099       GetUniCharsAndModifiers(aNativeKey.mOriginalVirtualKeyCode, aModKeyState);
4100   // But keypress events should be fired for each committed character.
4101   aNativeKey.mCommittedCharsAndModifiers = prevDeadChars + newChars;
4102   if (aNativeKey.IsKeyDownMessage()) {
4103     DeactivateDeadKeyState();
4104   }
4105   return true;
4106 }
4107 
MaybeInitNativeKeyWithCompositeChar(NativeKey & aNativeKey,const ModifierKeyState & aModKeyState)4108 bool KeyboardLayout::MaybeInitNativeKeyWithCompositeChar(
4109     NativeKey& aNativeKey, const ModifierKeyState& aModKeyState) {
4110   if (!IsInDeadKeySequence()) {
4111     return false;
4112   }
4113 
4114   if (NS_WARN_IF(!IsPrintableCharKey(aNativeKey.mOriginalVirtualKeyCode))) {
4115     return false;
4116   }
4117 
4118   UniCharsAndModifiers baseChars =
4119       GetUniCharsAndModifiers(aNativeKey.mOriginalVirtualKeyCode, aModKeyState);
4120   if (baseChars.IsEmpty() || !baseChars.CharAt(0)) {
4121     return false;
4122   }
4123 
4124   char16_t compositeChar = GetCompositeChar(baseChars.CharAt(0));
4125   if (!compositeChar) {
4126     return false;
4127   }
4128 
4129   // Active dead-key and base character does produce exactly one composite
4130   // character.
4131   aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar,
4132                                                 baseChars.ModifiersAt(0));
4133   if (aNativeKey.IsKeyDownMessage()) {
4134     DeactivateDeadKeyState();
4135   }
4136   return true;
4137 }
4138 
GetUniCharsAndModifiers(uint8_t aVirtualKey,VirtualKey::ShiftState aShiftState) const4139 UniCharsAndModifiers KeyboardLayout::GetUniCharsAndModifiers(
4140     uint8_t aVirtualKey, VirtualKey::ShiftState aShiftState) const {
4141   UniCharsAndModifiers result;
4142   int32_t key = GetKeyIndex(aVirtualKey);
4143   if (key < 0) {
4144     return result;
4145   }
4146   return mVirtualKeys[key].GetUniChars(aShiftState);
4147 }
4148 
GetNativeUniCharsAndModifiers(uint8_t aVirtualKey,const ModifierKeyState & aModKeyState) const4149 UniCharsAndModifiers KeyboardLayout::GetNativeUniCharsAndModifiers(
4150     uint8_t aVirtualKey, const ModifierKeyState& aModKeyState) const {
4151   int32_t key = GetKeyIndex(aVirtualKey);
4152   if (key < 0) {
4153     return UniCharsAndModifiers();
4154   }
4155   VirtualKey::ShiftState shiftState =
4156       VirtualKey::ModifierKeyStateToShiftState(aModKeyState);
4157   return mVirtualKeys[key].GetNativeUniChars(shiftState);
4158 }
4159 
GetDeadUniCharsAndModifiers() const4160 UniCharsAndModifiers KeyboardLayout::GetDeadUniCharsAndModifiers() const {
4161   MOZ_RELEASE_ASSERT(mActiveDeadKeys.Length() == mDeadKeyShiftStates.Length());
4162 
4163   if (NS_WARN_IF(mActiveDeadKeys.IsEmpty())) {
4164     return UniCharsAndModifiers();
4165   }
4166 
4167   UniCharsAndModifiers result;
4168   for (size_t i = 0; i < mActiveDeadKeys.Length(); ++i) {
4169     result +=
4170         GetUniCharsAndModifiers(mActiveDeadKeys[i], mDeadKeyShiftStates[i]);
4171   }
4172   return result;
4173 }
4174 
GetCompositeChar(char16_t aBaseChar) const4175 char16_t KeyboardLayout::GetCompositeChar(char16_t aBaseChar) const {
4176   if (NS_WARN_IF(mActiveDeadKeys.IsEmpty())) {
4177     return 0;
4178   }
4179   // XXX Currently, we don't support computing a composite character with
4180   //     two or more dead keys since it needs big table for supporting
4181   //     long chained dead keys.  However, this should be a minor bug
4182   //     because this runs only when the latest keydown event does not cause
4183   //     WM_(SYS)CHAR messages.  So, when user wants to input a character,
4184   //     this path never runs.
4185   if (mActiveDeadKeys.Length() > 1) {
4186     return 0;
4187   }
4188   int32_t key = GetKeyIndex(mActiveDeadKeys[0]);
4189   if (key < 0) {
4190     return 0;
4191   }
4192   return mVirtualKeys[key].GetCompositeChar(mDeadKeyShiftStates[0], aBaseChar);
4193 }
4194 
4195 // static
GetActiveLayout()4196 HKL KeyboardLayout::GetActiveLayout() { return GetInstance()->mKeyboardLayout; }
4197 
4198 // static
GetActiveLayoutName()4199 nsCString KeyboardLayout::GetActiveLayoutName() {
4200   return GetInstance()->GetLayoutName(GetActiveLayout());
4201 }
4202 
IsValidKeyboardLayoutsChild(const nsAString & aChildName)4203 static bool IsValidKeyboardLayoutsChild(const nsAString& aChildName) {
4204   if (aChildName.Length() != 8) {
4205     return false;
4206   }
4207   for (size_t i = 0; i < aChildName.Length(); i++) {
4208     if ((aChildName[i] >= '0' && aChildName[i] <= '9') ||
4209         (aChildName[i] >= 'a' && aChildName[i] <= 'f') ||
4210         (aChildName[i] >= 'A' && aChildName[i] <= 'F')) {
4211       continue;
4212     }
4213     return false;
4214   }
4215   return true;
4216 }
4217 
GetLayoutName(HKL aLayout) const4218 nsCString KeyboardLayout::GetLayoutName(HKL aLayout) const {
4219   const wchar_t kKeyboardLayouts[] =
4220       L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
4221   uint16_t language = reinterpret_cast<uintptr_t>(aLayout) & 0xFFFF;
4222   uint16_t layout = (reinterpret_cast<uintptr_t>(aLayout) >> 16) & 0xFFFF;
4223   // If the layout is less than 0xA000XXXX (normal keyboard layout for the
4224   // language) or 0xEYYYXXXX (IMM-IME), we can retrieve its name simply.
4225   if (layout < 0xA000 || (layout & 0xF000) == 0xE000) {
4226     nsAutoString key(kKeyboardLayouts);
4227     key.AppendPrintf("%08X", layout < 0xA000
4228                                  ? layout
4229                                  : reinterpret_cast<uintptr_t>(aLayout));
4230     wchar_t buf[256];
4231     if (NS_WARN_IF(!WinUtils::GetRegistryKey(
4232             HKEY_LOCAL_MACHINE, key.get(), L"Layout Text", buf, sizeof(buf)))) {
4233       return NS_LITERAL_CSTRING("No name or too long name");
4234     }
4235     return NS_ConvertUTF16toUTF8(buf);
4236   }
4237 
4238   if (NS_WARN_IF((layout & 0xF000) != 0xF000)) {
4239     nsAutoCString result;
4240     result.AppendPrintf("Odd HKL: 0x%08X",
4241                         reinterpret_cast<uintptr_t>(aLayout));
4242     return result;
4243   }
4244 
4245   // Otherwise, we need to walk the registry under "Keyboard Layouts".
4246   nsCOMPtr<nsIWindowsRegKey> regKey =
4247       do_CreateInstance("@mozilla.org/windows-registry-key;1");
4248   if (NS_WARN_IF(!regKey)) {
4249     return EmptyCString();
4250   }
4251   nsresult rv =
4252       regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
4253                    nsString(kKeyboardLayouts), nsIWindowsRegKey::ACCESS_READ);
4254   if (NS_WARN_IF(NS_FAILED(rv))) {
4255     return EmptyCString();
4256   }
4257   uint32_t childCount = 0;
4258   if (NS_WARN_IF(NS_FAILED(regKey->GetChildCount(&childCount))) ||
4259       NS_WARN_IF(!childCount)) {
4260     return EmptyCString();
4261   }
4262   for (uint32_t i = 0; i < childCount; i++) {
4263     nsAutoString childName;
4264     if (NS_WARN_IF(NS_FAILED(regKey->GetChildName(i, childName))) ||
4265         !IsValidKeyboardLayoutsChild(childName)) {
4266       continue;
4267     }
4268     uint32_t childNum = static_cast<uint32_t>(childName.ToInteger64(&rv, 16));
4269     if (NS_WARN_IF(NS_FAILED(rv))) {
4270       continue;
4271     }
4272     // Ignore normal keyboard layouts for each language.
4273     if (childNum <= 0xFFFF) {
4274       continue;
4275     }
4276     // If it doesn't start with 'A' nor 'a', language should be matched.
4277     if ((childNum & 0xFFFF) != language &&
4278         (childNum & 0xF0000000) != 0xA0000000) {
4279       continue;
4280     }
4281     // Then, the child should have "Layout Id" which is "YYY" of 0xFYYYXXXX.
4282     nsAutoString key(kKeyboardLayouts);
4283     key += childName;
4284     wchar_t buf[256];
4285     if (NS_WARN_IF(!WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE, key.get(),
4286                                              L"Layout Id", buf, sizeof(buf)))) {
4287       continue;
4288     }
4289     uint16_t layoutId = wcstol(buf, nullptr, 16);
4290     if (layoutId != (layout & 0x0FFF)) {
4291       continue;
4292     }
4293     if (NS_WARN_IF(!WinUtils::GetRegistryKey(
4294             HKEY_LOCAL_MACHINE, key.get(), L"Layout Text", buf, sizeof(buf)))) {
4295       continue;
4296     }
4297     return NS_ConvertUTF16toUTF8(buf);
4298   }
4299   return EmptyCString();
4300 }
4301 
LoadLayout(HKL aLayout)4302 void KeyboardLayout::LoadLayout(HKL aLayout) {
4303   mIsPendingToRestoreKeyboardLayout = false;
4304 
4305   if (mKeyboardLayout == aLayout) {
4306     return;
4307   }
4308 
4309   mKeyboardLayout = aLayout;
4310 
4311   MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Info,
4312           ("KeyboardLayout::LoadLayout(aLayout=0x%08X (%s))", aLayout,
4313            GetLayoutName(aLayout).get()));
4314 
4315   BYTE kbdState[256];
4316   memset(kbdState, 0, sizeof(kbdState));
4317 
4318   BYTE originalKbdState[256];
4319   // Bitfield with all shift states that have at least one dead-key.
4320   uint16_t shiftStatesWithDeadKeys = 0;
4321   // Bitfield with all shift states that produce any possible dead-key base
4322   // characters.
4323   uint16_t shiftStatesWithBaseChars = 0;
4324 
4325   mActiveDeadKeys.Clear();
4326   mDeadKeyShiftStates.Clear();
4327 
4328   ReleaseDeadKeyTables();
4329 
4330   ::GetKeyboardState(originalKbdState);
4331 
4332   // For each shift state gather all printable characters that are produced
4333   // for normal case when no any dead-key is active.
4334 
4335   for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
4336     VirtualKey::FillKbdState(kbdState, shiftState);
4337     for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
4338       int32_t vki = GetKeyIndex(virtualKey);
4339       if (vki < 0) {
4340         continue;
4341       }
4342       NS_ASSERTION(uint32_t(vki) < ArrayLength(mVirtualKeys), "invalid index");
4343       char16_t uniChars[5];
4344       int32_t ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)uniChars,
4345                                   ArrayLength(uniChars), 0, mKeyboardLayout);
4346       // dead-key
4347       if (ret < 0) {
4348         shiftStatesWithDeadKeys |= (1 << shiftState);
4349         // Repeat dead-key to deactivate it and get its character
4350         // representation.
4351         char16_t deadChar[2];
4352         ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)deadChar,
4353                             ArrayLength(deadChar), 0, mKeyboardLayout);
4354         NS_ASSERTION(ret == 2, "Expecting twice repeated dead-key character");
4355         mVirtualKeys[vki].SetDeadChar(shiftState, deadChar[0]);
4356 
4357         MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Debug,
4358                 ("  %s (%d): DeadChar(%s, %s) (ret=%d)",
4359                  kVirtualKeyName[virtualKey], vki,
4360                  GetShiftStateName(shiftState).get(),
4361                  GetCharacterCodeName(deadChar, 1).get(), ret));
4362       } else {
4363         if (ret == 1) {
4364           // dead-key can pair only with exactly one base character.
4365           shiftStatesWithBaseChars |= (1 << shiftState);
4366         }
4367         mVirtualKeys[vki].SetNormalChars(shiftState, uniChars, ret);
4368         MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Verbose,
4369                 ("  %s (%d): NormalChar(%s, %s) (ret=%d)",
4370                  kVirtualKeyName[virtualKey], vki,
4371                  GetShiftStateName(shiftState).get(),
4372                  GetCharacterCodeName(uniChars, ret).get(), ret));
4373       }
4374     }
4375   }
4376 
4377   // Now process each dead-key to find all its base characters and resulting
4378   // composite characters.
4379   for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
4380     if (!(shiftStatesWithDeadKeys & (1 << shiftState))) {
4381       continue;
4382     }
4383 
4384     VirtualKey::FillKbdState(kbdState, shiftState);
4385 
4386     for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
4387       int32_t vki = GetKeyIndex(virtualKey);
4388       if (vki >= 0 && mVirtualKeys[vki].IsDeadKey(shiftState)) {
4389         DeadKeyEntry deadKeyArray[256];
4390         int32_t n = GetDeadKeyCombinations(
4391             virtualKey, kbdState, shiftStatesWithBaseChars, deadKeyArray,
4392             ArrayLength(deadKeyArray));
4393         const DeadKeyTable* dkt =
4394             mVirtualKeys[vki].MatchingDeadKeyTable(deadKeyArray, n);
4395         if (!dkt) {
4396           dkt = AddDeadKeyTable(deadKeyArray, n);
4397         }
4398         mVirtualKeys[vki].AttachDeadKeyTable(shiftState, dkt);
4399       }
4400     }
4401   }
4402 
4403   ::SetKeyboardState(originalKbdState);
4404 
4405   if (MOZ_LOG_TEST(sKeyboardLayoutLogger, LogLevel::Verbose)) {
4406     static const UINT kExtendedScanCode[] = {0x0000, 0xE000};
4407     static const UINT kMapType = MAPVK_VSC_TO_VK_EX;
4408     MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Verbose,
4409             ("Logging virtual keycode values for scancode (0x%p)...",
4410              mKeyboardLayout));
4411     for (uint32_t i = 0; i < ArrayLength(kExtendedScanCode); i++) {
4412       for (uint32_t j = 1; j <= 0xFF; j++) {
4413         UINT scanCode = kExtendedScanCode[i] + j;
4414         UINT virtualKeyCode =
4415             ::MapVirtualKeyEx(scanCode, kMapType, mKeyboardLayout);
4416         MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Verbose,
4417                 ("0x%04X, %s", scanCode, kVirtualKeyName[virtualKeyCode]));
4418       }
4419     }
4420   }
4421 }
4422 
GetKeyIndex(uint8_t aVirtualKey)4423 inline int32_t KeyboardLayout::GetKeyIndex(uint8_t aVirtualKey) {
4424   // Currently these 68 (NS_NUM_OF_KEYS) virtual keys are assumed
4425   // to produce visible representation:
4426   // 0x20 - VK_SPACE          ' '
4427   // 0x30..0x39               '0'..'9'
4428   // 0x41..0x5A               'A'..'Z'
4429   // 0x60..0x69               '0'..'9' on numpad
4430   // 0x6A - VK_MULTIPLY       '*' on numpad
4431   // 0x6B - VK_ADD            '+' on numpad
4432   // 0x6D - VK_SUBTRACT       '-' on numpad
4433   // 0x6E - VK_DECIMAL        '.' on numpad
4434   // 0x6F - VK_DIVIDE         '/' on numpad
4435   // 0x6E - VK_DECIMAL        '.'
4436   // 0xBA - VK_OEM_1          ';:' for US
4437   // 0xBB - VK_OEM_PLUS       '+' any country
4438   // 0xBC - VK_OEM_COMMA      ',' any country
4439   // 0xBD - VK_OEM_MINUS      '-' any country
4440   // 0xBE - VK_OEM_PERIOD     '.' any country
4441   // 0xBF - VK_OEM_2          '/?' for US
4442   // 0xC0 - VK_OEM_3          '`~' for US
4443   // 0xC1 - VK_ABNT_C1        '/?' for Brazilian
4444   // 0xC2 - VK_ABNT_C2        separator key on numpad (Brazilian or JIS for Mac)
4445   // 0xDB - VK_OEM_4          '[{' for US
4446   // 0xDC - VK_OEM_5          '\|' for US
4447   // 0xDD - VK_OEM_6          ']}' for US
4448   // 0xDE - VK_OEM_7          ''"' for US
4449   // 0xDF - VK_OEM_8
4450   // 0xE1 - no name
4451   // 0xE2 - VK_OEM_102        '\_' for JIS
4452   // 0xE3 - no name
4453   // 0xE4 - no name
4454 
4455   static const int8_t xlat[256] = {
4456       // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
4457       //-----------------------------------------------------------------------
4458       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 00
4459       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 10
4460       0,  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 20
4461       1,  2,  3,  4,  5,  6,  7,  8,  9,  10, -1, -1, -1, -1, -1, -1,  // 30
4462       -1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  // 40
4463       26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1,  // 50
4464       37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, -1, 49, 50, 51,  // 60
4465       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 70
4466       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 80
4467       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 90
4468       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // A0
4469       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, 56, 57,  // B0
4470       58, 59, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // C0
4471       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, 63, 64, 65,  // D0
4472       -1, 66, 67, 68, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // E0
4473       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1   // F0
4474   };
4475 
4476   return xlat[aVirtualKey];
4477 }
4478 
CompareDeadKeyEntries(const void * aArg1,const void * aArg2,void *)4479 int KeyboardLayout::CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
4480                                           void*) {
4481   const DeadKeyEntry* arg1 = static_cast<const DeadKeyEntry*>(aArg1);
4482   const DeadKeyEntry* arg2 = static_cast<const DeadKeyEntry*>(aArg2);
4483 
4484   return arg1->BaseChar - arg2->BaseChar;
4485 }
4486 
AddDeadKeyTable(const DeadKeyEntry * aDeadKeyArray,uint32_t aEntries)4487 const DeadKeyTable* KeyboardLayout::AddDeadKeyTable(
4488     const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) {
4489   DeadKeyTableListEntry* next = mDeadKeyTableListHead;
4490 
4491   const size_t bytes = offsetof(DeadKeyTableListEntry, data) +
4492                        DeadKeyTable::SizeInBytes(aEntries);
4493   uint8_t* p = new uint8_t[bytes];
4494 
4495   mDeadKeyTableListHead = reinterpret_cast<DeadKeyTableListEntry*>(p);
4496   mDeadKeyTableListHead->next = next;
4497 
4498   DeadKeyTable* dkt =
4499       reinterpret_cast<DeadKeyTable*>(mDeadKeyTableListHead->data);
4500 
4501   dkt->Init(aDeadKeyArray, aEntries);
4502 
4503   return dkt;
4504 }
4505 
ReleaseDeadKeyTables()4506 void KeyboardLayout::ReleaseDeadKeyTables() {
4507   while (mDeadKeyTableListHead) {
4508     uint8_t* p = reinterpret_cast<uint8_t*>(mDeadKeyTableListHead);
4509     mDeadKeyTableListHead = mDeadKeyTableListHead->next;
4510 
4511     delete[] p;
4512   }
4513 }
4514 
EnsureDeadKeyActive(bool aIsActive,uint8_t aDeadKey,const PBYTE aDeadKeyKbdState)4515 bool KeyboardLayout::EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
4516                                          const PBYTE aDeadKeyKbdState) {
4517   int32_t ret;
4518   do {
4519     char16_t dummyChars[5];
4520     ret =
4521         ::ToUnicodeEx(aDeadKey, 0, (PBYTE)aDeadKeyKbdState, (LPWSTR)dummyChars,
4522                       ArrayLength(dummyChars), 0, mKeyboardLayout);
4523     // returned values:
4524     // <0 - Dead key state is active. The keyboard driver will wait for next
4525     //      character.
4526     //  1 - Previous pressed key was a valid base character that produced
4527     //      exactly one composite character.
4528     // >1 - Previous pressed key does not produce any composite characters.
4529     //      Return dead-key character followed by base character(s).
4530   } while ((ret < 0) != aIsActive);
4531 
4532   return (ret < 0);
4533 }
4534 
ActivateDeadKeyState(const NativeKey & aNativeKey,const ModifierKeyState & aModKeyState)4535 void KeyboardLayout::ActivateDeadKeyState(
4536     const NativeKey& aNativeKey, const ModifierKeyState& aModKeyState) {
4537   // Dead-key state should be activated at keydown.
4538   if (!aNativeKey.IsKeyDownMessage()) {
4539     return;
4540   }
4541 
4542   mActiveDeadKeys.AppendElement(aNativeKey.mOriginalVirtualKeyCode);
4543   mDeadKeyShiftStates.AppendElement(
4544       VirtualKey::ModifierKeyStateToShiftState(aModKeyState));
4545 }
4546 
DeactivateDeadKeyState()4547 void KeyboardLayout::DeactivateDeadKeyState() {
4548   if (mActiveDeadKeys.IsEmpty()) {
4549     return;
4550   }
4551 
4552   BYTE kbdState[256];
4553   memset(kbdState, 0, sizeof(kbdState));
4554 
4555   // Assume that the last dead key can finish dead key sequence.
4556   VirtualKey::FillKbdState(kbdState, mDeadKeyShiftStates.LastElement());
4557   EnsureDeadKeyActive(false, mActiveDeadKeys.LastElement(), kbdState);
4558   mActiveDeadKeys.Clear();
4559   mDeadKeyShiftStates.Clear();
4560 }
4561 
AddDeadKeyEntry(char16_t aBaseChar,char16_t aCompositeChar,DeadKeyEntry * aDeadKeyArray,uint32_t aEntries)4562 bool KeyboardLayout::AddDeadKeyEntry(char16_t aBaseChar,
4563                                      char16_t aCompositeChar,
4564                                      DeadKeyEntry* aDeadKeyArray,
4565                                      uint32_t aEntries) {
4566   for (uint32_t index = 0; index < aEntries; index++) {
4567     if (aDeadKeyArray[index].BaseChar == aBaseChar) {
4568       return false;
4569     }
4570   }
4571 
4572   aDeadKeyArray[aEntries].BaseChar = aBaseChar;
4573   aDeadKeyArray[aEntries].CompositeChar = aCompositeChar;
4574 
4575   return true;
4576 }
4577 
GetDeadKeyCombinations(uint8_t aDeadKey,const PBYTE aDeadKeyKbdState,uint16_t aShiftStatesWithBaseChars,DeadKeyEntry * aDeadKeyArray,uint32_t aMaxEntries)4578 uint32_t KeyboardLayout::GetDeadKeyCombinations(
4579     uint8_t aDeadKey, const PBYTE aDeadKeyKbdState,
4580     uint16_t aShiftStatesWithBaseChars, DeadKeyEntry* aDeadKeyArray,
4581     uint32_t aMaxEntries) {
4582   bool deadKeyActive = false;
4583   uint32_t entries = 0;
4584   BYTE kbdState[256];
4585   memset(kbdState, 0, sizeof(kbdState));
4586 
4587   for (uint32_t shiftState = 0; shiftState < 16; shiftState++) {
4588     if (!(aShiftStatesWithBaseChars & (1 << shiftState))) {
4589       continue;
4590     }
4591 
4592     VirtualKey::FillKbdState(kbdState, shiftState);
4593 
4594     for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
4595       int32_t vki = GetKeyIndex(virtualKey);
4596       // Dead-key can pair only with such key that produces exactly one base
4597       // character.
4598       if (vki >= 0 &&
4599           mVirtualKeys[vki].GetNativeUniChars(shiftState).Length() == 1) {
4600         // Ensure dead-key is in active state, when it swallows entered
4601         // character and waits for the next pressed key.
4602         if (!deadKeyActive) {
4603           deadKeyActive = EnsureDeadKeyActive(true, aDeadKey, aDeadKeyKbdState);
4604         }
4605 
4606         // Depending on the character the followed the dead-key, the keyboard
4607         // driver can produce one composite character, or a dead-key character
4608         // followed by a second character.
4609         char16_t compositeChars[5];
4610         int32_t ret =
4611             ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)compositeChars,
4612                           ArrayLength(compositeChars), 0, mKeyboardLayout);
4613         switch (ret) {
4614           case 0:
4615             // This key combination does not produce any characters. The
4616             // dead-key is still in active state.
4617             break;
4618           case 1: {
4619             char16_t baseChars[5];
4620             ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)baseChars,
4621                                 ArrayLength(baseChars), 0, mKeyboardLayout);
4622             if (entries < aMaxEntries) {
4623               switch (ret) {
4624                 case 1:
4625                   // Exactly one composite character produced. Now, when
4626                   // dead-key is not active, repeat the last character one more
4627                   // time to determine the base character.
4628                   if (AddDeadKeyEntry(baseChars[0], compositeChars[0],
4629                                       aDeadKeyArray, entries)) {
4630                     entries++;
4631                   }
4632                   deadKeyActive = false;
4633                   break;
4634                 case -1: {
4635                   // If pressing another dead-key produces different character,
4636                   // we should register the dead-key entry with first character
4637                   // produced by current key.
4638 
4639                   // First inactivate the dead-key state completely.
4640                   deadKeyActive =
4641                       EnsureDeadKeyActive(false, aDeadKey, aDeadKeyKbdState);
4642                   if (NS_WARN_IF(deadKeyActive)) {
4643                     MOZ_LOG(sKeyboardLayoutLogger, LogLevel::Error,
4644                             ("  failed to deactivating the dead-key state..."));
4645                     break;
4646                   }
4647                   for (int32_t i = 0; i < 5; ++i) {
4648                     ret = ::ToUnicodeEx(
4649                         virtualKey, 0, kbdState, (LPWSTR)baseChars,
4650                         ArrayLength(baseChars), 0, mKeyboardLayout);
4651                     if (ret >= 0) {
4652                       break;
4653                     }
4654                   }
4655                   if (ret > 0 &&
4656                       AddDeadKeyEntry(baseChars[0], compositeChars[0],
4657                                       aDeadKeyArray, entries)) {
4658                     entries++;
4659                   }
4660                   // Inactivate dead-key state for current virtual keycode.
4661                   EnsureDeadKeyActive(false, virtualKey, kbdState);
4662                   break;
4663                 }
4664                 default:
4665                   NS_WARNING("File a bug for this dead-key handling!");
4666                   deadKeyActive = false;
4667                   break;
4668               }
4669             }
4670             MOZ_LOG(
4671                 sKeyboardLayoutLogger, LogLevel::Debug,
4672                 ("  %s -> %s (%d): DeadKeyEntry(%s, %s) (ret=%d)",
4673                  kVirtualKeyName[aDeadKey], kVirtualKeyName[virtualKey], vki,
4674                  GetCharacterCodeName(compositeChars, 1).get(),
4675                  ret <= 0
4676                      ? "''"
4677                      : GetCharacterCodeName(baseChars, std::min(ret, 5)).get(),
4678                  ret));
4679             break;
4680           }
4681           default:
4682             // 1. Unexpected dead-key. Dead-key chaining is not supported.
4683             // 2. More than one character generated. This is not a valid
4684             //    dead-key and base character combination.
4685             deadKeyActive = false;
4686             MOZ_LOG(
4687                 sKeyboardLayoutLogger, LogLevel::Verbose,
4688                 ("  %s -> %s (%d): Unsupport dead key type(%s) (ret=%d)",
4689                  kVirtualKeyName[aDeadKey], kVirtualKeyName[virtualKey], vki,
4690                  ret <= 0
4691                      ? "''"
4692                      : GetCharacterCodeName(compositeChars, std::min(ret, 5))
4693                            .get(),
4694                  ret));
4695             break;
4696         }
4697       }
4698     }
4699   }
4700 
4701   if (deadKeyActive) {
4702     deadKeyActive = EnsureDeadKeyActive(false, aDeadKey, aDeadKeyKbdState);
4703   }
4704 
4705   NS_QuickSort(aDeadKeyArray, entries, sizeof(DeadKeyEntry),
4706                CompareDeadKeyEntries, nullptr);
4707   return entries;
4708 }
4709 
ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const4710 uint32_t KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(
4711     UINT aNativeKeyCode) const {
4712   // Alphabet or Numeric or Numpad or Function keys
4713   if ((aNativeKeyCode >= 0x30 && aNativeKeyCode <= 0x39) ||
4714       (aNativeKeyCode >= 0x41 && aNativeKeyCode <= 0x5A) ||
4715       (aNativeKeyCode >= 0x60 && aNativeKeyCode <= 0x87)) {
4716     return static_cast<uint32_t>(aNativeKeyCode);
4717   }
4718   switch (aNativeKeyCode) {
4719     // Following keycodes are same as our DOM keycodes
4720     case VK_CANCEL:
4721     case VK_BACK:
4722     case VK_TAB:
4723     case VK_CLEAR:
4724     case VK_RETURN:
4725     case VK_SHIFT:
4726     case VK_CONTROL:
4727     case VK_MENU:  // Alt
4728     case VK_PAUSE:
4729     case VK_CAPITAL:  // CAPS LOCK
4730     case VK_KANA:     // same as VK_HANGUL
4731     case VK_JUNJA:
4732     case VK_FINAL:
4733     case VK_HANJA:  // same as VK_KANJI
4734     case VK_ESCAPE:
4735     case VK_CONVERT:
4736     case VK_NONCONVERT:
4737     case VK_ACCEPT:
4738     case VK_MODECHANGE:
4739     case VK_SPACE:
4740     case VK_PRIOR:  // PAGE UP
4741     case VK_NEXT:   // PAGE DOWN
4742     case VK_END:
4743     case VK_HOME:
4744     case VK_LEFT:
4745     case VK_UP:
4746     case VK_RIGHT:
4747     case VK_DOWN:
4748     case VK_SELECT:
4749     case VK_PRINT:
4750     case VK_EXECUTE:
4751     case VK_SNAPSHOT:
4752     case VK_INSERT:
4753     case VK_DELETE:
4754     case VK_APPS:  // Context Menu
4755     case VK_SLEEP:
4756     case VK_NUMLOCK:
4757     case VK_SCROLL:  // SCROLL LOCK
4758     case VK_ATTN:    // Attension key of IBM midrange computers, e.g., AS/400
4759     case VK_CRSEL:   // Cursor Selection
4760     case VK_EXSEL:   // Extend Selection
4761     case VK_EREOF:   // Erase EOF key of IBM 3270 keyboard layout
4762     case VK_PLAY:
4763     case VK_ZOOM:
4764     case VK_PA1:  // PA1 key of IBM 3270 keyboard layout
4765       return uint32_t(aNativeKeyCode);
4766 
4767     case VK_HELP:
4768       return NS_VK_HELP;
4769 
4770     // Windows key should be mapped to a Win keycode
4771     // They should be able to be distinguished by DOM3 KeyboardEvent.location
4772     case VK_LWIN:
4773     case VK_RWIN:
4774       return NS_VK_WIN;
4775 
4776     case VK_VOLUME_MUTE:
4777       return NS_VK_VOLUME_MUTE;
4778     case VK_VOLUME_DOWN:
4779       return NS_VK_VOLUME_DOWN;
4780     case VK_VOLUME_UP:
4781       return NS_VK_VOLUME_UP;
4782 
4783     // Following keycodes are not defined in our DOM keycodes.
4784     case VK_BROWSER_BACK:
4785     case VK_BROWSER_FORWARD:
4786     case VK_BROWSER_REFRESH:
4787     case VK_BROWSER_STOP:
4788     case VK_BROWSER_SEARCH:
4789     case VK_BROWSER_FAVORITES:
4790     case VK_BROWSER_HOME:
4791     case VK_MEDIA_NEXT_TRACK:
4792     case VK_MEDIA_PREV_TRACK:
4793     case VK_MEDIA_STOP:
4794     case VK_MEDIA_PLAY_PAUSE:
4795     case VK_LAUNCH_MAIL:
4796     case VK_LAUNCH_MEDIA_SELECT:
4797     case VK_LAUNCH_APP1:
4798     case VK_LAUNCH_APP2:
4799       return 0;
4800 
4801     // Following OEM specific virtual keycodes should pass through DOM keyCode
4802     // for compatibility with the other browsers on Windows.
4803 
4804     // Following OEM specific virtual keycodes are defined for Fujitsu/OASYS.
4805     case VK_OEM_FJ_JISHO:
4806     case VK_OEM_FJ_MASSHOU:
4807     case VK_OEM_FJ_TOUROKU:
4808     case VK_OEM_FJ_LOYA:
4809     case VK_OEM_FJ_ROYA:
4810     // Not sure what means "ICO".
4811     case VK_ICO_HELP:
4812     case VK_ICO_00:
4813     case VK_ICO_CLEAR:
4814     // Following OEM specific virtual keycodes are defined for Nokia/Ericsson.
4815     case VK_OEM_RESET:
4816     case VK_OEM_JUMP:
4817     case VK_OEM_PA1:
4818     case VK_OEM_PA2:
4819     case VK_OEM_PA3:
4820     case VK_OEM_WSCTRL:
4821     case VK_OEM_CUSEL:
4822     case VK_OEM_ATTN:
4823     case VK_OEM_FINISH:
4824     case VK_OEM_COPY:
4825     case VK_OEM_AUTO:
4826     case VK_OEM_ENLW:
4827     case VK_OEM_BACKTAB:
4828     // VK_OEM_CLEAR is defined as not OEM specific, but let's pass though
4829     // DOM keyCode like other OEM specific virtual keycodes.
4830     case VK_OEM_CLEAR:
4831       return uint32_t(aNativeKeyCode);
4832 
4833     // 0xE1 is an OEM specific virtual keycode. However, the value is already
4834     // used in our DOM keyCode for AltGr on Linux. So, this virtual keycode
4835     // cannot pass through DOM keyCode.
4836     case 0xE1:
4837       return 0;
4838 
4839     // Following keycodes are OEM keys which are keycodes for non-alphabet and
4840     // non-numeric keys, we should compute each keycode of them from unshifted
4841     // character which is inputted by each key.  But if the unshifted character
4842     // is not an ASCII character but shifted character is an ASCII character,
4843     // we should refer it.
4844     case VK_OEM_1:
4845     case VK_OEM_PLUS:
4846     case VK_OEM_COMMA:
4847     case VK_OEM_MINUS:
4848     case VK_OEM_PERIOD:
4849     case VK_OEM_2:
4850     case VK_OEM_3:
4851     case VK_OEM_4:
4852     case VK_OEM_5:
4853     case VK_OEM_6:
4854     case VK_OEM_7:
4855     case VK_OEM_8:
4856     case VK_OEM_102:
4857     case VK_ABNT_C1: {
4858       NS_ASSERTION(IsPrintableCharKey(aNativeKeyCode),
4859                    "The key must be printable");
4860       ModifierKeyState modKeyState(0);
4861       UniCharsAndModifiers uniChars =
4862           GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
4863       if (uniChars.Length() != 1 || uniChars.CharAt(0) < ' ' ||
4864           uniChars.CharAt(0) > 0x7F) {
4865         modKeyState.Set(MODIFIER_SHIFT);
4866         uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
4867         if (uniChars.Length() != 1 || uniChars.CharAt(0) < ' ' ||
4868             uniChars.CharAt(0) > 0x7F) {
4869           // In this case, we've returned 0 in this case for long time because
4870           // we decided that we should avoid setting same keyCode value to 2 or
4871           // more keys since active keyboard layout may have a key to input the
4872           // punctuation with different key.  However, setting keyCode to 0
4873           // makes some web applications which are aware of neither
4874           // KeyboardEvent.key nor KeyboardEvent.code not work with Firefox
4875           // when user selects non-ASCII capable keyboard layout such as
4876           // Russian and Thai layout.  So, let's decide keyCode value with
4877           // major keyboard layout's key which causes the OEM keycode.
4878           // Actually, this maps same keyCode value to 2 keys on Russian
4879           // keyboard layout.  "Period" key causes VK_OEM_PERIOD but inputs
4880           // Yu of Cyrillic and "Slash" key causes VK_OEM_2 (same as US
4881           // keyboard layout) but inputs "." (period of ASCII).  Therefore,
4882           // we return DOM_VK_PERIOD which is same as VK_OEM_PERIOD for
4883           // "Period" key.  On the other hand, we use same keyCode value for
4884           // "Slash" key too because it inputs ".".
4885           CodeNameIndex code;
4886           switch (aNativeKeyCode) {
4887             case VK_OEM_1:
4888               code = CODE_NAME_INDEX_Semicolon;
4889               break;
4890             case VK_OEM_PLUS:
4891               code = CODE_NAME_INDEX_Equal;
4892               break;
4893             case VK_OEM_COMMA:
4894               code = CODE_NAME_INDEX_Comma;
4895               break;
4896             case VK_OEM_MINUS:
4897               code = CODE_NAME_INDEX_Minus;
4898               break;
4899             case VK_OEM_PERIOD:
4900               code = CODE_NAME_INDEX_Period;
4901               break;
4902             case VK_OEM_2:
4903               code = CODE_NAME_INDEX_Slash;
4904               break;
4905             case VK_OEM_3:
4906               code = CODE_NAME_INDEX_Backquote;
4907               break;
4908             case VK_OEM_4:
4909               code = CODE_NAME_INDEX_BracketLeft;
4910               break;
4911             case VK_OEM_5:
4912               code = CODE_NAME_INDEX_Backslash;
4913               break;
4914             case VK_OEM_6:
4915               code = CODE_NAME_INDEX_BracketRight;
4916               break;
4917             case VK_OEM_7:
4918               code = CODE_NAME_INDEX_Quote;
4919               break;
4920             case VK_OEM_8:
4921               // Use keyCode value for "Backquote" key on UK keyboard layout.
4922               code = CODE_NAME_INDEX_Backquote;
4923               break;
4924             case VK_OEM_102:
4925               // Use keyCode value for "IntlBackslash" key.
4926               code = CODE_NAME_INDEX_IntlBackslash;
4927               break;
4928             case VK_ABNT_C1:  // "/" of ABNT.
4929               // Use keyCode value for "IntlBackslash" key on ABNT keyboard
4930               // layout.
4931               code = CODE_NAME_INDEX_IntlBackslash;
4932               break;
4933             default:
4934               MOZ_ASSERT_UNREACHABLE("Handle all OEM keycode values");
4935               return 0;
4936           }
4937           return WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(code);
4938         }
4939       }
4940       return WidgetUtils::ComputeKeyCodeFromChar(uniChars.CharAt(0));
4941     }
4942 
4943     // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2.  However, we're already
4944     // using NS_VK_SEPARATOR for the separator key on Mac and Linux.  Therefore,
4945     // We should keep consistency between Gecko on all platforms rather than
4946     // with other browsers since a lot of keyCode values are already different
4947     // between browsers.
4948     case VK_ABNT_C2:
4949       return NS_VK_SEPARATOR;
4950 
4951     // VK_PROCESSKEY means IME already consumed the key event.
4952     case VK_PROCESSKEY:
4953       return 0;
4954     // VK_PACKET is generated by SendInput() API, we don't need to
4955     // care this message as key event.
4956     case VK_PACKET:
4957       return 0;
4958     // If a key is not mapped to a virtual keycode, 0xFF is used.
4959     case 0xFF:
4960       NS_WARNING("The key is failed to be converted to a virtual keycode");
4961       return 0;
4962   }
4963 #ifdef DEBUG
4964   nsPrintfCString warning(
4965       "Unknown virtual keycode (0x%08X), please check the "
4966       "latest MSDN document, there may be some new "
4967       "keycodes we've never known.",
4968       aNativeKeyCode);
4969   NS_WARNING(warning.get());
4970 #endif
4971   return 0;
4972 }
4973 
ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const4974 KeyNameIndex KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(
4975     uint8_t aVirtualKey) const {
4976   if (IsPrintableCharKey(aVirtualKey) || aVirtualKey == VK_PACKET) {
4977     return KEY_NAME_INDEX_USE_STRING;
4978   }
4979 
4980   switch (aVirtualKey) {
4981 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
4982 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
4983   case aNativeKey:                                                     \
4984     return aKeyNameIndex;
4985 
4986 #include "NativeKeyToDOMKeyName.h"
4987 
4988 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
4989 
4990     default:
4991       break;
4992   }
4993 
4994   HKL layout = GetLayout();
4995   WORD langID = LOWORD(static_cast<HKL>(layout));
4996   WORD primaryLangID = PRIMARYLANGID(langID);
4997 
4998   if (primaryLangID == LANG_JAPANESE) {
4999     switch (aVirtualKey) {
5000 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
5001 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey,    \
5002                                                      aKeyNameIndex) \
5003   case aNativeKey:                                                  \
5004     return aKeyNameIndex;
5005 
5006 #include "NativeKeyToDOMKeyName.h"
5007 
5008 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
5009 
5010       default:
5011         break;
5012     }
5013   } else if (primaryLangID == LANG_KOREAN) {
5014     switch (aVirtualKey) {
5015 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
5016 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
5017   case aNativeKey:                                                            \
5018     return aKeyNameIndex;
5019 
5020 #include "NativeKeyToDOMKeyName.h"
5021 
5022 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
5023 
5024       default:
5025         return KEY_NAME_INDEX_Unidentified;
5026     }
5027   }
5028 
5029   switch (aVirtualKey) {
5030 #undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
5031 #define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
5032   case aNativeKey:                                                           \
5033     return aKeyNameIndex;
5034 
5035 #include "NativeKeyToDOMKeyName.h"
5036 
5037 #undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
5038 
5039     default:
5040       return KEY_NAME_INDEX_Unidentified;
5041   }
5042 }
5043 
5044 // static
ConvertScanCodeToCodeNameIndex(UINT aScanCode)5045 CodeNameIndex KeyboardLayout::ConvertScanCodeToCodeNameIndex(UINT aScanCode) {
5046   switch (aScanCode) {
5047 #define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \
5048   case aNativeKey:                                                       \
5049     return aCodeNameIndex;
5050 
5051 #include "NativeKeyToDOMCodeName.h"
5052 
5053 #undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX
5054 
5055     default:
5056       return CODE_NAME_INDEX_UNKNOWN;
5057   }
5058 }
5059 
SynthesizeNativeKeyEvent(nsWindowBase * aWidget,int32_t aNativeKeyboardLayout,int32_t aNativeKeyCode,uint32_t aModifierFlags,const nsAString & aCharacters,const nsAString & aUnmodifiedCharacters)5060 nsresult KeyboardLayout::SynthesizeNativeKeyEvent(
5061     nsWindowBase* aWidget, int32_t aNativeKeyboardLayout,
5062     int32_t aNativeKeyCode, uint32_t aModifierFlags,
5063     const nsAString& aCharacters, const nsAString& aUnmodifiedCharacters) {
5064   UINT keyboardLayoutListCount = ::GetKeyboardLayoutList(0, nullptr);
5065   NS_ASSERTION(keyboardLayoutListCount > 0,
5066                "One keyboard layout must be installed at least");
5067   HKL keyboardLayoutListBuff[50];
5068   HKL* keyboardLayoutList = keyboardLayoutListCount < 50
5069                                 ? keyboardLayoutListBuff
5070                                 : new HKL[keyboardLayoutListCount];
5071   keyboardLayoutListCount =
5072       ::GetKeyboardLayoutList(keyboardLayoutListCount, keyboardLayoutList);
5073   NS_ASSERTION(keyboardLayoutListCount > 0,
5074                "Failed to get all keyboard layouts installed on the system");
5075 
5076   nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
5077   HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
5078   if (loadedLayout == nullptr) {
5079     if (keyboardLayoutListBuff != keyboardLayoutList) {
5080       delete[] keyboardLayoutList;
5081     }
5082     return NS_ERROR_NOT_AVAILABLE;
5083   }
5084 
5085   // Setup clean key state and load desired layout
5086   BYTE originalKbdState[256];
5087   ::GetKeyboardState(originalKbdState);
5088   BYTE kbdState[256];
5089   memset(kbdState, 0, sizeof(kbdState));
5090   // This changes the state of the keyboard for the current thread only,
5091   // and we'll restore it soon, so this should be OK.
5092   ::SetKeyboardState(kbdState);
5093 
5094   OverrideLayout(loadedLayout);
5095 
5096   uint8_t argumentKeySpecific = 0;
5097   switch (aNativeKeyCode & 0xFF) {
5098     case VK_SHIFT:
5099       aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R);
5100       argumentKeySpecific = VK_LSHIFT;
5101       break;
5102     case VK_LSHIFT:
5103       aModifierFlags &= ~nsIWidget::SHIFT_L;
5104       argumentKeySpecific = aNativeKeyCode & 0xFF;
5105       aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_SHIFT;
5106       break;
5107     case VK_RSHIFT:
5108       aModifierFlags &= ~nsIWidget::SHIFT_R;
5109       argumentKeySpecific = aNativeKeyCode & 0xFF;
5110       aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_SHIFT;
5111       break;
5112     case VK_CONTROL:
5113       aModifierFlags &= ~(nsIWidget::CTRL_L | nsIWidget::CTRL_R);
5114       argumentKeySpecific = VK_LCONTROL;
5115       break;
5116     case VK_LCONTROL:
5117       aModifierFlags &= ~nsIWidget::CTRL_L;
5118       argumentKeySpecific = aNativeKeyCode & 0xFF;
5119       aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_CONTROL;
5120       break;
5121     case VK_RCONTROL:
5122       aModifierFlags &= ~nsIWidget::CTRL_R;
5123       argumentKeySpecific = aNativeKeyCode & 0xFF;
5124       aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_CONTROL;
5125       break;
5126     case VK_MENU:
5127       aModifierFlags &= ~(nsIWidget::ALT_L | nsIWidget::ALT_R);
5128       argumentKeySpecific = VK_LMENU;
5129       break;
5130     case VK_LMENU:
5131       aModifierFlags &= ~nsIWidget::ALT_L;
5132       argumentKeySpecific = aNativeKeyCode & 0xFF;
5133       aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_MENU;
5134       break;
5135     case VK_RMENU:
5136       aModifierFlags &= ~nsIWidget::ALT_R;
5137       argumentKeySpecific = aNativeKeyCode & 0xFF;
5138       aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_MENU;
5139       break;
5140     case VK_CAPITAL:
5141       aModifierFlags &= ~nsIWidget::CAPS_LOCK;
5142       argumentKeySpecific = VK_CAPITAL;
5143       break;
5144     case VK_NUMLOCK:
5145       aModifierFlags &= ~nsIWidget::NUM_LOCK;
5146       argumentKeySpecific = VK_NUMLOCK;
5147       break;
5148   }
5149 
5150   AutoTArray<KeyPair, 10> keySequence;
5151   WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags);
5152   keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific));
5153 
5154   // Simulate the pressing of each modifier key and then the real key
5155   // FYI: Each NativeKey instance here doesn't need to override keyboard layout
5156   //      since this method overrides and restores the keyboard layout.
5157   for (uint32_t i = 0; i < keySequence.Length(); ++i) {
5158     uint8_t key = keySequence[i].mGeneral;
5159     uint8_t keySpecific = keySequence[i].mSpecific;
5160     uint16_t scanCode = keySequence[i].mScanCode;
5161     kbdState[key] = 0x81;  // key is down and toggled on if appropriate
5162     if (keySpecific) {
5163       kbdState[keySpecific] = 0x81;
5164     }
5165     ::SetKeyboardState(kbdState);
5166     ModifierKeyState modKeyState;
5167     // If scan code isn't specified explicitly, let's compute it with current
5168     // keyboard layout.
5169     if (!scanCode) {
5170       scanCode =
5171           ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
5172     }
5173     LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
5174     // If the scan code is for an extended key, set extended key flag.
5175     if ((scanCode & 0xFF00) == 0xE000) {
5176       lParam |= 0x1000000;
5177     }
5178     bool makeSysKeyMsg = IsSysKey(key, modKeyState);
5179     MSG keyDownMsg =
5180         WinUtils::InitMSG(makeSysKeyMsg ? WM_SYSKEYDOWN : WM_KEYDOWN, key,
5181                           lParam, aWidget->GetWindowHandle());
5182     if (i == keySequence.Length() - 1) {
5183       bool makeDeadCharMsg =
5184           (IsDeadKey(key, modKeyState) && aCharacters.IsEmpty());
5185       nsAutoString chars(aCharacters);
5186       if (makeDeadCharMsg) {
5187         UniCharsAndModifiers deadChars =
5188             GetUniCharsAndModifiers(key, modKeyState);
5189         chars = deadChars.ToString();
5190         NS_ASSERTION(chars.Length() == 1,
5191                      "Dead char must be only one character");
5192       }
5193       if (chars.IsEmpty()) {
5194         NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
5195         nativeKey.HandleKeyDownMessage();
5196       } else {
5197         AutoTArray<NativeKey::FakeCharMsg, 10> fakeCharMsgs;
5198         for (uint32_t j = 0; j < chars.Length(); j++) {
5199           NativeKey::FakeCharMsg* fakeCharMsg = fakeCharMsgs.AppendElement();
5200           fakeCharMsg->mCharCode = chars.CharAt(j);
5201           fakeCharMsg->mScanCode = scanCode;
5202           fakeCharMsg->mIsSysKey = makeSysKeyMsg;
5203           fakeCharMsg->mIsDeadKey = makeDeadCharMsg;
5204         }
5205         NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, 0, &fakeCharMsgs);
5206         bool dispatched;
5207         nativeKey.HandleKeyDownMessage(&dispatched);
5208         // If some char messages are not consumed, let's emulate the widget
5209         // receiving the message directly.
5210         for (uint32_t j = 1; j < fakeCharMsgs.Length(); j++) {
5211           if (fakeCharMsgs[j].mConsumed) {
5212             continue;
5213           }
5214           MSG charMsg = fakeCharMsgs[j].GetCharMsg(aWidget->GetWindowHandle());
5215           NativeKey nativeKey(aWidget, charMsg, modKeyState);
5216           nativeKey.HandleCharMessage(charMsg);
5217         }
5218       }
5219     } else {
5220       NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
5221       nativeKey.HandleKeyDownMessage();
5222     }
5223   }
5224   for (uint32_t i = keySequence.Length(); i > 0; --i) {
5225     uint8_t key = keySequence[i - 1].mGeneral;
5226     uint8_t keySpecific = keySequence[i - 1].mSpecific;
5227     uint16_t scanCode = keySequence[i - 1].mScanCode;
5228     kbdState[key] = 0;  // key is up and toggled off if appropriate
5229     if (keySpecific) {
5230       kbdState[keySpecific] = 0;
5231     }
5232     ::SetKeyboardState(kbdState);
5233     ModifierKeyState modKeyState;
5234     // If scan code isn't specified explicitly, let's compute it with current
5235     // keyboard layout.
5236     if (!scanCode) {
5237       scanCode =
5238           ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
5239     }
5240     LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
5241     // If the scan code is for an extended key, set extended key flag.
5242     if ((scanCode & 0xFF00) == 0xE000) {
5243       lParam |= 0x1000000;
5244     }
5245     // Don't use WM_SYSKEYUP for Alt keyup.
5246     bool makeSysKeyMsg = IsSysKey(key, modKeyState) && key != VK_MENU;
5247     MSG keyUpMsg = WinUtils::InitMSG(makeSysKeyMsg ? WM_SYSKEYUP : WM_KEYUP,
5248                                      key, lParam, aWidget->GetWindowHandle());
5249     NativeKey nativeKey(aWidget, keyUpMsg, modKeyState);
5250     nativeKey.HandleKeyUpMessage();
5251   }
5252 
5253   // Restore old key state and layout
5254   ::SetKeyboardState(originalKbdState);
5255   RestoreLayout();
5256 
5257   // Don't unload the layout if it's installed actually.
5258   for (uint32_t i = 0; i < keyboardLayoutListCount; i++) {
5259     if (keyboardLayoutList[i] == loadedLayout) {
5260       loadedLayout = 0;
5261       break;
5262     }
5263   }
5264   if (keyboardLayoutListBuff != keyboardLayoutList) {
5265     delete[] keyboardLayoutList;
5266   }
5267   if (loadedLayout) {
5268     ::UnloadKeyboardLayout(loadedLayout);
5269   }
5270   return NS_OK;
5271 }
5272 
5273 /*****************************************************************************
5274  * mozilla::widget::DeadKeyTable
5275  *****************************************************************************/
5276 
GetCompositeChar(char16_t aBaseChar) const5277 char16_t DeadKeyTable::GetCompositeChar(char16_t aBaseChar) const {
5278   // Dead-key table is sorted by BaseChar in ascending order.
5279   // Usually they are too small to use binary search.
5280 
5281   for (uint32_t index = 0; index < mEntries; index++) {
5282     if (mTable[index].BaseChar == aBaseChar) {
5283       return mTable[index].CompositeChar;
5284     }
5285     if (mTable[index].BaseChar > aBaseChar) {
5286       break;
5287     }
5288   }
5289 
5290   return 0;
5291 }
5292 
5293 /*****************************************************************************
5294  * mozilla::widget::RedirectedKeyDownMessage
5295  *****************************************************************************/
5296 
5297 MSG RedirectedKeyDownMessageManager::sRedirectedKeyDownMsg;
5298 bool RedirectedKeyDownMessageManager::sDefaultPreventedOfRedirectedMsg = false;
5299 
5300 // static
IsRedirectedMessage(const MSG & aMsg)5301 bool RedirectedKeyDownMessageManager::IsRedirectedMessage(const MSG& aMsg) {
5302   return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
5303          (sRedirectedKeyDownMsg.message == aMsg.message &&
5304           WinUtils::GetScanCode(sRedirectedKeyDownMsg.lParam) ==
5305               WinUtils::GetScanCode(aMsg.lParam));
5306 }
5307 
5308 // static
RemoveNextCharMessage(HWND aWnd)5309 void RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd) {
5310   MSG msg;
5311   if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
5312                             PM_NOREMOVE | PM_NOYIELD) &&
5313       (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
5314     WinUtils::PeekMessage(&msg, aWnd, msg.message, msg.message,
5315                           PM_REMOVE | PM_NOYIELD);
5316   }
5317 }
5318 
5319 }  // namespace widget
5320 }  // namespace mozilla
5321