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.
