I didn’t expect this to be a thing that is only fixed recently. And the fix itself goes through a little bit back and forth. So I’d just like to share it since it is an interesting experience.
Between the communication of application and input method server. A common thing is application send a key event to input method and wait for the handling result of this event. Fcitx allows multiple different mode for it, including sync and async mode. By default it is async mode to avoid any block on the application side. But since we also support sync mode, we should keep two implementation have the same effect.
But in reality, we do behave the same under most circumstance, except when you bypass the key event and do some other thing at the same time. The reason behind this is actually easy to understand. Check the pseudo code below.
Imagine the input method issues commitString request at the same time. In the first sync case, the key event will be handled before the commitString, while the latter one will handle commitString before the key event.
If the key event is filtered, then there is no difference, but if the key is not filtered, then we will get two different result. For example, keyboard engine will show spell check within the preedit, but when you press space, the preedit will be commit to client and also the space key. You may say you can solve it by just combining the space key within the commit string request. Then what about a “left” key that doesn’t produce text? One way to solve it is to piggyback a rich result value instead of just a boolean value, but that would require more code change to existing interface. So in order to resolve this, we will force the input method to use the forward key interface to send the key back. Luckily, all event can be handled by the same way. The trick can be done within the last reserved event handler for key event.
Here’s the things changed with in the fcitx framework.
Engine can safely assume any commitString is handled before the key event. If engine want it the other way, it can use forward key request itself. This keeps the default behavior for all input context.
DBus based input context will block all the request sending the client until the request is returned. This ensures processKeyEvent is returned before the following request.
If there is any pending request, mark processKeyEvent request as true, and use forwardKey to re-send the key event to the client.
Within the input context code, tries to use the same data to forward key event if possible to avoid any conversion error.
Due to a frequently request about adding scripting support to Fcitx, I tried to make Fcitx 5 able to be extended in a different way.
During Fcitx 4 times, the addon must be written with Shared library and those assumptions are hard-coded. In Fcitx 5, I added an another abstraction called Addon Loader, which is responsible for the actual addon loading.
The builtin addon loader enables addon to be statically linked into Fcitx, which avoids the inconsistency of library and addon version, and it makes some important addon always available. And the shared library addon loader just loads the addon like the old days.
And starting from today, there can be a new addon type Lua to be used to extend Fcitx. In old Fcitx 4 days, lua addon is yet another shared library addon, instead of an “lua” typed addon. With the new addon loader mechanism, lua addon loader will do all the C++ coding work, and people can simply write pure lua addon and enable/disable them just like any other addons.
In order to add support of the Google Pinyin’s API back, fcitx5-lua also comes with a imeapi addon, which is purely lua (Though, I did wrote some code specifically to it to support all APIs, because the full Google Pinyin API contains some weird helper function like utf8 to utf16 conversion.).
So either, you can put a old days lua file to share/fcitx5/lua/imeapi/extensions , so imeapi will load it for you. Or you can write your own standalone lua Addon, by having a regular addon config file.
Right now, due to missing the real use case for lua addon, the API exposed by lua addon loader is quite limited to only covers imeapi’s use case. Documentation of existing API can be found at https://fcitx.github.io/fcitx5-lua/index.html. In the future, based on the use case we want to support more API will be added to it.
Right now, imeapi is designed to bridge the api to quickphrase and pinyin in chinese addons (register_trigger + candidate string will only works for pinyin).
Also, this lua addon loader enables to invoke any lua functions from C++ side. The arguments and return values are passed with RawConfig in Fcitx to avoid any ABI issues. In this case, Pinyin just simply invokes a function in imeapi to send over the candidates string. In old Fcitx 4 days, such thing are usually done by addon actively scan the candidate list, these kinds of style is not encouraged anymore in Fcitx 5. Instead, if certain functionality can be extended, it should be exposed by the addon itself (E.g. quickphrase now supports to be extended by other addons, and that’s how it works with luad addon lodaer),
As for extending addon loader, while there is no plan to add other addon type, code contribution are welcomed for things like Python, etc. Or even a “Type=DBus” addon that simply bridges all the call by dbus to another process.