W3C home > Mailing lists > Public > www-dom@w3.org > October to December 2009

Re: [whatwg] focus change inside keypress event handler

From: Michael A. Puls II <shadow2531@gmail.com>
Date: Thu, 29 Oct 2009 17:24:52 -0400
To: "Boris Zbarsky" <bzbarsky@mit.edu>
Cc: whatwg@whatwg.org, www-dom@w3.org
Message-ID: <op.u2ky3q1l1ejg13@sandra-svwliu01>
On Thu, 29 Oct 2009 10:14:42 -0400, Boris Zbarsky <bzbarsky@mit.edu> wrote:

> On 10/29/09 9:20 AM, Michael A. Puls II wrote:
>> Despite that though, preventDefault() still works in
>> Firefox and Safari inside a "keypress" handler to prevent the char from
>> being inserted. So, I'm not exactly sure what's they're doing behind the
>> scenes.
>
> Last I checked in Gecko, things looked somewhat like this:
>
> Editors (those editable things inside text inputs) set up some default  
> actions (effectively event listeners in the system event group).  The  
> default keypress event action is to enter the character.
>
> When you press a button on your keyboard, the focus is used for one  
> thing and one thing only: to decide where to dispatch the key events. So  
> the keypress event is dispatched to the thing that has focus.  If one of  
> the event handlers for keypress changes what has the focus, that doesn't  
> change where the default action of the keypress event takes place (since  
> the event target chain is built completely before any of the event  
> handling takes place).
>
> Make sense?

I think so. The event target isn't changed by focus().

But, in Firefox, Safari and Opera, it's possible to change what element  
the text is inserted into by changing the focus in 'keydown'.

>> Note that Opera for example doesn't allow preventDefault() to have any
>> effect in the keydown handler. It only works in the "keypress" handler
>> more like you expect.
>
> You might be interested in  
> https://bugzilla.mozilla.org/show_bug.cgi?id=167145

Thanks. Read all of it. That helps with the history of it and the thoughts  
at the time.

>> 1. What order do those fire in?
>>
>> 2. What ones can you use preventDefault() in to stop the character from
>> being inserted?
>>
>> 3. For each one that you can use preventDefault() in to stop the
>> insertion of the 'd', if you use preventDefault(), which of the others
>> will not fire?
>
> These are all excellent questions that the spec should answer.

Yes indeed.

>> 4. When is the 'd' actually suppposed to be inserted (what the spec
>> says, not necessarily what browsers do)? (This will help determine what
>> handlers you can use focus() in to change what field the typed char gets
>> inserted in)
>
> This is two separate questions:
>
> 1)  When is the 'd' actually inserted?
> 2)  When is the element the 'd' will be inserted in determined?
>
> In Gecko, the answers are effectively:
>
> 1)  During the default action phase of the keypress event,
>      assuming that it has not had preventDefault() called via
>      various mechanisms (e.g. preventDefault() on keydown will
>      trigger preventDefault on all resulting keypresses in Gecko).
> 2)  Immediately before the keypress event is fired.
>
> (two sides of the same coin, really, since this is just how default  
> actions work in DOM event land).

O.K., thanks.

>> In short though, browsers don't agree on this stuff and it's difficult
>> to decide what the right thing to do is in regards to "how it's supposed
>> to work". I could even throw other events that detect modification of
>> the fields value to complicate things even more.
>
> Yep.  And you could use script to set .value at various points in there,  
> leading to fun questions about how onchange should work, too.  It's a  
> mess.  ;)

:)

Does the following description make sense (ignoring textInput for now) or  
sound good?

'keydown' fires first.

If a handler for 'keydown' calls preventDefault() (explicitly or  
implicitly via returning false), do not fire 'keypress' after the  
'keydown' handler returns.

If a handler for 'keydown' does not call preventDefault(), and the key  
pressed represents text, after the 'keydown' handler returns, fire  
'keypress' with the insertion context element (Thanks Scott for the  
'context' hint) being the element that's currently focused after the  
'keydown' handler returns and right before 'keypress' is fired. If the key  
pressed does not represent text, do not fire 'keypress'.

If 'keypress' was fired, and the handler for it calls preventDefault()  
(explicitly or implicitly via return false), after the handler returns, do  
not insert the text.

If 'keypress' was fired and the handler for it does not call  
preventDefault(), after the handler returns, insert the text in the  
insertion context element.

If the key is being held down, 'keydown' or both 'keydown' first and then  
'keypress' second will fire repeatedly according to the rules above.

Once the key is finally released and 'keydown' stops firing, always fire  
'keyup' no matter what.

Note that 'keyup' may fire before 'keypress' if you release the key before  
an alert() inside the 'keydown' handler shows and blocks.

In short, 'keydown' and 'keyup' *always* fire when pressing and releasing  
a key. Whether 'keypress' is fired and something is inserted into the  
field (and which field) and whether keypress fires before keyup, depends  
on the rules above.

(Note that the above description describes how things seem from testing on  
the user/author side, not from the implementation side.)

In testing, that seems to be what Safari Win32 does and it's pretty  
consistent about it. In fact, I chose Safari as a basis for the  
description above because it's consistent and it's easier to see what's  
happening.

It's already been said how Opera is different as far as focus changes in  
'keypress' changing the insertion context element and preventDefault() not  
working in 'keydown' go. But, Opera also does something else differently.  
When holding down a key, it just repeatedly fires 'keypress', instead of  
just 'keydown' or both 'keydown and 'keypress' like Firefox and Safari.

As for Firefox, it's different too in that preventDefault() doesn't stop  
any events from firing. It just stops text insertion in some cases.

Attached is one doc I was testing with. Uncomment one or both of the  
preventDefaults() to play around.

I realize there's more to things than that, but that's a starting  
*example* of the detail I think the spec should cover.

Ultimately though, the spec should define all this stuff clearly in a way  
that all browsers can implement. Browsers just shouldn't be different in  
this area. It's too creepy. :)

Thanks

-- 
Michael


Received on Thursday, 29 October 2009 21:25:38 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Friday, 22 June 2012 06:14:04 GMT