解决pyside6 GUI程序在linux下无法使用fcitx输入法

解决pyside6 GUI程序在linux下无法使用fcitx输入法

问题

使用pyside6编写qt GUI程序,在linux下运行时,若使用fcitx输入法,则任意输入框内都无法切换使用,例如输入中文。

原因

查看python3.[xx]/site-packages/PySide6/Qt/plugins/platforminputcontexts,pyside不包含fcitx相关plugin,默认只包括ibus plugin。

解决

github项目fcitx-qt5(archived)和项目fcitx5-qt提供了为qt编译fcitx输入法插件的支持,注意这两个项目的5一个是qt版本,一个是fcitx版本,但fcitx-qt5也支持qt6。

手动patch

编译这两个项目及可以得到所需的libfcitxplatforminputcontextplugin-qt6.so。但编译步骤较为复杂,若不想自己编译,可以在arch package中找到这两个软件包(任一):

  • fcitx-qt6 (上游fcitx-qt5项目不再更新,但软件包内容较简洁)
  • fcitx5-qt (持续更新,但软件包内文件较多)

点击打开package页面,在右侧找到download from mirror按钮,下载预编译的软件包,并手动解压(当然如果本来就使用arch发行版可以直接安装,然后在系统路径找到so文件)。

找到所需的so文件后,将其复制到前述的pyside6路径python3.[xx]/site-packages/PySide6/Qt/plugins/platforminputcontexts。重新运行程序,此时应可以在输入框正常切换fcitx输入法。

自动化patch

链接https://archlinux.org/packages/extra/x86_64/fcitx-qt6/download/并不会直接返回软件包文件下载地址,真正的下载地址包含在响应头的Location字段中。

如下bash脚本自动从上述源下载软件包,使用tar解压,并复制到当前环境默认python的site-packages中安装的pyside6目标目录下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mkdir -p /tmp/fcitx-fix ; cd /tmp/fcitx-fix
response=$(curl -I -L https://archlinux.org/packages/extra/x86_64/fcitx-qt6/download/)
echo response:
echo $response
location=$(echo "$response" | grep -i "Location:" | awk '{print $2}' | tr -d '\r')
echo $location
curl $location -o fcitx-qt6.pkg.tar.zst
tar -xvf fcitx-qt6.pkg.tar.zst
target_path=$(python -c "import site; print(site.getsitepackages()[0])")/PySide6/Qt/plugins/platforminputcontexts/
echo target_path=$target_path
so_file=usr/lib/qt6/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin-qt6.so
sudo cp  $so_file  $target_path
ls $target_path

troubleshooting

复制so到pyside6目录后运行程序仍无法使用输入法

尝试打开qt调试输出:

1
env QT_DEBUG_PLUGINS=1 python gui.py 2>debug.log

检查输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
qt.core.plugin.factoryloader: looking at ".venv/lib/python3.12/site-packages/PySide6/Qt/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin-qt6.so"
qt.core.plugin.loader: Found metadata in lib .venv/lib/python3.12/site-packages/PySide6/Qt/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin-qt6.so, metadata=
{
    "IID": "org.qt-project.Qt.QPlatformInputContextFactoryInterface.5.1",
    "MetaData": {
        "Keys": [
            "fcitx"
        ]
    },
    "archlevel": 1,
    "className": "QFcitxPlatformInputContextPlugin",
    "debug": false,
    "version": 395008
}


qt.core.plugin.loader: In .venv/lib/python3.12/site-packages/PySide6/Qt/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin-qt6.so:
  Plugin uses incompatible Qt library (6.7.0) [release]
qt.core.plugin.factoryloader: "The plugin '.venv/lib/python3.12/site-packages/PySide6/Qt/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin-qt6.so' uses incompatible Qt library. (6.7.0) [release]" 
         not a plugin

错误表明当前的plugin so的qt版本是6.7.0,与使用的pyside不匹配。

检查pyside对应qt版本:

1
2
3
4
5
from PySide6.QtCore import QLibraryInfo
v=QLibraryInfo.version()
#6.6.2
print(f"{v.majorVersion()}.{v.microVersion()}")
#6.6

因此可以判断原因:预编译的so的qt版本与pyside6的qt版本不匹配。经过尝试,需要至少minor版本相同。例如6.7.2与6.7.0是可以兼容,但6.6.9和6.7.0不行。

对于pyside6,似乎python包的版本就是对应的qt版本,使用pip install --upgrade pyside6升级到相同小版本即可。

对于plugin so,可以使用objdump -p $so_file, 在输出中查找对应的qt小版本。

如下脚本判断$so_file的qt小版本(只精确到minor,即三段版本号第二段,如6.7)是否与环境默认python安装的pyside6版本是否匹配,若不匹配,以返回值1退出。

1
2
3
4
5
6
7
so_qt_version=$(objdump -p $so_file | grep -e "Qt_6.[0-9]"  -o | sed 's/Qt_//')
pyside_version=$(python -c "from PySide6.QtCore import QLibraryInfo; v=QLibraryInfo.version(); print(f'{v.majorVersion()}.{v.minorVersion()}')")
echo so_qt_version=$so_qt_version, pyside_version=$pyside_version
if [ "$so_qt_version" != "$pyside_version" ]; then # abort if versions are not the same
    echo "Error: versions of so and pyside are not the same"
    exit 1
fi

nuitka打包默认不包含platforminputcontexts

若使用nuitka打包pyside6编写的程序,除使用--enable-plugin=pyside6外,要在nuitka为linux目标平台打包pyside6 GUI程序时包含输入法相关插件,还要加上如下配置:

1
--include-qt-plugins=platforminputcontexts

如果使用nuitka python注释配置:

1
2
# nuitka-project-if: {OS} == "Linux":
#    nuitka-project: --include-qt-plugins=platforminputcontexts

License

根据fcitx-qt5项目的README

1
2
The platform input context plugin is released under 3-Clause BSD License.
Other libraries are released under GPL2+.

所以上述方式使用plugin so遵循3-Clause BSD License即可。

0%