解决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即可。