Users can emulate AltGr key with pressing both Ctrl key and Alt key on Windows
since AltGr is represented as so in Windows and physical keyboard may not have
AltRight key.
If user emulates AltGr key, we should set MODIFIER_ALTGRAPH to a set of
keyboard events for printable keys only when the key press produces
character(s) or a dead key. For example:
1. ControlLeft keydown event should make ctrlKey true.
2. AltLeft keydown event should make altKey true (not AltGraph state).
3. ctrlKey and altKey of printable keydown, keypress and keyup events should be
set to false, but getModifierState("AltGraph") should return true.
4. AltLeft keyup event should make altKey false.
5. ControlLeft keyup event should make ctrlKey false.
(If AltLeft key is pressed first, altKey of AltLeft keydown is true and
both altKey and ctrlKey of the following ControlLeft keydown are true as
usual.)
MozReview-Commit-ID: 8Km8GXPDQw1
KeyboardLayout::InitNativeKey() takes |const ModifierKeyState&| as its
argument with NativeKey reference and it calls some internal methods with
the given ModifierKeyState without any changes. Additionally, its caller
is only NativeKey::InitWithKeyChar() and its called with given NativeKey
instance's mModKeyState. So, removing the redundant arguments from
some methods makes them clearer what they compute with.
So, this patch does not change any behavior.
MozReview-Commit-ID: 3w9Ee7PMU05
By the proposal from Google, <https://github.com/w3c/uievents/issues/147>,
Chromium treat AltRight key as "AltGraph" modifier if the keyboard layout
has AltGr key.
When AltRight key is pressed with a keyboard layout which has AltGr key,
modifiers should as following:
1. "keydown" for ControlLeft:
ctrlKey: true, altKey: false, getModifierState("AltGraph"): false
2. "keydown" for AltRight:
ctrlKey: false, altKey: false, getModifierState("AltGraph"): true
3. Some "keydown", "keypress" and "keyup" events:
ctrlKey: false, altKey: false, getModifierState("AltGraph"): true
4. "keyup" for ControlLeft:
ctrlKey: false, altKey: false, getModifierState("AltGraph"): true
5. "keyup" for AltRight:
ctrlKey: false, altKey: false, getModifierState("AltGraph"): false
So, only when the preceding "keydown" event for ControlLeft, ctrlKey should
be set to true as usual. However, after AltRight key is pressed actually,
we should treat "AltGraph" modifier is true and both ctrlKey and altKey
should be set to false for web apps can handle text input normally.
So, MODIFIER_ALTGRAPH and MODIFIER_CONTROL/MODIFIER_ALT should not be set
at the same time.
This patch makes ModifierKeyState have only MODIFIER_ALTGRAPH or
MODIFIER_CONTROL/MODIFIER_ALT.
Additionally, this patch makes VirtualKey::ShiftState treat "AltGraph" as a
modifier. So, now, VirtualKey needs to convert ShiftState to index value when
it accesses its mShiftStates array. Therefore, this patch adds
VirtualKey::ToIndex() and make each VirtualKey method use it before
accessing mShiftStates.
Note that this patch also fixes bug of WinUtils::SetupKeyModifiersSequence().
The constructor of KeyPair takes 2 keycode values, but the second virtual
keycode can have scancode to distinguish if the key is left or right.
However, WinUtils::SetupKeyModifiersSequence() never sets scancode to
KeyPair. Therefore, it fails to dispatch AltRight key event.
MozReview-Commit-ID: 7ealxJH9KlZ
For setting AltRight key's key value to "AltGraph" if it should work as so,
we need to know if current keyboard layout has AltGr key. Unfortunately,
Windows doesn't provide such information but we retrieve all input characters
from each key when a keyboard layout is loaded. So, when we load a keyboard
layout, we can mark if current keyboard layout has AltGr key with checking
at least one key inputs different character(s) when AltGr key is pressed.
MozReview-Commit-ID: 8GI3phSVTUS
Currently, TabChild discards eKeyDown and eKeyPress events which are marked as
"repeated" and were dispatched after the latest eKeyDown event comes into the
process. However, keyboard layout utils may generate native key events
as "repeated" even if each native key is important to input proper text.
So, TabChild shouldn't decide if coming keyboard event is skippable only with
mIsRepeat. For solving this issue, this patch adds
mMaybeSkippableInRemoteProcess to WidgetKeyboardEvent and makes
TabChild::SkipRepeatedKeyEvent() check
WidgetKeyboardEvent::CanSkipInRemoteProcess() instead.
On Windows, there are two ways to generate keyboard input messages. One is
using SendMessage() or PostMessage(). The other is SendInput() API. In both
ways, utils can make their input as repeated key messages.
The former case must be safe for this issue since such utils need to set 31st
bit of lParam to 1 explicitly.
On the other hand, in the latter case, the utils probably need to append
KEYEVENTF_KEYUP into KEYBDINPUT::dwFlags. Otherwise, only first call is
treated as non-repeated event.
So, when given message does not came from physical key operation, NativeKey
should set WidgetKeyboardEvent::mMaybeSkippableInRemoteProcess to false
even if WidgetKeyboardEvent::mIsRepeat is true.
MozReview-Commit-ID: 3rinrOjx8Tf
inline functions are supposed to be declared in the header file, so the compiler can inline them.
gcc complains about this, but clang/msvc apparently do not.
We also needed to move the DeadKey struct and class into the header, as the function calls a
method on the DeadKey class, and you can't do that on a forward declared class.
MozReview-Commit-ID: 8NxP59AXuZi
Starting from 52, NativeKey::HandleCharMessage() ignores all control characters. However, some keyboard layout utilities may send WM_CHAR message whose wParam is '\r' for emulating pressing Enter key. For supporting such utilities, we should dispatch Enter keypress event when HandleCharMessage() receives such event.
Note that this patch does NOT support a pair of WM_KEYDOWN and WM_CHAR whose wParam is '\r' but the WM_KEYDOWN isn't VK_RETURN. If there is such case, we need to support it too. However, it needs a lot of code changes. So, we shouldn't support it until such bug is filed actually.
MozReview-Commit-ID: CWyvBtLmXgg
Ctrl+Space causes WM_CHAR of ' '. On the other native applications, you can input ' ' with this key combination though, we shouldn't allow this because we need to remove Ctrl and Alt modifier state at dispatching keypress event for the limitation of TextEditor but this is important key combination for custom shortcut keys.
So, when Ctrl or Alt key is pressed but it doesn't change the inputting character, i.e., the character can be inputted without Ctrl or Alt, we shouldn't remove those modifier state from eKeyPress event.
MozReview-Commit-ID: 7omLvNdQWzW
In PresShell, eContextMenu event is marked as dispatched only in chrome when its shiftKey state is true. However, Shift+F10 causes the context menu, it should not be marked as so because this is standard shortcut key to open context menu on Windows.
This patch consumes Shift key state if previous key message is WM_SYSKEYDOWN of F10 before dispatching eContextMenu event. So, user cannot block to prevent its default at opening context menu with Shift+F10, we should discuss this later.
MozReview-Commit-ID: 1P9LpeJoQof
Currently, we use alias NS_VK_* for WidgetKeyboardEvent::mKeyCode. Similarly, we should create alias enum for nsIDOMKeyEvent::DOM_KEY_LOCATION_*. Then, we can reduce the length and avoid to include nsIDOMKeyEvent in some cpp files.
MozReview-Commit-ID: 5cs4zQ061Lc
NativeKey::GetFollowingCharMessage() may remove a char message which is different from previously found message in the queue because hacky keyboard layout or utility can overwrite the wParam when it's removed from the queue.
Now, we should assume that newer message, i.e., actually removed from the queue, is the expected message by the user. See bug 1336028 comment 0 for the actual scenarios which are collected by crash reports.
https://bugzilla.mozilla.org/show_bug.cgi?id=1336028#c0
MozReview-Commit-ID: 9ZgukHH1vfi
There are still a lot of crash due to failing to get following WM_CHAR message. Almost half of them are, we found a WM_CHAR message but it's gone at removing the message from the queue.
Although, we're still not sure what happen actually. It could be possible if somebody hooks PeekMessage() or something. Then, we can assume that the found message isn't necessary for the user because it must be removed by somebody when it became unnecessary or is handled.
This patch mark a new bool flag, mCharMessageHasGone, as true in such case. Then, NativeKey will dispatch keypress events without following char messages and mark the event as consumed.
MozReview-Commit-ID: mporX1sihC
When NativeKey crashes by itself, it means that we detect an impossible situation in usual environment. In such case, active 3rd party's keyboard layout or something other utility may hook API and returns odd result to us.
For investigating the cause and deciding what we should do in such cases, we should collect active keyboard layout name via crash reports.
MozReview-Commit-ID: HYRj24GwDHZ
I did my best to remove as much stuff as possible in this patch. The starting
point was to remove all the IsVistaOrLater() and IsWin7OrLater() calls, but I
also grepped for various strings and found some other removable stuff that way.
I may have still missed some things.
Notable things done by this patch.
- It removes numerous blocklist entries.
- It removes CanComputeVirtualKeyCodeFromScanCode(), because it's always true
now.
- It removes ShowXP{Folder,File}Picker(), even though these were available as
fallbacks on Vista+. The "when platform is built without the longhorn SDK"
condition in the comment above nsFilePicker::ShowXPFolderPicker() sounds like
it won't ever happen any more.
- It removes the config.trim_on_minimize preference. This requires adding a
bool sHaveInitializedPrefs variable; previously the lack of pref
initialization was indicated by the tri-state sTrimOnMinimize variable having
the value 2.
Notable things *not* done by this patch.
- ClearThemeRegion() still exists. The comment suggests that it is XP/Vista
only, but the code suggests otherwise. jimm thinks the comment is wrong.
- The comment in WinWakeLockListener::Callback() suggests that the StartTimer()
call is no longer needed to block the screen saver. I'm uncertain about this
and so I think it's best left to a follow-up.
Currently, KeyboardLayout doesn't support chained dead keys because probably, the initial developer didn't expect there are such keyboard layout. Additionally, if we'd try to handle them with KeyboardLayout, it'd need to create too big and too complicated table at loading such keyboard layout. It's really nightmare. Therefore, this patch takes different approach.
Currently, when WM_(SYS)KEYDOWN is received, KeyboardLayout (and NativeKey) respects following WM_(SYS)CHAR. Similarly, this patch makes KeyboardLayout respect WM_(SYS)DEADCHAR when it handles dead key. If WM_(SYS)KEYDOWN is followed by WM_DEADCHAR, that means that the key press is in a dead key sequence and not finishing the existing dead key sequence. Therefore, when WM_(SYS)KEYDOWN is followed by WM_(SYS)DEADCHAR, KeyboardLayout activates dead key sequence.
For supporting dead key chain, this patch makes KeyboardLayout::mActiveDeadKey and KeyboardLayout::mDeadKeyShiftState arrays. When dead keydown message is received, KeyboardLayout appends an item to each of them. (I.e., when the array is not empty, it's in a dead key sequence.)
When WM_(SYS)KEYUP is received, KeyboardLayout checks if it's in mActiveDeadKey. If it's included in the array, it initializes NativeKey as a dead keyup event.
Otherwise, when non-printable key (probably) is received in a dead key sequence, KeyboardLayout doesn't handle it as a part of the dead key sequence. For example, a modifier key may be pressed for next key. (Even if the keyboard layout maps text input to a non-printable key, we can ignore them because such key's KeyboardEvent.key value should be decided only with the virtual keyboard.)
MozReview-Commit-ID: 9n8B0YYuKCO
Similarly, NativeKey is a stack class and mFollowingCharMsgs which stores following char messages of WM_(SYS)KEYDOWN should be AutoTArray for preventing to use heap at handling inputs with usual keyboard layout.
5 is enough size for handling usual keyboard layout because we support only 5 or less characters per dead key sequence.
MozReview-Commit-ID: IphcIOmPW0C
Fortunately, UniCharsAndModifiers instances are only in stack. Therefore, we can make it a stack class and use nsAutoString and AutoTArray for not using heap at handling inputs from usual keyboard layouts.
MozReview-Commit-ID: 9ZPbdjGst64
Now, we have an security issue. mCommittedCharsAndModifiers may be initialized with multiple WM_(SYS)CHAR messages. However, if it's generated by odd (or malicious) middleware, mCommittedCharsAndModifiers may be overflown because it has only fixed array. For fixing this issue, first, we should hide the members for making the users not depend on the design of UniCharsAndModifiers.
This patch changes UniCharsAndModifiers to a class and hiding mChars and adding |CharAt() const|.
MozReview-Commit-ID: 5EjrIhmCdE4
This patch creates NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages() for dispatching eKeyPress event with mCommittedCharsAndModifiers when it stores following printable WM_(SYS)CHAR messages.
Using loop for dispatching eKeyPress event for every WM_(SYS)CHAR message is wrong because WidgetKeyboardEvent::mKeyValue is initialized with mCommittedCharsAndModifiers and it causes TextEventDispatcher dispatching multiple eKeyPress events at every call of MaybeDispatchKeypressEvents(). Therefore, if mKeyValue is "^^", eKeyPress event is dispatched 4 times --for the first message, eKeyPress events are fired for each "^" and for the second message, eKeyPress events are fired again for each "^"--. Therefore, when it handles WM_(SYS)KEYDOWN and it causes inputting one or more printable characters, it's the easiest way not to use HandleCharMessage().
The new method calls TextEventDispatcher::MaybeDispatchKeypressEvents() only once and it requests to call the callback method with new argument of MaybeDispatchKeypressEvents() when it needs to dispatch 2 or more eKeyPress events. Then, NativeKey::WillDispatchKeyboardEvent() can set each eKeyPress event to raw information of the message and proper modifier state.
With this change, we can dispatch multiple eKeyPress events with retrieved WM_(SYS)CHAR message information rather than retrieved information from active keyboard layout. Therefore, NeedsToHandleWithoutFollowingCharMessages() doesn't return true even when mCommittedCharsAndModifiers stores two or more characters.
FYI: there is a bug in test_keycodes.xul. That is, Alt+'A' of Greek keyboard layout should cause WM_SYSCHAR with a corresponding Greek character but ASCII characters are specified. Therefore, this patch includes the fix of these bugs
MozReview-Commit-ID: JVm7ZJVug0O
First, mCommittedCharsAndModifiers should be initialized with following char messages because the messages could be different from the information of current keyboard layout.
So, this patch guarantees that mCommittedCharsAndModifiers are same as the user expected when there is one or more WM_CHAR or WM_SYSCHAR messages.
MozReview-Commit-ID: I5Ack0xccoL
Currently, Enter and Backspace keys are handled without following WM_(SYS)CHAR message. However, older code needs hack for them for avoiding conflict with Ctrl+J vs. Ctrl+Enter, etc.
So, we can get rid of them now. And when a keydown causes inputting a control character, NativeKey should handle it with keyboard layout (i.e., without following char message(s)).
MozReview-Commit-ID: 6bVuK0BzFbx
Currently, NativeKey::HandleCharMessage() is only a public method and it takes any char message. However, when it's called outside of NativeKey, it should work only with NativeKey::mMsg.
Therefore, we should make current HandleCharMessage() a private method and create new overload method which doesn't take MSG as an argument.
MozReview-Commit-ID: LowV2FUmR3U
For consistency with IsPrintableCharMessage(), IsFollowedByNonControlCharMessage() should be renamed to IsFollowedByPrintableCharMessage().
MozReview-Commit-ID: CBJFPO4FZej
Currently, NativeKey::IsPrintableCharMessage() returns true if given message is WM_CHAR or WM_SYSCHAR. However, WM_SYSCHAR never causes inputting any character and even if WM_CHAR has a control character (i.e., non-printable character), it returns true.
MozReview-Commit-ID: IoU5F06WImz
When key combination is reserved by the system, web apps shouldn't be able to consume the key events. In such case, we've decided that we never expose the key events in web contents (including chrome contents). Therefore, NativeKey stops dispatching keyboard events only for Alt+Space.
However, new code of the fix of bug 1300003 always consumes WM_SYSCHAR which follows WM_SYSKEYDOWN of Alt+Space. This is the cause of bug 1305943.
For fixing this bug, NativeKey should have a helper method, IsReservedBySystem(), and when it returns true, it should do nothing when Handle*Message() is called and should not consume following WM_SYSCHAR messages at handling WM_*KEYDOWN.
Unfortunately, it's impossible to test this regression because nsDOMWindowUtils::SendNativeKeyEvent() may call nsIWidget::SynthesizeNativeKeyEvent() asynchronously. See <https://dxr.mozilla.org/mozilla-central/source/dom/base/nsDOMWindowUtils.cpp#1105-1108>. Therefore, it cannot return if it's consumed.
MozReview-Commit-ID: 9ABh2rYNkFs
We usually declare class members with following order:
1. public members
2. private members
3. friends
However, current KeyboardLayout is declared with completely opposite order. Let's use usual order for preventing mistakes.
MozReview-Commit-ID: LwOcEUbJzes
Currently, checking if it's in dead key sequence directly refers mActiveDeadKey. However, this isn't clear for most developers. So, let's create a helper method, IsInDeadKeySequence(), and wrap the nonintuitive check.
MozReview-Commit-ID: 7qTer9R8Gfs
This patch creates KeyboardLayout::MaybeInitNativeKeyAsDeadKey() for wrapping dead key handling code in KeyboardLayout::InitNativeKey().
This makes InitNativeKey() code simpler. Now, any developers must be able to understand what InitNativeKey() does easier than before fixing this bug.
MozReview-Commit-ID: C59ESUXeTxU
There is DeactivateDeadKeyState() but not ActivateDeadKeyState(). There should be both of them and hides the dead key state management into them.
MozReview-Commit-ID: JvAPE5f2HVy
VirtualKey::GetCompositeChar() needs index of virtual keycode which may make around the caller messy. So, KeyboardLayout::GetCompositeChar() should wrap it and KeyboardLayout::MaybeInitNativeKeyWithCompositeChar() should use it.
MozReview-Commit-ID: 8KLTJpCFZ8u
Similar to VirtualKey::GetUniChars(), VirtualKey::GetNativeUniChars() needs key index. So, it should be wrapped by a new helper method, KeyboardLayout::GetNativeUniCharsAndModifiers(), and KeyboardEvent::InitNativeKey() should use this instead of accessing its member's GetNativeUniChars().
MozReview-Commit-ID: 7M9OlNF698Y
When InitNativeKey() retrieves UniCharsAndModifiers for a key, it needs key index for the given virtual keycode. Therefore, wrapping the code with GetUniCharsAndModifiers() makes InitNativeKey() code simpler since each call specifies the virtual keycode to the method instead of key index.
MozReview-Commit-ID: Azy8chXexaz
This patch gets rid of |shiftState| from KeyboardLayout::InitNativeKey() and make each caller clearer. This must make other developers understand what modifier state is used at each call.
MozReview-Commit-ID: 6zydP1jkffv
When NativeKey tries to remove a char message from the queue, another NativeKey instance might be created due to odd API hook or something. In such case, the old instance should handle the received message and the new instance should do nothing for keeping the order of message handling.
This patch makes:
* NativeKey::GetFollowingCharMsg() store removing char message to mRemovingMsg before calling PeekMessage() with PM_REMOVE.
* NativeKey::InitWithChar() set the old instance's mReceivedMsg to the received char message and do nothing even if HandleCharMessage() is called later.
* NativeKey::GetFollowingCharMsg() return received char message if mReceivedMsg is set during a call of PeekMessage().
MozReview-Commit-ID: KXYW0GgC9AY
For detecting nested creation of NativeKey instances, NativeKey should manage the latest instance with sLastestInstance for the other instances and previous instance with mLastInstance.
MozReview-Commit-ID: BFZ0cr1640S
Currently, NativeKey::DispatchPluginEventsAndDiscardsCharMessages() calls nsWindowBase::DispatchPluginEvent() and nsWindowBase::DispatchPluginEvent() does nothing when windowless plugin doesn't have focus. However, this is unclear when other developers read the code of DispatchPluginEventsAndDiscardsCharMessages() and it causes unnecessary virtual calls. So, it should try to dispatch plugin events only when a windowless plugin has focus.
For making the check safer, nsWindowBase should expose the method to check it as ShouldDispatchPluginEvent(). Unfortunately, we cannot mark this method as const due to PluginHasFocus() needs to be not const method, though. Then, for loops in DispatchPluginEventsAndDiscardsCharMessages() should check it at each try.
This change helps to log the behavior (working on bug 1297013) without noise.
Additionally, this patch renames the method to MaybeDispatchPluginEventsForRemovedCharMessages() because it doesn't remove any char messages anymore.
MozReview-Commit-ID: F14Lcx47M6U
NativeKey removes odd WM_CHAR messages which are caused by ATOK or WXG if the user tries to do "Kakutei-Undo" (meaning "undo the last commit") after dispatching eKeyDown event.
However, NativeKey should remove them from the queue first because there are some problems:
* If focus is moved during dispatching an eKeyDown event, we'll fail to remove the messages from the queue.
* If dispatching eKeyDown advance native event loop due to entering to a modal loop or dosing synchronous XHR, the message pattern is broken before removing the odd messages from the queue.
After removing the odd char messages, NativeKey should store them with mRemovedOddCharMsgs because NativeKey needs to dispatch them to focused windowless plugin.
Note that this patch also fixes a bug of the loop to remove the odd WM_CHAR messages. Old code removes only one WM_CHAR messages, but we need to remove all WM_CHAR messages before WM_KEYUP. This must be a regression.
MozReview-Commit-ID: I60bcIx2SFS
NativeKey is now removing and storing following char messages when it's created for a keydown message. Therefore, IsFollowedByNonControlCharMessage() just refers the stored messages and it's enough fast. So, we can get rid of mIsFollowedByNonControlCharMessage.
MozReview-Commit-ID: 542A2sHNXeC
GetFollowingCharMessage() is now called only when removing following char message. Therefore, it does not need to have the optional argument indicating if removing the found message.
MozReview-Commit-ID: 7P39wyfSC1
While dispatching an event, focused widget may be changed. In such case, NativeKey shouldn't continue to dispatch remaining events (eKeyPress events) for preventing to dispatch to input text in unexpected website.
MozReview-Commit-ID: 7geuqks0LQK
In some cases, we may receive following char message of WM_*KEYDOWN *during* dispatching an eKeyDown event. In such case, NativeKey shouldn't dispatch eKeyPress event twice (one is caused by receiving WM_*CHAR message, the other is caused by post dispatching eKeyDown event code).
This patch makes NativeKey consume following WM_*CHAR messages before dispatching eKeyDown. Therefore, the former case will never occur.
For doing that, NativeKey stores following WM_*CHAR messages in mFollowingCharMsgs and uses it when it needs to dispatch eKeyPress events for each WM_*CHAR message.
MozReview-Commit-ID: 6QNvlwVVlTz
On some keyboard layouts, a key sequence, a dead key -> another dead key, may produce a composite character instead of two base characters for each key. For example, with "Russian - Mnemonic" keyboard layout on Win 8 or later, both 's' and 'c' are dead keys but key sequence, 's' -> 'c', produces a Unicode character.
For solving this issue, this patch fixes 2 bugs:
First, KeyboardLayout::GetDeadKeyCombinations() doesn't add dead key entry if 2nd key is a dead key (::ToUnicodeEx() returns -1). In such case, it should add a dead key entry with the first character which is produced when only the 2nd key is pressed (the character is called as "base character" and used for index of the dead key table).
Next, KeyboardLayout::InitNativeKey() should check if 2nd dead key press produces a composite character. If it's produced, it should initialize given NativeKey with the composite character. Otherwise, it should initialize with base characters of each key. This patch does it with KeyboardLayout::MaybeInitNativeKeyWithCompositeChar().
Finally, we should add automated test for this. However, unfortunately, it's not available on Win7 and our infra is still using Win7 for running automated tests. Therefore, this patch doesn't include new automated tests.
MozReview-Commit-ID: G1DrfkHKNcK
The new test failure is caused by a bug of the test API, KeyboardLayout::SysnthesizeNativeKeyEvent(). It doesn't generate WM_SYSKEY* messages nor WM_SYS*CHAR messages when Alt key is pressed. Therefore, the new path in the previous code works unexpectedly with automated tests.
This patch makes KeyboardLayout::SysnthesizeNativeKeyEvent() WM_SYS* message aware. When Alt key is pressed (but Ctrl key is not pressed) and the Alt key + something doesn't cause text input, the API generates WM_SYS* messages as expected.
MozReview-Commit-ID: FLbe4SYEZLf
Some keyboard utilities for Windows can change non-printable keys to printable keys. Therefore, if a keydown message is followed by one or more char message whose wParam isn't a control character, NativeKey should treat it as a printable key's event.
MozReview-Commit-ID: HoFbz5Zafeh