解决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中找到这两个软件包(任一):
点击打开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即可。