This is an engineering notebook post concerning Leo's key-handling code.  
Please feel free to ignore unless you might someday maintain this code.

This is a "thinking out loud post", inspired by the recent difficulties in 
the "keys2" branch. Leo's key-handling code is complex and difficult.  Some 
of this difficulty is inherent.  Some is likely self-inflicted, so 
simplifications may be possible.

*Status*

I have installed Greek, German and Chinese language packs on Windows, so I 
can easily type σ, or ß  or 都.  

At present (at least in the "keys2" branch), Leo does not handle most 
(all?) Greek characters.  Traces show that proper key events are generated, 
but somehow these characters are "disqualified" later.

Similarly, Leo handles regular German characters properly, but not ß.

Otoh, Leo *does* handle 都 properly.  And I see why.  When I type a key, a 
popup appears with a menu of items.  When I select the item Qt (or 
Windows?) inserts the Chinese character directly in the widget *without* 
generating a key event!

*Initial thoughts*

Last night I realized (Doh!) that I hadn't read the QKeyEvent docs 
<http://doc.qt.io/qt-5/qkeyevent.html>in a long time. This produced some 
surprises.

Even before reading the docs, I realized that modifier keys other than 
"Shift" are problematic.  It's not entirely clear what they mean.

Let's define a *bare shift* as a Shift modifier no accompanied by any other 
modifier.

Let's define a *bare key* as a key that has (at most) the Shift modifier.

The separation between event.binding and event.char causes a great deal of 
confusion.  I would like to clear that up.

At present, k.masterKeyHandler uses event.char and event.stroke, but this 
is strange.  One would think that the stroke would contain a char ivar.


*Reading the docs*
Here are what appear to be the essential excerpts:

QQQ
*event.text()*: Returns the Unicode text that this key generated.

Return values when modifier keys such as Shift, Control, Alt, and Meta are 
pressed differ among platforms and could return an empty string.

*event.key()*: See Qt::Key <http://doc.qt.io/qt-5/qt.html#Key-enum> for the 
list of keyboard codes. These codes are independent of the underlying 
window system.

This function does not distinguish between capital and non-capital letters, 
use the text() function.

>From Qt::Key <http://doc.qt.io/qt-5/qt.html#Key-enum>: On Windows, when the 
KeyDown event for [Key_AltGr] is sent, the Ctrl+Alt modifiers are also set.
QQQ

There is a lot to chew on here.

*Generating characters*

filter.toBinding returns (binding, char).  At present, the distinction 
between binding and char is muddled.

It's *imperative* that this confusion be cleaned up.  Thinking out loud, 
let's see if the following plan might work:

At present: filter.qtKey *does *use event.key() to generate the keynum 
field, but does not test for Key_AltGr.  This likely causes a lot 
problems/bug later.

1. For bare keys, char should just be event.text().  Indeed, this contains 
the desired (single) unicode character, *with the proper case*.

At present, various parts of code contain *case-adjusting code*.  Wherever 
they appear, these lines are extremely difficult to get right.  But not all 
of the case-adjusting code can disappear.  In particular, there must be 
case-adjusting code to handle user settings.

2. For keys containing modifiers other than Shift, char should probably be 
empty.

But there is a crucial complication.  For keys such as Home, Right, etc. 
event.text() generates multi-character (unicode) text. 

3. In any case, the eventFilter logic should "adjust" event modifiers as 
follows:

A: Remove the Shift modifier from bare events.  This should eliminate the 
case-adjusting logic that presently exists in filter.tweak.

B. Remove the Alt and Ctrl modifiers if keynum == Key_AltGr.

*Ensuring that user settings match bindings*

At present, this kinda happens automatically, because both key binding and 
user create g.KeyStroke events.  In both cases, the ctor, via 
ks.finalize_binding, converts the incoming binding to stroke.s.

In essence, this is the canonical form of either the key binding or the 
user setting. And in particular, ks.finalize_char (a helper of 
ks.finalize_binding) has the dreaded case-adjustment code.

*What modifiers are allowed?*

But now we come to a new question in Leo's history! What are we to do about 
Alt, Ctrl, Meta and Command modifiers? That is, to which characters are 
these modifiers *allowed* to be applied?

This question has tricky ramifications. It seems to me, that *regardless* 
of what modifiers the QKeyEvent *might *deliver, it makes no sense to allow 
user settings like Alt-σ or Ctrl-ß or Meta+都.

Otoh, we definitely *do* want to allow user settings like Shift-Tab, 
Shift-Home, Shift-Ctrl-End, etc. And the present code does allow such 
things.  There are already lists of such characters in g.KeyStroke.  
Perhaps more should be added.

*Summary*

Leo's key handling must be perfect.  Nothing else is acceptable.

Surprisingly, Greek and German letters appear to be a better test of the 
code than Chinese.

Modifiers probably should be adjusted more than they are now.

Case-adjusting code can never be completely eliminated, but is should be 
possible to eliminate it from the eventFilter code.

At present, the exact meaning of the (binding, char) tuple returned from 
filter.toBinding is unclear.  This has ripple effects in the code.

When this confusion is gone, it should be possible clean the code further. 
This would be a separate project, but now is the time to clean the code as 
much as possible, when all the details are fresh in my mind.

More details may come to mind, but I have been working on this post most of 
the night.  Time for a break.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to