[Mono-winforms-list] patch for enabling primitive XIM text input

Doug Rintoul doug_rintoul at sil.org
Tue Mar 25 19:08:54 EDT 2008


Atsushi Eno wrote:
> Hello,
>
>> The first problem has to do with the tracking of the control, shift, 
>> and alt key. These keys will currently get "stuck" because if 
>> FosterParent filters the key release event, a key release event for 
>> these keys are never put on the hwnd Queue. For example, if you press 
>> CTRL-space to enable an IM, winforms still thinks the control key is 
>> still pressed, even after you release it. Using the left and right 
>> cursor keys to move around a input field will move a word at a time, 
>> rather than a letter at a time.
>>
> Ah, good point! It should be fixed too. But I somewhat doubt if your 
> change
> especially that KeyRelease event is always passed works fine.
> It could result in inconsistent key event processing (KeyPress could be
> filtered and KeyRelease always isn't) and such inconsistency trapped me
> couple of days. So, IMHO there should be some condition to determine
> whether to filter KeyRelease or not.
>
Key filtering is totaling at the whim of the IM. If the the IM processes 
a key event it will tell the calling procedure the event is filtered. I 
am assuming you mean there should be a condition on whether we should 
process a key event in winforms even when the IM has filtered the event. 
If so, then you are correct. I think my patch currently works because 
few apps use key release events and so dual processing by both the IM 
and winforms is not an issue. However keypress events for mod could be a 
problem if the IM filters event. The keypress event would never be 
processed by winforms and thus the key state would never be registered. 
In this case we cannot do dual processing of all keypress events. So 
some condition needs to be determine as to when we pass the key press 
and key release events onto winform.

Unfortunately, winforms currently relies on key press and key release 
events to track the modification key states. Perhaps it is enough to 
test if the event is a key press or a key release mod key event (alt, 
ctrl, shift, menu, etc) and then pass the event on to winforms for 
processing even if the IM filters the event. The only other alternative 
I can see is to redesign winforms so that it queries X for the current 
state of the modifier keys whenever it needs that information.
>> The second issue has to do with the way that IME compose messages are 
>> handle. A bit of background is required here. I am one of the authors 
>> of KMFL (kmfl.sourceforge.net), which provides Tavaultesoft Keyman 
>> services to Linux. The way KMFL is designed is that KMFL can generate 
>> multiple compose messages in response to a single key stroke. The 
>> problem is that XIM does not use a FIFO to queue XIM compose 
>> messages, but a stack. So unless XIM compose events are processed 
>> immediately upon receipt, the recipient window will receive the XIM 
>> compose messages in the reverse order that they are generated. The 
>> fix is rather easy to implement. We just allow the application to 
>> process the keypress messages upon receipt rather than queuing a 
>> whole bunch and then returning. Note that the GTK XIM connector and 
>> the QT XIM interface work correctly with KMFL, so they implement a 
>> similar solution.
>>
> I'm not sure what you meant here. Do you mean such event processing 
> like below
> could happen? :
>
>    - KeyPress for 'A' occurs, and then it is stored in X event queue 
> ... well, "stack" ...
>      as pending.
>    - KeyPress for 'B' occurs, and then it is stored as pending.
>    - XNextEvent() is called, and X returns KeyPress 'B' because it is 
> not FIFO.
>
This is sort of what happens. It has been awhile since I poked around 
the XIM code in X. I just went back to familiarized myself with the 
situation. The actual problem is with the XIM commit code in X11. Here 
is an example of what actually happens:

1. The user presses 7. The input method is to generate the string 
"seven" in response to this. The IM will actually generate each 
character as a separate compose event. I realize that in this case the 
IM could have generated one compose event containing the string "seven", 
but this is not always the case. The way the kmfl engine is designed, it 
needs to be able to generate separate compose events in response to one 
keypress.
2. The IM calls the XIM commit callback to commit the first letter "s"
3. The XIM commit callback pushes the commit string on the IC commit 
info stack and then fabricates a KeyPress event with a keycode of 0 and 
pushes this event onto the event queue. Control is then transfered to 
winforms.
4. winforms receives the fabricated event and puts the event onto the 
hwnd queue via UpdateMessageQueue (UpdateMessageQueue was called by 
GetMessage).
5. UpdateMessageQueue then calls XPending and XNextEvent in a loop to 
get the next event. XNextEvent passes control back to X which in turn 
passes control back to the IM.
6. The IM calls the XIM commit callback to commit the second letter "e"
7. Steps 3, 4 and 5 are repeated.
8. Steps 2, 3, 4 and 5 are repeated for the rest of the letters. Note 
that the IC commit info stack now has "neves" on it.
9. Control is now passed back to winforms GetMessage. GetMessage calls 
Keyboard.KeyEvent to process the first fabricated keypress.
10. KeyEvent calls LookupString which in turn calls Xutf8LookupString. 
Xutf8LookupString returns the first compose sequence off the C commit 
info stack, in this case "n" which is in turn sent to the app via 
SendImeComposition.
11. Step 10 is repeated for each of the compose character and thus neves 
is sent to the application.

> Gtk and Qt of course have different event processing model from 
> winforms, so it
> could be just that the issue with kfml does not occur. I'm not sure 
> your change is
> valid from our perspective (UpdateMessageQueue() may have to lookup 
> every X
> events; I have no idea as I'm just digging into winforms only for XIM 
> support ;).
Not sure I understand. Every event is still processed by 
UpdateMessageQueue. Just not in a loop for keypress events.
>
> Besides I'm not sure why giving up processing pending event 
> immediately in
> UpdateMessageQueue() could fix the situation. To my understanding, events
> are anyways retrieved as LIFO (if I believe you) and if kfml anyways 
> regenerate
> other messages as a result of KeyPress, they will be retrieved 
> immediately
> anyways, won't they?
What my patch does is remove step 5. Control is passed back up the chain 
to GetMessage and thus Keyboard.KeyEvent to pop the commit string off 
the commit info stack before the IM and X can put another commit string 
onto the stack.
>
>> There is a third issue, the importance of which is debatable. For 
>> other frameworks (QT, GTK), each window in an application gets its 
>> own input method, independent of the other windows in an application. 
>> For example, in a text editor, even though you enable the input 
>> method, for the main editor, the IM is not enabled for the search 
>> box. This may not seem important at first, but it can be an issue for 
>> multilingual application where different fields can have different 
>> input methods associated with them. The patch I created last November 
>> did support this feature; however it does add a lot of complexity to 
>> the mix.
>>
> Hmm, I don't think Windows Forms allow such input method switching.
> It just controls whether IM could be enabled (default) or not. Of course
> it is possible to have different XICs for each window but I doubt we have
> any configuration point (other than custom configuration, environment
> variables or whatever).
>
Winforms itself does not allow for such switching but an IM framework 
such as SCIM does. For example, I could have one field in which I want 
to type IPA characters and another field in which I want to type Greek. 
I enable the IM for the first field and switch to the IPA keyboard. I 
then switch to the second field and enable the IM and switch it to 
greek. For other frameworks such as GTK and QT, if I click on the first 
field, the input context is automatically switch back to IPA.

Stimulating stuff. Hopefully we can address these issues and come up 
with a working solution.

Doug Rintoul.
SIL Intl.


More information about the Mono-winforms-list mailing list