New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
X11: fix XIM input method support #1850
Conversation
I added a // Filter the events received by windows (only allow those matching a specific window)
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
{
printf("CheckEvent: event type=%d, window=%ld, user=%ld\n",event->type,event->xany.window, userData);
// Just check if the event matches the window
return event->xany.window == reinterpret_cast< ::Window >(userData);
} Looks like upon keypresses, the IME is firing ClientMessage events into the queue with a different Window ID:
I added a This is what happened when I press a key:
Gonna test it with multiple windows. |
With 2 windows, the IME sometimes glitches out if we switch to the other window while typing something. I looked up some documentations, and it seems that the XIM object is per-display, and the XIC context is bound to a specific window. So I saved the XIM object to the namespace This is the snippet I used to test: #include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
sf::RenderWindow win1,win2;
bool processEvent(sf::Event& event,int win){
switch(event.type){
case sf::Event::Closed:
win1.close();
win2.close();
return false;
case sf::Event::KeyPressed:
printf("(Win%d) Key Pressed: %d\n",win,event.key.code);
break;
case sf::Event::TextEntered:
printf("(Win%d) Text Entered: %d\n",win,event.text.unicode);
break;
}
return true;
}
int main(int argc, char* argv[])
{
win1.create(sf::VideoMode(400, 200), "Window1");
win1.setVerticalSyncEnabled(true);
win2.create(sf::VideoMode(400, 200),"Window2");
win2.setVerticalSyncEnabled(true);
while (win1.isOpen() && win2.isOpen()) {
sf::Event event;
while (win1.pollEvent(event))
if(!processEvent(event,1))
return 0;
while(win2.pollEvent(event))
if(!processEvent(event,2))
return 0;
win1.clear(sf::Color::Magenta);
win2.clear(sf::Color::Cyan);
win1.display();
win2.display();
}
return 0;
} |
The updated code uses It also keeps a global XIM object instead of creating a new one with every window. Maybe the commit name should include that? |
Rebased with latest master. @eXpl0it3r Any updates? |
I don't know much about the whole X11 setup and hope @binary1248 can have a closer look at this 🙂 |
I still don't quite understand why it was necessary to make such significant changes to the logic around I would prefer this PR is modified to affect the existing Alternatively, this would have to be tested on multiple different systems/configurations to verify that the original bug is not re-introduced. Maybe @naezith or @texus could help with this since they worked on the issue. |
This is possible. The only things we need to do are:
Working on it. Should we change the commit/pr name? |
The new commit is a moderate change set to have XIM working across multiple windows. |
Rebased with latest master. Sorry for the mess... It was indeed not necessary to change this much. To my defense, there are very little and even conflicting information on how to handle XIM correctly, not to mention with multiple windows. I removed I rewrote the code, pushed the second commit and was never able to repeat the bug. Just being curious, is it possible for this pull request to make it into SFML 2.6.0? I sure can do a back port. |
There is no need to apologize for standard development practice. 😉 After all is said and done this PR should/would be squashed and rebased anyway, so any intermediate steps wouldn't have become part of the commit history. Regarding the backport to 2.6.0: @eXpl0it3r will have to comment on that. I personally don't have anything against it. |
All fixed. You really have those eagle eyes👍 |
Yeah, I think it could be a great addition and is isolated enough for SFML 2.6. |
@eXpl0it3r I still don't quite get it. Is it the case that the feature changes on 2.6.x will be ported to 3.0 once all the major API changes are sorted out? That sounds like a major undertaking. |
No, we'll continuously merge changes from 2.6.x to master. |
Rebased with |
Looks good to me, although I must admit I don't really have the technical expertise or experience to test these changes because I have never had to type using an input method before. Perhaps there are others willing to give this a try. |
Thank you for diving into this! 🙂 |
I noticed since this commit that more events are generated, which looks like a bug to me. Testing with SFML-Input and SFML feature/scancode branch on Ubuntu 20.04: when pressing a key, two KeyPressed events are generated with a small delay between them, instead of one event. If the key is held down, many KeyPressed events are regularly generated when the key is down (which is normal) but also after the key is released (not normal) for some time. I did not test the newly supported input method though. I never used such input method. |
@kimci86 Can you try again with Maybe you have the input method framework IBus installed. It comes bundled with GNOME and is notoriously hard to replace, many of us end up giving up GNOME just to not use IBus. |
Running again with Is there a way to have this behavior by default, without having to set an environment variable? |
@kimci86 IBus is, how to say... Neglected. It kind of works, but most people who care more about input methods often use others like Fcitx or Uim. Also it's part of good-old GNOME. The fault is most likely IBus's IMHO.
AFAIK I'm afraid no, but I'm not an expert. I've never used IBus before. Gonna do some testing. |
@kimci86 Oh no, the fault is mine in fact... If you look at WindowImplX11.cpp:L1880 // Key down event
case KeyPress:
{
// Fill the event parameters
Event event;
event.type = Event::KeyPressed;
event.key.code = (......)
pushEvent(event);
// Generate a TextEntered event
if (!XFilterEvent(&windowEvent, None)) // Feed the event to the IME, discard it if requested
{
event.type = Event::TextEntered;
......
}
} Clearly there's something wrong here, and the I wasn't able to catch that mainly because when the IME takes some text, IBus sends a KeyPress without text input attached, while Fcitx and XWayland (what I use) sends no KeyPress at all. Thus if the previous event is not filtered, it gets duplicated by IBus. I opened #1894 with the fix. |
Description
This PR is a (good enough) fix to #1840.
It fixes the existing XIM code, supporting input methods (at least with Fcitx5).
How to test
Dump all the KeyPressed/TextInput event from any window. If you don't have a input method, nothing should change. If you do have one, it should be working now.