1. Why?
The description of events in the current UIEvents spec is woefully underspecified. This has led to different User Agents (UAs) implementing the same feature with different behaviors.
The intent with this document is to:
-
Describe the current behaviors that are shared by existing UAs
-
Identify behaviors where they differ
-
Initiate discussions to resolve the differences
Part of this process will necessarily require that we describe processes that rightfully belong in other specifications (e.g., Pointer Events or Input Events). The intent is to eventually move those portions into their appropriate home, but they are kept here while drafting this document to make it easier to discuss.
2. Native OS Requirements
The following is the set of assumptions that this specification makes about the underlying native operating system. It is expected that the native OS will provide these basic services for the UA.
In the event that the native OS does not provide these services, then the UA will need to implement them.
2.1. MouseEvent Requirements
The native OS platform will provide:
-
An event when the mouse is moved
-
An event when a mouse button is pressed
-
An event when a mouse button is released
-
A way to identify when a mouse button press should be interpreted as a "click"
-
For example, as a flag or as a separate event
-
If a separate "click" event is fired, then the native OS will fire it immediately after the corresponding "mouse up" event, with no intervening mouse-related events
-
-
A way to identify when a mouse click is a "double click"
For these events, the OS will be able to provide the following info:
-
The x,y mouse coordinates relative to the native OS desktop
-
The x,y mouse coordinates relative to the UA’s window viewport
-
Which keyboard modifiers are currently being held
2.2. PointerEvent Requirements
TODO: Specify native requirements here.
2.3. KeyboardEvent Requirements
The native OS platform will provide:
-
An event when a key is pressed
Note: On Windows: WM_KEYDOWN, WM_SYSKEYDOWN
Note: On macOS: NSKeyDown, NSFlagsChanged (for modifiers without other keys)
-
An event when a key is released
Note: On Windows: WM_KEYUP, WM_SYSKEYUP
Note: On macOS: NSKeyUp, NSFlagsChanged (for modifiers without other keys)
-
An event when a character should be generated as a result of a keypress
-
This may be a separate event, or it may be combined with the keydown event
-
If a separate event, then there are no intervening key events between keydown and char
-
Note: On Windows: WM_CHAR, WM_SYSCHAR
Note: On macOS: Combined with keydown
-
-
An event when text should be inserted
-
These are commonly used for alternate input devices like chordal keyboards or speech input
-
This may be the same event as for when a key is pressed
Note: On Windows: WM_CHAR (without associated keydown/keyup) Note: On macOS: NSTextInputClient with insertText
-
-
A way to identify key events that are "repeat"s from the key being held down
-
The platform will maintain a key repeat threshold
-
-
A way to identify the modifier keys that are held in combination with a key press
-
Either via flags in the messages, or via a separate call
Note: On Windows: included with WM_ messages
Note: On macOS: included with NSKey messages and NSFlagChanged
Note: On Linux (GTK): not provided with messages. need to request separately
-
2.4. IME Requirements
IMEs differ wildly on different platforms, and often have different capabilities (such as whether or not they can be "canceled") even on the same platform. What is the common set of requirements that we can rely on?
For example, on Windows, Win+'.' opens an emoji window that will generate composition events. But there is not indication from the OS that composition is about to take place. A similar problem exists with "shape writing" using the virtual keyboard.
2.5. Native Entry Points
2.5.1. Mouse
2.5.2. Touch
TODO: Include native touch events and resolve with native mouse events. How do these two event types interact on the common platforms? When are mouse events generated from touch events?
2.5.3. Keyboard
2.5.4. Clipboard
3. Event
Move to/merge with [DOM] spec Event
interface.
3.1. Event Interface
A Event
has the following additional internal state:
This is a proposal. See uievents/270
3.2. initialize an Event
- Input
-
event, the
Event
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
For reference, see initialize an event, list of event flags.
-
Initialize the following public attributes
-
Set event.
type
= eventType -
Set event.
target
= eventTarget -
Set event.
currentTarget
= null (This will be set appropriately during dispatch) -
Set event.
eventPhase
=NONE
(This will be set appropriately during dispatch) -
Set event.
bubbles
= true -
Set event.
cancelable
= true -
Set event.
defaultPrevented
= false -
Set event.
composed
= false // See COMPAT note for mouseenter and mouseleave -
Set event.
isTrusted
= false -
Set event.
timeStamp
= Number of milliseconds relative to the time origin
-
-
Initialize the following historical attributes
-
Set event.srcElement = eventTarget
-
Set event.cancelBubble = alias for stopPropagation
-
Set event.returnValue = alias for !canceled_flag
-
-
Initialize the following internal state
-
Unset event’s stop propagation flag
-
Unset event’s stop immediate propagation flag
-
Unset event’s canceled flag
-
Unset event’s in passive listener flag
-
Unset event’s composed flag
-
Unset event’s initialized flag
-
Unset event’s dispatch flag
-
-
Initialize the following proposed internal state
-
Unset event’s due to user interaction flag
-
4. UI Event
4.1. UIEvent Interface
A UIEvent
has the following:
view
detail
Along with the following historical attribute:
which
Add definition for UIEventInit
4.2. initialize a UIEvent
- Input
-
event, the
UIEvent
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize an Event with event, eventType and eventTarget
-
Initialize the following public attributes
-
Set event.
view
= the eventTarget’s node document’sWindow
object -
Set event.
detail
= 0
-
-
Initialize the following historical attributes
-
Set event.
which
= 0 (used by bothMouseEvent
andKeyboardEvent
)
-
-
If this event is the result of user interaction, then
-
Set event’s due to user interaction flag
Note: See uievents/270
-
Set event.
isTrusted
= false
-
Event firing for load, unload, abort, error, select. Should those be covered here or are they handled elsewhere already?
5. Focus Event
6. Mouse Event
6.1. MouseEvent Interface
A MouseEvent
has the following:
screenX
screenY
clientX
clientY
ctrlKey
shiftKey
altKey
metaKey
button
buttons
relatedTarget
6.2. Global State for MouseEvent
6.2.1. User Agent-Level State
The UA must maintain the following values that are shared for the entire User Agent.
A mouse button bitmask that tracks the current state of the mouse buttons.
6.2.2. Window-Level State
The UA must maintain the following values that are shared for the Window.
A last mouse element value (initially undefined) that keeps track
of the last Element
that we sent a MouseEvent to.
A last mouse DOM path value (initially empty) that contains a snapshot
of the ancestors Element
s of the last mouse element when the most recent mouse
event was sent.
6.3. initialize a MouseEvent
- Input
-
event, the
MouseEvent
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize a UIEvent with event, eventType and eventTarget
-
Initialize the following public attributes
-
Set event.
screenX
= the x-coordinate of the position where the event occurred relative to the origin of the desktop -
Set event.
screenY
= the y-coordinate of the position where the event occurred relative to the origin of the desktop -
Set event.
clientX
= the x-coordinate of the position where the event occurred relative to the origin of the viewport -
Set event.
clientY
= the y-coordinate of the position where the event occurred relative to the origin of the viewport -
Set event modifiers with event
-
Set event.
button
= 0 -
Set event.
buttons
= mouse button bitmask
-
-
Initialize CSSOM attributes for MouseEvent with event
6.4. create a MouseEvent
- Input
-
eventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Let event = the result of creating a new event using
MouseEvent
-
Initialize a MouseEvent with event, eventType and eventTarget
-
Return event
6.5. calculate MouseEvent button attribute
- Input
-
mbutton, an ID that identifies a mouse button
- Output
-
A button ID suitable for storing in the
MouseEvent
'sbutton
attribute
-
If mbutton is the primary mouse button, then return 0
-
If mbutton is the auxiliary (middle) mouse button, then return 1
-
If mbutton is the secondary mouse button, then return 2
-
If mbutton is the X1 (back) button, then return 3
-
If mbutton is the X2 (forward) button, then return 4
6.6. set MouseEvent attributes from native
- Input
-
event, the
MouseEvent
to initializenative, the native mouse event
- Output
-
None
-
If event.
type
is one of [ mousedown, mouseup ], then-
Let mbutton be an ID from native that identifies which mouse button was pressed
-
Set event.
button
= calculate MouseEvent button attribute with mbutton
-
6.7. handle native mouse down
- Input
-
native, the native mousedown
- Output
-
None
-
Let mbutton be an ID from native that identifies which mouse button was pressed
-
Update the mouse button bitmask as follows:
-
If mbutton is the primary mouse button, then set the 0x01 bit
-
If mbutton is the secondary mouse button, then set the 0x02 bit
-
If mbutton is the auxiliary (middle) mouse button, then set the 0x04 bit
-
-
Let target = hit test with viewport-relative coordinates from native
-
Let event = create a MouseEvent with "mousedown", target
-
Set MouseEvent attributes from native with native
-
Maybe send pointerdown event with event
-
Let result = dispatch event at target
-
If result is true and target is a focusable area that is click focusable, then
-
Run the focusing steps at target
-
-
if mbutton is the secondary mouse button, then
-
Maybe show context menu with native, target
-
6.8. handle native mouse up
- Input
-
native, the native mouseup
- Output
-
None
Note: Other mouse events can occur between the mousedown and mouseup.
-
Let mbutton be an ID from native that identifies which mouse button was pressed
-
Update the mouse button bitmask as follows:
-
If mbutton is the primary mouse button, then clear the 0x01 bit
-
If mbutton is the secondary mouse button, then clear the 0x02 bit
-
If mbutton is the auxiliary (middle) mouse button, then clear the 0x04 bit
-
-
Let target = hit test with viewport-relative coordinates from native
-
Let event = create a MouseEvent with "mouseup", target
-
Set MouseEvent attributes from native with native
-
Maybe send pointerup event with event
-
dispatch event at target
6.9. handle native mouse click
- Input
-
native, the native mouse click
- Output
-
None
Note: The platform should call this immediately after handle native mouse up for mouseups that generate clicks.
-
Let target = hit test with viewport-relative coordinates from native
-
Send click event with native and target.
6.10. send click event
- Input
-
native, the native mousedown
target, the
EventTarget
of the event - Output
-
None
-
Let mbutton = 1 (primary mouse button by default)
-
If native is valid, then
-
Let mbutton be an ID from native that identifies which mouse button was pressed
-
-
Let eventType = "auxclick"
-
If mbutton is the primary mouse button, then
-
Set eventType = "click"
-
-
Let event = create a PointerEvent with eventType and target
-
If native is valid, then
-
Set MouseEvent attributes from native with event, native
-
If event.
screenX
is not an integer value, then round it. -
If event.
screenY
is not an integer value, then round it.
-
-
dispatch event at target
Note: See pointerevents/100 for info about browsers using PointerEvents and rounded coordinates.
Note: Any "default action" is handled during dispatch by triggering the activation behavior algorithm for the target. So there is no need for handle that here. However, need to verify that the existing spec handles disabled/css-pointer-events/inert/...
Note: To handle `HTMLelement.click()`, call this algorithm with native = null and target = `HTMLelement`.
Note: To handle keyboard-initiated clicks, call this algorithm with native = null and target = currently focused element.
6.11. handle native mouse double click
- Input
-
native, the native mouse double click
- Output
-
None
Note: This should be called immediately after handle native mouse click for mouse clicks that generate double clicks.
-
Let mbutton be an ID from native that identifies which mouse button was pressed
-
If mbutton is not the primary mouse button, then return
-
Let target = hit test with viewport-relative coordinates from native
-
Let event = create a PointerEvent with "dblclick" and target
-
Set MouseEvent attributes from native with event, native
-
If event.
screenX
is not an integer value, then round it. -
If event.
screenY
is not an integer value, then round it. -
dispatch event at target
6.12. handle native mouse move
- Input
-
native, the native mouse move
- Output
-
None
This algorithm makes assumptions about the dispatch of PointerEvents because they are not currently specified explicitly. Once pointerevents/285 is resolved this may need to be updated.
-
Let target = hit test with viewport-relative coordinates from native
-
Let targetDomPath = calculate DOM path
-
Generate events for leaving the current element:
-
If last mouse element is defined and not equal to target, then
-
Let mouseout = create a MouseEvent with "mouseout" and last mouse element
TODO: Set mouseout attributes from native. +CSSOM attributes
-
Maybe send pointerout event with mouseout
-
Dispatch mouseout at target
-
Let leaveElements be a copy of last mouse DOM path with all elements common to targetDomPath removed.
-
For each element in leaveElements, do
Handle case where element has been deleted. Also case where it has been moved: Should the DOM mutation have triggered a mouseleave event? Should we sent it now? Should it be dropped? Need to verify what current browsers do.
-
Let mouseleave = create a MouseEvent with "mouseleave" and element
-
Set mouseleave.
bubbles
= false -
Set mouseleave.
cancelable
= false -
Set mouseleave.
composed
= falseCompat: Value of event.composed. Spec says false. Chrome/Linux = true Firefox/Linux = false
-
Maybe send pointerleave event with mouseleave
-
Let result = dispatch mouseleave at element
-
-
-
-
Generate events for entering the new element:
-
If target is not last mouse element, then
-
Let mouseover = create a MouseEvent with "mouseover" and target
TODO: Set mouseout attributes from native. +CSSOM attributes
-
Maybe send pointerover event with mouseover
-
Dispatch mouseout at target
-
Let enterElements be a copy of targetDomPath with all elements common to last mouse DOM path removed.
-
For each element in enterElements, do
Handle case where element has been deleted or moved.
-
Let mouseenter = create a MouseEvent with "mouseenter" and element
-
Set mouseenter.
bubbles
= false -
Set mouseenter.
cancelable
= false -
Set mouseenter.
composed
= falseCompat: Value of event.composed. Spec says false. Chrome/Linux = true Firefox/Linux = false
-
Maybe send pointerenter event with mouseenter
Compat for shadow DOM elements Chrome/Linux fires this event at the element and the shadow root
-
Let result = dispatch mouseenter at element
-
-
Set last mouse element to target
-
Set last mouse DOM path to targetDomPath
-
-
-
Let mousemove = create a MouseEvent with "mousemove" and element
-
Maybe send pointermove event with mousemove
-
Dispatch mousemove at element
6.13. maybe show context menu
- Input
-
native, the native mousedown or pointer event
target, the
EventTarget
of the event - Output
-
None
-
Let menuevent = create a PointerEvent with "contextmenu", target
-
If native is valid, then
-
Set MouseEvent attributes from native with native
-
-
Let result = dispatch menuevent at target
-
If result is true, then show the UA context menu
-
Note: To handle a context menu triggered by the keyboard, call this algorithm with native = null and target = currently focused element.
7. Wheel Event
8. Input Event
8.1. initialize an InputEvent
- Input
-
e, the
Event
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize a UIEvent with e, eventType and eventTarget
-
Initialize the following public attributes
-
Set event.data = null
-
Set event.isComposing = false
-
Set event.inputType = ""
-
Set event.composed = true
Note: Setting composed to true matches current UA behavior, but it makes more sense for this to be false. See whatwg/html/5453 for discussion.
-
-
Initialize the additional editing attributes from [[Input Events]]
Move the following into InputEvents spec (level 1 or level 2) since that’s where these attributes are defined.
-
Set e.dataTransfer = false
-
Set e.targetRanges = []
-
8.2. create an InputEvent
- Input
-
eventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Let e = the result of creating a new event using
InputEvent
-
Initialize an InputEvent with e, eventType and eventTarget
-
Return e
8.3. fire key input events
- Input
-
key, a DOMString containing the string corresponding to the key
target, the
EventTarget
of the event - Output
-
None
-
If suppress key input events flag is set, then
-
Exit (since the keydown was canceled)
-
Handle historical keypress event here. Return if cancelled.
-
Let inputType = null
-
Let data = null
How much of this can be moved into the [[Input Events]] spec? Issue: List more keys here
-
If key is "Backspace", then inputType = "deleteContentBackward"
-
If key is "Delete", then inputType = "deleteContentForward"
-
Otherwise,
-
inputType = "insertText"
inputType should be "insertParagraph" or "insertLineBreak" when pressing Enter.
-
data = key
-
-
If inputType is not null, then
Note: Need to verify Firefox behavior. Can be enabled by changing the "dom.input_events.beforeinput_enabled" pref in "about:config"
-
Let result = fire an InputEvent with "beforeinput", inputType and data
-
If result is false, then return.
-
Let textInputData be data.
-
Let shouldFireTextInput to true.
-
If inputType is either "insertParagraph" or "insertLineBreak", then:
-
Set textInputData to "\n".
-
If target is an
HTMLInputElement
, then set shouldFireTextInput to false.
-
-
If inputType is not one of "insertText", "insertParagraph" or "insertLineBreak", then set shouldFireTextInput to false.
-
If shouldFireTextInput is true, then:
-
Set result = fire a TextEvent with "textInput", and textInputData
Note: The "textInput" event is obsolete.
-
If result is false, then return.
-
Note: Perform DOM update here. Insert key into target element
Note: Compat: For insertFromPaste, Chrome has data = null, Firefox has data = same as beforeinput.
-
Fire an InputEvent with "input", inputType and data
-
8.4. fire an InputEvent
- Input
-
eventType, a DOMString containing the event type
inputType, a DOMString containing the input event type
data, a DOMString containing event data
- Output
-
None
What about target ranges? Need to add support here.
The target for input events should consider focus, but should also ensure that the element is editable and being modified. Compare: fire a compositionevent
-
Let target = currently focused area of a top-level browsing context
-
Let event = result of create an InputEvent with eventType, target
-
Set event.
inputType
= inputType -
Set event.
data
= data -
Return the result of dispatch event at target
9. Text Event
Note: TextEvent
is obsolete.
9.1. TextEvent Interface
See IDL definition in UI Events.
The data
attribute must return the value it was initialized to.
The initTextEvent(type, bubbles, cancelable, view, data)
method steps are:
-
If this’s dispatch flag is set, then return.
-
Initialize a UIEvent with this, type and eventTarget
-
Set this.
cancelable
= cancelable -
The bubbles/cancelable/view should be parameters to "Initialize a UIEvent" instead of being set twice.
9.2. initialize a TextEvent
- Input
-
e, the
Event
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize a UIEvent with e, eventType and eventTarget
-
Initialize the following public attributes
-
Set event.data = ""
-
9.3. create a TextEvent
- Input
-
eventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Let e = the result of creating a new event using
TextEvent
-
Initialize a TextEvent with e, eventType and eventTarget
-
Return e
9.4. fire a TextEvent
- Input
-
eventType, a DOMString containing the event type
data, a DOMString containing event data, or null
- Output
-
None
-
Let target = currently focused area of a top-level browsing context
-
Let event = result of create a TextEvent with eventType, target
-
If data is null, set data to the empty string.
-
Set event.
data
= data -
Return the result of dispatch event at target
10. Keyboard Event
10.1. KeyboardEvent Interface
A KeyboardEvent
has the following:
DOM_KEY_LOCATION_STANDARD
DOM_KEY_LOCATION_LEFT
DOM_KEY_LOCATION_RIGHT
DOM_KEY_LOCATION_NUMPAD
key
code
location
ctrlKey
shiftKey
altKey
metaKey
repeat
isComposing
Along with the following historical attributes:
keyCode
keyChar
And the following internal state:
10.2. Global State for KeyboardEvent
10.2.1. User Agent-Level State
The UA must maintain the following values that are shared for the entire User Agent.
A key modifier state (initially empty) that keeps track of the current state of each modifier key available on the system.
10.2.2. Window-Level State
The UA must maintain the following values that are shared for the Window.
A suppress key input events flag (initially false) that is used to suppress input events when the initial keydown event is canceled.
10.3. initialize a KeyboardEvent
- Input
-
event, the
KeyboardEvent
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize a UIEvent with event, eventType and eventTarget
-
Initialize the following public attributes
-
Set event.
key
= "" -
Set event.
code
= "" -
Set event.
location
=DOM_KEY_LOCATION_STANDARD
-
Set event.
shiftKey
= false -
Set event.
ctrlKey
= false -
Set event.
altKey
= false -
Set event.
metaKey
= false -
Set event.
repeat
= false -
Set event.
isComposing
= false
-
-
Initialize the following historical attributes
-
Initialize the following internal state
Need to review: ScrollLock, Hyper, Super, and (for virtual keyboards) Symbol, SymbolLock
-
Unset event’s shift flag
-
Unset event’s control flag
-
Unset event’s alt flag
-
Unset event’s altgraph flag
-
Unset event’s meta flag
-
Unset event’s capslock flag
-
Unset event’s numlock flag
-
10.4. create a KeyboardEvent
- Input
-
eventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Let e = the result of creating a new event using
KeyboardEvent
-
Initialize a KeyboardEvent with e, eventType and eventTarget
-
Return e
10.5. set event modifiers
- Input
-
event, the
KeyboardEvent
orMouseEvent
to update - Output
-
None
eval: ScrollLock, Hyper, Super, and (for virtual keyboards) Symbol, SymbolLock
-
Set event’s shift flag if key modifier state includes "Shift", unset it otherwise
-
Set event’s control flag if key modifier state includes "Control", unset it otherwise
-
Set event’s alt flag if key modifier state includes "Alt", unset it otherwise
-
Set event’s altgraph flag if key modifier state includes "AltGraph", unset it otherwise
-
Set event’s meta flag if key modifier state includes "Meta", unset it otherwise
-
Set event’s capslock flag if key modifier state includes "CapsLock", unset it otherwise
-
Set event’s numlock flag if key modifier state includes "NumLock", unset it otherwise
-
Set event.
shiftKey
= true if the event’s shift flag is set, false otherwise -
Set event.
ctrlKey
= true if the event’s control flag is set, false otherwise -
Set event.
altKey
= true if the event’s alt flag or altgraph flag is set, false otherwise -
Set event.
metaKey
= true if the event’s meta flag is set, false otherwise
10.6. set KeyboardEvent attributes
- Input
-
event, the
KeyboardEvent
to initializenativeKey, native key info
- Output
-
None
-
Set the following public attributes
-
Set event.
key
= the key attribute value for this key pressNeeds more formal description of non-printable characters
Need to include description of how AltGraph should be handled. See uievents/147
-
Set event.
code
= the key code attribute value corresponding to the physical key that was pressed. -
Set event.
location
= the result of calculate key location with event.code -
if nativeKey indicates that this is a repeat key event
-
Set event.
repeat
-
-
set event modifiers with event
-
-
Set the following historical attributes
TODO: For historical reasons, we can’t have a formal description of these fields without recognizing that certain UAs produce different values.
10.7. calculate key location
- Input
-
code, the
code
for the key - Output
-
The DOM key location for the specified key
-
If code is any of [ "AltLeft", "ControlLeft", "MetaLeft", "ShiftLeft"], then
-
return
DOM_KEY_LOCATION_LEFT
-
-
If code is any of [ "AltRight", "ControlRight", "MetaRight", "ShiftRight"], then
-
return
DOM_KEY_LOCATION_RIGHT
-
-
If code matches any of the values in the numpad section, then
-
return
DOM_KEY_LOCATION_NUMPAD
-
-
return
DOM_KEY_LOCATION_STANDARD
10.8. get modifier state
- Input
-
event, the
KeyboardEvent
to initializemodifier, a DOMString containing the name of the modifier key
- Output
-
True if the modifier is currently set, false otherwise
-
If modifier is "Shift", then return true if event’s shift flag is set
-
If modifier is "Control", then return true if event’s control flag is set
-
If modifier is "Alt", then return true if event’s alt flag is set
-
If modifier is "AltGraph", then return true if event’s altgraph flag is set
-
If modifier is "Meta", then return true if event’s meta flag is set
-
If modifier is "CapsLock", then return true if event’s capslock flag is set
-
If modifier is "NumLock", then return true if event’s numlock flag is set
-
Return false
10.9. handle pre browser key
- Input
-
key, basic info about the key
- Output
-
True is the User Agent has already handled this key
-
If Keyboard Lock is enabled, then return false
Note: Keyboard Lock is not an official standard. This is demonstrating how it might be integrated.
These key shortcuts are defined by the User Agent (e.g., Cmd-T on Mac). They should be defined in such a way that the UA is in control.
Need a more complete list of these pre-keydown browser keys, or a better description of the sort of keys the UA handles.
-
If key is the shortcut to create a new tab, then
-
Create a new tab
-
Return true
-
-
If key is the shortcut to close a window, then
-
Close the current tab
-
Return true
-
IME is often provided by the native OS. So the requirements need to be defined and added to the IME Requirements section.
How should IME keys be represented. We need the native OS to call enter composition mode and exit composition mode
When should begin composition be called? How should that be hooked with the native IME calls.
-
Return false
10.10. handle post browser key
- Input
-
key, basic info about the key
- Output
-
True is the User Agent has already handled this key
-
If Keyboard Lock is enabled, then return false
Placeholder until there’s an actual agreed-upon definition for Keyboard Lock.
-
If key is:
-
The shortcut to cut (e.g., ctrl-x), then Handle native cut
-
The shortcut to copy (e.g., ctrl-c), then Handle native copy
-
The shortcut to paste (e.g., ctrl-v), then Handle native paste
Need more complete set of post-keydown browser keys. Perhaps define a set of common browser keys (clipboard, open/close tabs, quit).
-
And then return true
-
-
Return false
10.11. handle native key down
- Input
-
nativeKey, native key info
- Output
-
None
-
Update global modifier key state
-
If nativKey is left or right Shift key, then add "Shift" to key modifier state
-
If nativKey is left or right Control key, then add "Control" to key modifier state
-
If nativKey is left or right Alt key, then add "Alt" to key modifier state
-
If nativKey is AltGraph key, then add "AltGraph" to key modifier state
-
If nativKey is left or right Meta key, then add "Meta" to key modifier state
-
If handle pre browser key with nativeKey, then
Note: Chrome/Firefox handle some BrowserKeys before generating keydown events. Tested with ctrl-t (to create new tab)
-
exit
-
-
Let target = currently focused area of a top-level browsing context
-
Let event = result of create a KeyboardEvent with "keydown", target
-
set KeyboardEvent attributes with event, nativeKey
-
Let result = dispatch event at target
Note: when in composition, canceling the keydown has no effect (tested: macOS Chrome; TODO: test other configs)
-
If the in composition flag is set, then
-
handle composition key and exit
-
-
Unset the suppress key input events flag
-
If result = false, then
-
Set the suppress key input events flag
-
-
If native platform has separate CHAR event, then
Is this check necessary? Can native CHAR events be ignored or do they contain needed info?
-
Exit (because CHAR event will trigger handle native key press)
-
-
Call handle native key press with nativeKey
10.12. handle native key up
- Input
-
nativeKey, native key info
- Output
-
None
-
Update global modifier key state
-
If nativeKey is left or right Shift key, then remove "Shift" to key modifier state
-
If nativeKey is left or right Control key, then remove "Control" to key modifier state
-
If nativeKey is left or right Alt key, then remove "Alt" to key modifier state
-
If nativeKey is AltGraph key, then remove "AltGraph" to key modifier state
-
If nativeKey is left or right Meta key, then remove "Meta" to key modifier state
-
-
Let target = currently focused area of a top-level browsing context
-
Let event = result of create a KeyboardEvent with "keyup", target
-
set KeyboardEvent attributes with event, nativeKey
-
dispatch event at target
10.13. handle native key press
- Input
-
nativeKey, native key info
- Output
-
None
Note: This may be called directly if the native platform generates CHAR events that are separate from keydown events. Or it may be called from handle native key down.
-
If composition mode flag is set, then
-
Handle composition key with nativeKey
-
Exit
-
-
If handle post browser key, then exit
-
Let target = currently focused area of a top-level browsing context
What should happen if the event focus has changed since the keydown event? What is the appropriate target for the keyup? The current focus or the previous? Are there security issues (e.g., if it’s not safe to edit the current focus)?
-
Let key = extract info from nativeKey
-
Fire key input events with key and target
11. Composition Event
11.1. Global State for CompositionEvent
11.1.1. Window-Level State
The UA must maintain the following values that are shared for the Window.
A composition mode flag (initially false) that is set if the native IME is enabled and the next key press will trigger compositionstart.
An in composition flag (initially false) that tracks if the system is currently in the middle of input composition (i.e., after compositionstart but before compositionend).
11.2. initialize a CompositionEvent
- Input
-
e, the
Event
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize a UIEvent with e, eventType and eventTarget
-
Initialize the following public attributes
-
Set event.data = ""
Note: This attribute has the same name as an attribute in InputEvent.
-
11.3. create a CompositionEvent
- Input
-
eventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Let e = the result of creating a new event using
CompositionEvent
-
Initialize a CompositionEvent with e, eventType and eventTarget
-
Return e
11.4. fire a CompositionEvent
- Input
-
eventType, a DOMString containing the event type
data, a DOMString containing event data
- Output
-
None
-
Let target = currently focused area of a top-level browsing context
The target for compositionstart should be determined by the element with focus, but subsequent composition events should be fired on that same element. Need to test what happens when focus changes during composition. On the Mac, if you change focus, the composition target changes. On Windows, behavior depends on the IME.
-
Let event = result of create a CompositionEvent with eventType, target
-
Set event.
data
= data -
Return the result of dispatch event at target
11.5. enter composition mode
- Input
-
None
- Output
-
None
This is an oversimplification. We need to native OS to call then when the user enters composition mode.
-
Set the composition mode flag
11.7. handle composition key
- Input
-
None
- Output
-
None
Note: This is called when a key is added to the composition buffer, or when the user navigates between composition options.
Note: This is where the IME handles the UI part to navigate the candidates or accept all or part of the text. Not sure how much (if any) of this makes sense to "specify" here since it is controlled by the IME.
-
If special IME key, then
-
If arrow, then select new candidate
-
If enter, then accept the current candidate, run end composition and exit
-
...
-
Need agreement on event order for compositionupdate and beforeinput. Chrome currently does bi -> cu, whereas Safari does cu -> bi. Firefox doesn’t yet produce bi, but prefers cu -> bi. See input-events/49 and uievents/66
-
Let data = the current composition candidate string
-
Fire a CompositionEvent with "compositionupdate" and data
-
Let result = fire an InputEvent with "beforeinput", "insertCompositionText" and data
Not all beforeinput events can be canceled - need to encode that here
-
If result is true, then
-
Update the DOM with the composition text
-
Fire an InputEvent with "input", "insertCompositionText" and data
Note: Not cancelable
-
11.8. begin composition
- Input
-
None
- Output
-
None
-
If in composition flag, then exit
-
Let data = currently selected text
-
Let result = fire a CompositionEvent with "compositionstart" and data
Document what happens when result is not true (event canceled)
11.9. end composition
- Input
-
None
- Output
-
None
-
If in composition flag is not set, then exit
Compat: Chrome sends out beforeinput/compositionupdate/textInput/input sequence before compositionend (tested on macOS). Compare with Firefox.
-
Set result = fire a TextEvent with "textInput", and data
Note: The "textInput" event is obsolete.
-
If result is false, then return.
-
Let data = the current composition candidate string
-
fire a CompositionEvent with "compositionend" and data
-
If Firefox:
Compat: Firefox sends input events after compositionend. Not sure when the DOM is updated relative to compositionend (tested on macOS). Need to resolve this.
-
Fire an InputEvent with "input", "insertCompositionText" and data
-
-
Unset the in composition flag
12. Pointer Event
The contents of this section should eventually be moved into the PointerEvent spec.
12.1. initialize a PointerEvent
- Input
-
event, the
PointerEvent
to initializeeventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Initialize a MouseEvent with event, eventType and eventTarget
12.2. create a PointerEvent
- Input
-
eventType, a DOMString containing the event type
eventTarget, the
EventTarget
of the event - Output
-
None
-
Let event = the result of creating a new event using
PointerEvent
-
Initialize a PointerEvent with event, eventType and eventTarget
-
Return event
12.3. create PointerEvent from MouseEvent
- Input
-
eventType, a DOMString containing the event type
mouseevent, the corresponding
MouseEvent
- Output
-
None
-
Let event = the result of creating a new event using
PointerEvent
-
Let target = mouseevent.
target
-
Initialize a PointerEvent with event, eventType and target
-
Copy MouseEvent attributes from mouseevent into event
-
Return event
12.4. maybe send pointerout event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
12.5. maybe send pointerleave event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
12.6. maybe send pointerover event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
12.7. maybe send pointerenter event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
12.8. maybe send pointermove event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
Can this send pointermove and pointerrawupdate? Or do we need 2 methods?
What is needed to properly define how pointermove events are coalesced?
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
12.9. maybe send pointerdown event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
Unlike mousedown events, pointerdown events are not nested when multiple buttons are pressed. The MouseEvent is passed so that the fields can be copied into the PointerEvent.
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
12.10. maybe send pointerup event
- Input
-
mouseout, the corresponding mouseout
MouseEvent
- Output
-
None
Unlike mouseup events, pointerup events are not nested when multiple buttons are pressed. The MouseEvent is passed so that the fields can be copied into the PointerEvent.
-
Let pointerout = create PointerEvent from MouseEvent with "pointerout" and mouseout
-
Set pointerevent attributes
-
Let target = mouseout.
target
-
dispatch pointerout at target
13. Pointer Lock
The contents of this section should eventually be moved into the [PointerLock] spec
Note: The algorithms here are an oversimplification since they don’t account for the lock/unlock state the or the pointer leaving and re-entering the UA screen boundaries. That should be fixed as part of moving this section to the PointerLock spec.
13.1. MouseEvent Interface Extension
A MouseEvent
has the following:
movementX
movementY
13.2. Global State for PointerLock
13.2.1. Window-Level State
The UA must maintain the following values that are shared for the Window.
A last mouse move value (initially undefined) that records the position of the last mousemove event.
13.3. initialize PointerLock attributes for MouseEvent
- Input
-
event, a
MouseEvent
- Output
-
None
13.4. set PointerLock attributes for mousemove
- Input
-
event, a
MouseEvent
- Output
-
None
-
If event.
type
is not "mousemove", then exit -
If last mouse move is not defined, then
-
Otherwise,
-
Set event.
movementX
= event.screenX
- last mouse move’s x-coordinate -
Set event.
movementY
= event.screenX
- last mouse move’s y-coordinate
-
-
Set last mouse move = ( event.
screenX
, event.screenY
)
14. Keyboard Lock
KeyboardLock is not yet an accepted standard and is included here as a placeholder to explore how it might be integrated.
The contents of this section should eventually be moved into the [WICG-Keyboard-Lock] spec
14.1. Global State for Keyboard Lock
14.1.1. User Agent-Level State
The UA must maintain the following values that are shared for the entire User Agent.
14.1.2. Window-Level State
The UA must maintain the following values that are shared for the Window.
A keyboard lock enable flag (initially false) that tracks whether Keyboard Lock is currently enabled.
14.2. Keyboard Lock is enabled
- Input
-
None
- Output
-
True if keyboard lock is enabled.
-
Return keyboard lock enable flag
15. Core DOM
These definitions probably belong in another spec.
15.1. hit test
- Input
-
pos, the x,y coordinates relative to the viewport
- Output
-
The frontmost DOM element at pos
To account for inert or disabled elements. this should call elementsFromPoint and reject invalid elements
-
Return [CSSOM-View]'s elementFromPoint with pos
16. CSSOM
The contents of this section should eventually be moved into the [CSSOM] spec
17. Clipboard
Should these be moved into the Clipboard spec?
17.1. handle native cut
- Input
-
None
- Output
-
None
Define when the "cut" event is fired.
-
Let data = null
-
Let result = fire an InputEvent with "beforeinput", "deleteByCut" and data
-
If result is true, then
-
Copy selected text to clipboard
-
Remove selected text from DOM target element
-
Fire an InputEvent with "input", "deleteByCut" and data
17.2. handle native copy
- Input
-
None
- Output
-
None
Note: No input events fired
Define when "copy" event is fired. Should that be in the Clipboard Spec?
-
Update clipboard with current selection
17.3. handle native paste
- Input
-
None
- Output
-
None
Note: This is intended to be called when the UA triggers a paste action (via user action)
Define when the "paste" event is fired.
-
Let data = the text on the clipboard being pasted
-
Let result = fire an InputEvent with "beforeinput", "insertFromPaste" and data
-
If result is false, then return.
-
Set result = fire a TextEvent with "textInput", and data
Note: The "textInput" event is obsolete.
-
If result is false, then return.
-
Paste clipboard contents into DOM target element
-
Fire an InputEvent with "input", "insertFromPaste" and data
18. Acknowledgements
Thanks to the following for their contributions to this document:
-
Anupam Snigdha
-
Domenic Denicola
-
Masayuki Nakano