init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
if(NOT BUILD_ONLY_PLUGIN)
set(REQUIRED_QT5_VERSION 5.7.0)
endif()
find_package(Qt5 ${REQUIRED_QT5_VERSION} CONFIG REQUIRED Core DBus Widgets)
find_package(Qt5Gui ${REQUIRED_QT5_VERSION} REQUIRED Private)
add_subdirectory(dbusaddons)
add_subdirectory(platforminputcontext)
if(NOT BUILD_ONLY_PLUGIN)
add_subdirectory(guiwrapper)
add_subdirectory(widgetsaddons)
add_subdirectory(quickphrase-editor)
add_subdirectory(immodule-probing)
endif()

View File

@@ -0,0 +1,80 @@
ecm_setup_version(PROJECT VARIABLE_PREFIX FCITX5QT5DBUSADDONS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt5dbusaddons_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5DBusAddonsConfigVersion.cmake"
SOVERSION 1)
# create a Config.cmake and a ConfigVersion.cmake file and install them
set(CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/Fcitx5Qt5DBusAddons")
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/Fcitx5Qt5DBusAddonsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5DBusAddonsConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
set(dbusaddons_SOURCES
fcitxqtwatcher.cpp
fcitxqtdbustypes.cpp
fcitxqtinputcontextproxy.cpp
fcitxqtinputcontextproxyimpl.cpp
fcitxqtinputmethodproxy.cpp
fcitxqtcontrollerproxy.cpp
)
set(dbusaddons_HEADERS
fcitxqtwatcher.h
fcitxqtdbustypes.h
fcitxqtinputcontextproxy.h
fcitxqtinputmethodproxy.h
fcitxqtcontrollerproxy.h
)
set(fcitxqtdbusaddons_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
)
add_library(Fcitx5Qt5DBusAddons ${LIBRARY_TYPE} ${dbusaddons_SOURCES})
generate_export_header(Fcitx5Qt5DBusAddons BASE_NAME Fcitx5Qt5DBusAddons)
add_library(Fcitx5Qt5::DBusAddons ALIAS Fcitx5Qt5DBusAddons)
target_include_directories(Fcitx5Qt5DBusAddons PUBLIC "$<BUILD_INTERFACE:${fcitxqtdbusaddons_INCLUDE_DIRS}>")
target_include_directories(Fcitx5Qt5DBusAddons INTERFACE "$<INSTALL_INTERFACE:${Fcitx5Qt5_INCLUDE_INSTALL_DIR}/Fcitx5Qt5DBusAddons>")
set_target_properties(Fcitx5Qt5DBusAddons
PROPERTIES VERSION ${FCITX5QT5DBUSADDONS_VERSION}
AUTOMOC TRUE
SOVERSION ${FCITX5QT5DBUSADDONS_SOVERSION}
POSITION_INDEPENDENT_CODE ON
EXPORT_NAME DBusAddons
)
target_link_libraries(
Fcitx5Qt5DBusAddons
PUBLIC
Qt5::Core
Qt5::DBus
)
if(BUILD_ONLY_PLUGIN)
set_target_properties(Fcitx5Qt5DBusAddons PROPERTIES
COMPILE_DEFINITIONS "FCITX5QT5DBUSADDONS_STATIC_DEFINE")
else()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5DBusAddonsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5DBusAddonsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel )
install(EXPORT Fcitx5Qt5DBusAddonsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE Fcitx5Qt5DBusAddonsTargets.cmake NAMESPACE Fcitx5Qt5:: )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt5dbusaddons_version.h
DESTINATION ${Fcitx5Qt5_INCLUDE_INSTALL_DIR} COMPONENT Devel )
install(TARGETS Fcitx5Qt5DBusAddons EXPORT Fcitx5Qt5DBusAddonsTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES ${dbusaddons_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt5dbusaddons_export.h
DESTINATION "${Fcitx5Qt5_INCLUDE_INSTALL_DIR}/Fcitx5Qt5DBusAddons")
endif()

View File

@@ -0,0 +1,8 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Qt5Core @REQUIRED_QT5_VERSION@)
find_dependency(Qt5DBus @REQUIRED_QT5_VERSION@)
include("${CMAKE_CURRENT_LIST_DIR}/Fcitx5Qt5DBusAddonsTargets.cmake")

View File

@@ -0,0 +1,31 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtcontrollerproxy -c
* FcitxQtControllerProxy interfaces/org.fcitx.Fcitx.Controller1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitxqtcontrollerproxy.h"
namespace fcitx {
/*
* Implementation of interface class FcitxQtControllerProxy
*/
FcitxQtControllerProxy::FcitxQtControllerProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
FcitxQtControllerProxy::~FcitxQtControllerProxy()
{
}
}

View File

@@ -0,0 +1,291 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtcontrollerproxy -c
* FcitxQtControllerProxy interfaces/org.fcitx.Fcitx.Controller1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITXQTCONTROLLERPROXY_H
#define FCITXQTCONTROLLERPROXY_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "fcitxqtdbustypes.h"
#include "fcitx5qt5dbusaddons_export.h"
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.Controller1
*/
class FCITX5QT5DBUSADDONS_EXPORT FcitxQtControllerProxy: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.fcitx.Fcitx.Controller1"; }
public:
FcitxQtControllerProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~FcitxQtControllerProxy();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> Activate()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Activate"), argumentList);
}
inline QDBusPendingReply<> AddInputMethodGroup(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("AddInputMethodGroup"), argumentList);
}
inline QDBusPendingReply<QString> AddonForIM(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("AddonForIM"), argumentList);
}
inline QDBusPendingReply<FcitxQtInputMethodEntryList> AvailableInputMethods()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("AvailableInputMethods"), argumentList);
}
inline QDBusPendingReply<FcitxQtLayoutInfoList> AvailableKeyboardLayouts()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("AvailableKeyboardLayouts"), argumentList);
}
inline QDBusPendingReply<bool> CanRestart() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CanRestart"),
argumentList);
}
inline QDBusPendingReply<bool> CheckUpdate()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CheckUpdate"), argumentList);
}
inline QDBusPendingReply<> Configure()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Configure"), argumentList);
}
inline QDBusPendingReply<> ConfigureAddon(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("ConfigureAddon"), argumentList);
}
inline QDBusPendingReply<> ConfigureIM(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("ConfigureIM"), argumentList);
}
inline QDBusPendingReply<QString> CurrentInputMethod()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CurrentInputMethod"), argumentList);
}
inline QDBusPendingReply<QString> CurrentUI()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CurrentUI"), argumentList);
}
inline QDBusPendingReply<> Exit()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Exit"), argumentList);
}
inline QDBusPendingReply<QString, QString, QString, QVariantMap,
FcitxQtFullInputMethodEntryList>
FullInputMethodGroupInfo(const QString &in0) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(
QStringLiteral("FullInputMethodGroupInfo"), argumentList);
}
inline QDBusReply<QString> FullInputMethodGroupInfo(
const QString &in0, QString &defaultInputMethod, QString &defaultLayout,
QVariantMap &properties,
FcitxQtFullInputMethodEntryList &inputMethodEntryList) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(
QDBus::Block, QStringLiteral("FullInputMethodGroupInfo"),
argumentList);
if (reply.type() == QDBusMessage::ReplyMessage &&
reply.arguments().count() == 5) {
defaultInputMethod = qdbus_cast<QString>(reply.arguments().at(1));
defaultLayout = qdbus_cast<QString>(reply.arguments().at(2));
properties = qdbus_cast<QVariantMap>(reply.arguments().at(3));
inputMethodEntryList = qdbus_cast<FcitxQtFullInputMethodEntryList>(
reply.arguments().at(4));
}
return reply;
}
inline QDBusPendingReply<FcitxQtAddonInfoList> GetAddons()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("GetAddons"), argumentList);
}
inline QDBusPendingReply<FcitxQtAddonInfoV2List> GetAddonsV2()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("GetAddonsV2"), argumentList);
}
inline QDBusPendingReply<QDBusVariant, FcitxQtConfigTypeList> GetConfig(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("GetConfig"), argumentList);
}
inline QDBusReply<QDBusVariant> GetConfig(const QString &in0, FcitxQtConfigTypeList &out1)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("GetConfig"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
out1 = qdbus_cast<FcitxQtConfigTypeList>(reply.arguments().at(1));
}
return reply;
}
inline QDBusPendingReply<QString, FcitxQtStringKeyValueList> InputMethodGroupInfo(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("InputMethodGroupInfo"), argumentList);
}
inline QDBusReply<QString> InputMethodGroupInfo(const QString &in0, FcitxQtStringKeyValueList &items)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("InputMethodGroupInfo"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
items = qdbus_cast<FcitxQtStringKeyValueList>(reply.arguments().at(1));
}
return reply;
}
inline QDBusPendingReply<QStringList> InputMethodGroups()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("InputMethodGroups"), argumentList);
}
inline QDBusPendingReply<> Refresh()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Refresh"), argumentList);
}
inline QDBusPendingReply<> ReloadAddonConfig(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("ReloadAddonConfig"), argumentList);
}
inline QDBusPendingReply<> ReloadConfig()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("ReloadConfig"), argumentList);
}
inline QDBusPendingReply<> RemoveInputMethodGroup(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("RemoveInputMethodGroup"), argumentList);
}
inline QDBusPendingReply<> ResetIMList()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("ResetIMList"), argumentList);
}
inline QDBusPendingReply<> Restart()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Restart"), argumentList);
}
inline QDBusPendingReply<> SetAddonsState(FcitxQtAddonStateList in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("SetAddonsState"), argumentList);
}
inline QDBusPendingReply<> SetConfig(const QString &in0, const QDBusVariant &in1)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
return asyncCallWithArgumentList(QStringLiteral("SetConfig"), argumentList);
}
inline QDBusPendingReply<> SetCurrentIM(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("SetCurrentIM"), argumentList);
}
inline QDBusPendingReply<> SetInputMethodGroupInfo(const QString &name, const QString &layout, FcitxQtStringKeyValueList entries)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(name) << QVariant::fromValue(layout) << QVariant::fromValue(entries);
return asyncCallWithArgumentList(QStringLiteral("SetInputMethodGroupInfo"), argumentList);
}
inline QDBusPendingReply<int> State()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("State"), argumentList);
}
inline QDBusPendingReply<> Toggle()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Toggle"), argumentList);
}
Q_SIGNALS: // SIGNALS
void InputMethodGroupsChanged();
};
}
#endif

View File

@@ -0,0 +1,339 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <QDBusMetaType>
#include "fcitxqtdbustypes.h"
namespace fcitx {
#define FCITX5_QT_DEFINE_DBUS_TYPE(TYPE) \
qRegisterMetaType<TYPE>(#TYPE); \
qDBusRegisterMetaType<TYPE>(); \
qRegisterMetaType<TYPE##List>(#TYPE "List"); \
qDBusRegisterMetaType<TYPE##List>();
void registerFcitxQtDBusTypes() {
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtFormattedPreedit);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtStringKeyValue);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtInputMethodEntry);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtFullInputMethodEntry);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtLayoutInfo);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtVariantInfo);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtConfigOption);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtConfigType);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtAddonInfo);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtAddonState);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtAddonInfoV2);
}
bool FcitxQtFormattedPreedit::operator==(
const FcitxQtFormattedPreedit &preedit) const {
return (preedit.format_ == format_) && (preedit.string_ == string_);
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtFormattedPreedit &preedit) {
argument.beginStructure();
argument << preedit.string();
argument << preedit.format();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtFormattedPreedit &preedit) {
QString str;
qint32 format;
argument.beginStructure();
argument >> str >> format;
argument.endStructure();
preedit.setString(str);
preedit.setFormat(format);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtStringKeyValue &arg) {
argument.beginStructure();
argument << arg.key();
argument << arg.value();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtStringKeyValue &arg) {
QString key, value;
argument.beginStructure();
argument >> key >> value;
argument.endStructure();
arg.setKey(key);
arg.setValue(value);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtInputMethodEntry &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.nativeName();
argument << arg.icon();
argument << arg.label();
argument << arg.languageCode();
argument << arg.configurable();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtInputMethodEntry &arg) {
QString uniqueName, name, nativeName, icon, label, languageCode;
bool configurable;
argument.beginStructure();
argument >> uniqueName >> name >> nativeName >> icon >> label >>
languageCode >> configurable;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setNativeName(nativeName);
arg.setIcon(icon);
arg.setLabel(label);
arg.setLanguageCode(languageCode);
arg.setConfigurable(configurable);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtFullInputMethodEntry &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.nativeName();
argument << arg.icon();
argument << arg.label();
argument << arg.languageCode();
argument << arg.addon();
argument << arg.configurable();
argument << arg.layout();
argument << arg.properties();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtFullInputMethodEntry &arg) {
QString uniqueName, name, nativeName, icon, label, languageCode, addon,
layout;
bool configurable;
QVariantMap properties;
argument.beginStructure();
argument >> uniqueName >> name >> nativeName >> icon >> label >>
languageCode >> addon >> configurable >> layout >> properties;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setNativeName(nativeName);
arg.setIcon(icon);
arg.setLabel(label);
arg.setLanguageCode(languageCode);
arg.setAddon(addon);
arg.setConfigurable(configurable);
arg.setLayout(layout);
arg.setProperties(properties);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtVariantInfo &arg) {
argument.beginStructure();
argument << arg.variant();
argument << arg.description();
argument << arg.languages();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtVariantInfo &arg) {
QString variant, description;
QStringList languages;
argument.beginStructure();
argument >> variant >> description >> languages;
argument.endStructure();
arg.setVariant(variant);
arg.setDescription(description);
arg.setLanguages(languages);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtLayoutInfo &arg) {
argument.beginStructure();
argument << arg.layout();
argument << arg.description();
argument << arg.languages();
argument << arg.variants();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtLayoutInfo &arg) {
QString layout, description;
QStringList languages;
FcitxQtVariantInfoList variants;
argument.beginStructure();
argument >> layout >> description >> languages >> variants;
argument.endStructure();
arg.setLayout(layout);
arg.setDescription(description);
arg.setLanguages(languages);
arg.setVariants(variants);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtConfigOption &arg) {
argument.beginStructure();
argument << arg.name();
argument << arg.type();
argument << arg.description();
argument << arg.defaultValue();
argument << arg.properties();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtConfigOption &arg) {
QString name, description, type;
QDBusVariant defaultValue;
QVariantMap properties;
argument.beginStructure();
argument >> name >> type >> description >> defaultValue >> properties;
argument.endStructure();
arg.setName(name);
arg.setType(type);
arg.setDescription(description);
arg.setDefaultValue(defaultValue);
arg.setProperties(properties);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtConfigType &arg) {
argument.beginStructure();
argument << arg.name();
argument << arg.options();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtConfigType &arg) {
QString name;
FcitxQtConfigOptionList options;
argument.beginStructure();
argument >> name >> options;
argument.endStructure();
arg.setName(name);
arg.setOptions(options);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtAddonInfo &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.comment();
argument << arg.category();
argument << arg.configurable();
argument << arg.enabled();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtAddonInfo &arg) {
QString uniqueName, name, comment;
int category;
bool configurable, enabled;
argument.beginStructure();
argument >> uniqueName >> name >> comment >> category >> configurable >>
enabled;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setComment(comment);
arg.setCategory(category);
arg.setConfigurable(configurable);
arg.setEnabled(enabled);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtAddonInfoV2 &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.comment();
argument << arg.category();
argument << arg.configurable();
argument << arg.enabled();
argument << arg.onDemand();
argument << arg.dependencies();
argument << arg.optionalDependencies();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtAddonInfoV2 &arg) {
QString uniqueName, name, comment;
int category;
bool configurable, enabled, onDemand;
QStringList dependencies, optionalDependencies;
argument.beginStructure();
argument >> uniqueName >> name >> comment >> category >> configurable >>
enabled >> onDemand >> dependencies >> optionalDependencies;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setComment(comment);
arg.setCategory(category);
arg.setConfigurable(configurable);
arg.setEnabled(enabled);
arg.setOnDemand(onDemand);
arg.setDependencies(dependencies);
arg.setOptionalDependencies(optionalDependencies);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtAddonState &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.enabled();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtAddonState &arg) {
QString uniqueName;
bool enabled;
argument.beginStructure();
argument >> uniqueName >> enabled;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setEnabled(enabled);
return argument;
}
} // namespace fcitx

View File

@@ -0,0 +1,171 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTDBUSTYPES_H_
#define _DBUSADDONS_FCITXQTDBUSTYPES_H_
#include "fcitx5qt5dbusaddons_export.h"
#include <QDBusArgument>
#include <type_traits>
namespace fcitx {
FCITX5QT5DBUSADDONS_EXPORT void registerFcitxQtDBusTypes();
#define FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(TYPE) \
class FCITX5QT5DBUSADDONS_EXPORT TYPE { \
public:
#define FCITX5_QT_DECLARE_FIELD(TYPE, GETTER, SETTER) \
public: \
std::conditional_t<std::is_class<TYPE>::value, const TYPE &, TYPE> \
GETTER() const { \
return GETTER##_; \
} \
void SETTER( \
std::conditional_t<std::is_class<TYPE>::value, const TYPE &, TYPE> \
value) { \
GETTER##_ = value; \
} \
\
private: \
TYPE GETTER##_ = TYPE();
#define FCITX5_QT_END_DECLARE_DBUS_TYPE(TYPE) \
} \
; \
typedef QList<TYPE> TYPE##List; \
FCITX5QT5DBUSADDONS_EXPORT QDBusArgument &operator<<( \
QDBusArgument &argument, const TYPE &value); \
FCITX5QT5DBUSADDONS_EXPORT const QDBusArgument &operator>>( \
const QDBusArgument &argument, TYPE &value);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtFormattedPreedit);
FCITX5_QT_DECLARE_FIELD(QString, string, setString);
FCITX5_QT_DECLARE_FIELD(qint32, format, setFormat);
public:
bool operator==(const FcitxQtFormattedPreedit &preedit) const;
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtFormattedPreedit);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtStringKeyValue);
FCITX5_QT_DECLARE_FIELD(QString, key, setKey);
FCITX5_QT_DECLARE_FIELD(QString, value, setValue);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtStringKeyValue);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtInputMethodEntry);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, nativeName, setNativeName);
FCITX5_QT_DECLARE_FIELD(QString, icon, setIcon);
FCITX5_QT_DECLARE_FIELD(QString, label, setLabel);
FCITX5_QT_DECLARE_FIELD(QString, languageCode, setLanguageCode);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtInputMethodEntry);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtFullInputMethodEntry);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, nativeName, setNativeName);
FCITX5_QT_DECLARE_FIELD(QString, icon, setIcon);
FCITX5_QT_DECLARE_FIELD(QString, label, setLabel);
FCITX5_QT_DECLARE_FIELD(QString, languageCode, setLanguageCode);
FCITX5_QT_DECLARE_FIELD(QString, addon, setAddon);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_DECLARE_FIELD(QString, layout, setLayout);
FCITX5_QT_DECLARE_FIELD(QVariantMap, properties, setProperties);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtFullInputMethodEntry);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtVariantInfo);
FCITX5_QT_DECLARE_FIELD(QString, variant, setVariant);
FCITX5_QT_DECLARE_FIELD(QString, description, setDescription);
FCITX5_QT_DECLARE_FIELD(QStringList, languages, setLanguages);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtVariantInfo);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtLayoutInfo);
FCITX5_QT_DECLARE_FIELD(QString, layout, setLayout);
FCITX5_QT_DECLARE_FIELD(QString, description, setDescription);
FCITX5_QT_DECLARE_FIELD(QStringList, languages, setLanguages);
FCITX5_QT_DECLARE_FIELD(FcitxQtVariantInfoList, variants, setVariants);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtLayoutInfo);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtConfigOption);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, type, setType);
FCITX5_QT_DECLARE_FIELD(QString, description, setDescription);
FCITX5_QT_DECLARE_FIELD(QDBusVariant, defaultValue, setDefaultValue);
FCITX5_QT_DECLARE_FIELD(QVariantMap, properties, setProperties);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtConfigOption);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtConfigType);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(FcitxQtConfigOptionList, options, setOptions);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtConfigType);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtAddonInfo);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, comment, setComment);
FCITX5_QT_DECLARE_FIELD(int, category, setCategory);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_DECLARE_FIELD(bool, enabled, setEnabled);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtAddonInfo);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtAddonInfoV2);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, comment, setComment);
FCITX5_QT_DECLARE_FIELD(int, category, setCategory);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_DECLARE_FIELD(bool, enabled, setEnabled);
FCITX5_QT_DECLARE_FIELD(bool, onDemand, setOnDemand);
FCITX5_QT_DECLARE_FIELD(QStringList, dependencies, setDependencies);
FCITX5_QT_DECLARE_FIELD(QStringList, optionalDependencies,
setOptionalDependencies);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtAddonInfoV2);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtAddonState);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(bool, enabled, setEnabled);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtAddonState);
} // namespace fcitx
Q_DECLARE_METATYPE(fcitx::FcitxQtFormattedPreedit)
Q_DECLARE_METATYPE(fcitx::FcitxQtFormattedPreeditList)
Q_DECLARE_METATYPE(fcitx::FcitxQtStringKeyValue)
Q_DECLARE_METATYPE(fcitx::FcitxQtStringKeyValueList)
Q_DECLARE_METATYPE(fcitx::FcitxQtInputMethodEntry)
Q_DECLARE_METATYPE(fcitx::FcitxQtInputMethodEntryList)
Q_DECLARE_METATYPE(fcitx::FcitxQtFullInputMethodEntry)
Q_DECLARE_METATYPE(fcitx::FcitxQtFullInputMethodEntryList)
Q_DECLARE_METATYPE(fcitx::FcitxQtVariantInfo)
Q_DECLARE_METATYPE(fcitx::FcitxQtVariantInfoList)
Q_DECLARE_METATYPE(fcitx::FcitxQtLayoutInfo)
Q_DECLARE_METATYPE(fcitx::FcitxQtLayoutInfoList)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigOption)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigOptionList)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigType)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigTypeList)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfo)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfoList)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfoV2)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfoV2List)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonState)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonStateList)
#endif // _DBUSADDONS_FCITXQTDBUSTYPES_H_

View File

@@ -0,0 +1,134 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitxqtinputcontextproxy_p.h"
namespace fcitx {
FcitxQtInputContextProxy::FcitxQtInputContextProxy(FcitxQtWatcher *watcher,
QObject *parent)
: QObject(parent),
d_ptr(new FcitxQtInputContextProxyPrivate(watcher, this)) {}
FcitxQtInputContextProxy::~FcitxQtInputContextProxy() { delete d_ptr; }
void FcitxQtInputContextProxy::setDisplay(const QString &display) {
Q_D(FcitxQtInputContextProxy);
d->display_ = display;
}
const QString &FcitxQtInputContextProxy::display() const {
Q_D(const FcitxQtInputContextProxy);
return d->display_;
}
bool FcitxQtInputContextProxy::isValid() const {
Q_D(const FcitxQtInputContextProxy);
return d->isValid();
}
QDBusPendingReply<> FcitxQtInputContextProxy::focusIn() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->FocusIn();
}
QDBusPendingReply<> FcitxQtInputContextProxy::focusOut() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->FocusOut();
}
QDBusPendingReply<> FcitxQtInputContextProxy::hideVirtualKeyboard() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->HideVirtualKeyboard();
}
QDBusPendingReply<bool> FcitxQtInputContextProxy::processKeyEvent(
unsigned int keyval, unsigned int keycode, unsigned int state, bool type,
unsigned int time) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->ProcessKeyEvent(keyval, keycode, state, type, time);
}
QDBusPendingReply<> FcitxQtInputContextProxy::reset() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->Reset();
}
QDBusPendingReply<>
FcitxQtInputContextProxy::setSupportedCapability(qulonglong caps) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetSupportedCapability(caps);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setCapability(qulonglong caps) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetCapability(caps);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setCursorRect(int x, int y, int w,
int h) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetCursorRect(x, y, w, h);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setCursorRectV2(int x, int y,
int w, int h,
double scale) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetCursorRectV2(x, y, w, h, scale);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setSurroundingText(
const QString &text, unsigned int cursor, unsigned int anchor) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetSurroundingText(text, cursor, anchor);
}
QDBusPendingReply<>
FcitxQtInputContextProxy::setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetSurroundingTextPosition(cursor, anchor);
}
QDBusPendingReply<> FcitxQtInputContextProxy::showVirtualKeyboard() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->ShowVirtualKeyboard();
}
QDBusPendingReply<> FcitxQtInputContextProxy::prevPage() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->PrevPage();
}
QDBusPendingReply<> FcitxQtInputContextProxy::nextPage() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->NextPage();
}
QDBusPendingReply<> FcitxQtInputContextProxy::selectCandidate(int i) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SelectCandidate(i);
}
QDBusPendingReply<> FcitxQtInputContextProxy::invokeAction(unsigned int action,
int cursor) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->InvokeAction(action, cursor);
}
bool FcitxQtInputContextProxy::isVirtualKeyboardVisible() {
Q_D(FcitxQtInputContextProxy);
return d->isVirtualKeyboardVisible_;
}
bool FcitxQtInputContextProxy::supportInvokeAction() const {
Q_D(const FcitxQtInputContextProxy);
return d->supportInvokeAction_;
}
} // namespace fcitx

View File

@@ -0,0 +1,85 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_H_
#define _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_H_
#include "fcitx5qt5dbusaddons_export.h"
#include "fcitxqtdbustypes.h"
#include <QDBusPendingReply>
namespace fcitx {
class FcitxQtWatcher;
class FcitxQtInputContextProxyPrivate;
class FCITX5QT5DBUSADDONS_EXPORT FcitxQtInputContextProxy : public QObject {
Q_OBJECT
public:
FcitxQtInputContextProxy(FcitxQtWatcher *watcher, QObject *parent);
~FcitxQtInputContextProxy();
bool isValid() const;
void setDisplay(const QString &display);
const QString &display() const;
public Q_SLOTS:
QDBusPendingReply<> focusIn();
QDBusPendingReply<> focusOut();
QDBusPendingReply<> hideVirtualKeyboard();
QDBusPendingReply<bool> processKeyEvent(unsigned int keyval,
unsigned int keycode,
unsigned int state, bool type,
unsigned int time);
QDBusPendingReply<> reset();
QDBusPendingReply<> setSupportedCapability(qulonglong caps);
QDBusPendingReply<> setCapability(qulonglong caps);
QDBusPendingReply<> setCursorRect(int x, int y, int w, int h);
QDBusPendingReply<> setCursorRectV2(int x, int y, int w, int h,
double scale);
QDBusPendingReply<> setSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor);
QDBusPendingReply<> setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor);
QDBusPendingReply<> showVirtualKeyboard();
QDBusPendingReply<> prevPage();
QDBusPendingReply<> nextPage();
QDBusPendingReply<> selectCandidate(int i);
QDBusPendingReply<> invokeAction(unsigned int action, int cursor);
bool isVirtualKeyboardVisible();
bool supportInvokeAction() const;
Q_SIGNALS:
void commitString(const QString &str);
void currentIM(const QString &name, const QString &uniqueName,
const QString &langCode);
void deleteSurroundingText(int offset, unsigned int nchar);
void forwardKey(unsigned int keyval, unsigned int state, bool isRelease);
void updateFormattedPreedit(const FcitxQtFormattedPreeditList &str,
int cursorpos);
void updateClientSideUI(const FcitxQtFormattedPreeditList &preedit,
int cursorpos,
const FcitxQtFormattedPreeditList &auxUp,
const FcitxQtFormattedPreeditList &auxDown,
const FcitxQtStringKeyValueList &candidates,
int candidateIndex, int layoutHint, bool hasPrev,
bool hasNext);
void inputContextCreated(const QByteArray &uuid);
void inputContextCreationFailed();
void notifyFocusOut();
void virtualKeyboardVisibilityChanged(bool visible);
private:
FcitxQtInputContextProxyPrivate *const d_ptr;
Q_DECLARE_PRIVATE(FcitxQtInputContextProxy);
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_H_

View File

@@ -0,0 +1,271 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_P_H_
#define _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_P_H_
#include "fcitxqtinputcontextproxy.h"
#include "fcitxqtinputcontextproxyimpl.h"
#include "fcitxqtinputmethodproxy.h"
#include "fcitxqtwatcher.h"
#include <QDBusServiceWatcher>
#include <cstddef>
namespace fcitx {
class FcitxQtInputContextProxyPrivate {
public:
FcitxQtInputContextProxyPrivate(FcitxQtWatcher *watcher,
FcitxQtInputContextProxy *q)
: q_ptr(q), fcitxWatcher_(watcher), watcher_(q) {
registerFcitxQtDBusTypes();
QObject::connect(fcitxWatcher_, &FcitxQtWatcher::availabilityChanged, q,
[this]() { availabilityChanged(); });
watcher_.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QObject::connect(&watcher_, &QDBusServiceWatcher::serviceUnregistered,
q, [this]() {
cleanUp();
availabilityChanged();
});
availabilityChanged();
}
~FcitxQtInputContextProxyPrivate() {
Q_Q(FcitxQtInputContextProxy);
if (isValid()) {
icproxy_->DestroyIC();
}
QObject::disconnect(
q, &FcitxQtInputContextProxy::virtualKeyboardVisibilityChanged,
nullptr, nullptr);
cleanUp();
}
bool isValid() const { return (icproxy_ && icproxy_->isValid()); }
void availabilityChanged() {
QTimer::singleShot(100, q_ptr, [this]() { recheck(); });
}
void recheck() {
if (!isValid() && fcitxWatcher_->availability()) {
createInputContext();
}
if (!fcitxWatcher_->availability()) {
cleanUp();
}
}
void cleanUp() {
auto services = watcher_.watchedServices();
for (const auto &service : services) {
watcher_.removeWatchedService(service);
}
delete improxy_;
improxy_ = nullptr;
delete icproxy_;
icproxy_ = nullptr;
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
delete introspectWatcher_;
introspectWatcher_ = nullptr;
delete queryWatcher_;
queryWatcher_ = nullptr;
setVirtualKeyboardVisible(false);
supportInvokeAction_ = false;
}
void createInputContext() {
Q_Q(FcitxQtInputContextProxy);
if (!fcitxWatcher_->availability()) {
return;
}
cleanUp();
auto service = fcitxWatcher_->serviceName();
auto connection = fcitxWatcher_->connection();
auto owner = connection.interface()->serviceOwner(service);
if (!owner.isValid()) {
return;
}
watcher_.setConnection(connection);
watcher_.setWatchedServices(QStringList() << owner);
// Avoid race, query again.
if (!connection.interface()->isServiceRegistered(owner)) {
cleanUp();
return;
}
QFileInfo info(QCoreApplication::applicationFilePath());
improxy_ = new FcitxQtInputMethodProxy(
owner, "/org/freedesktop/portal/inputmethod", connection, q);
FcitxQtStringKeyValueList list;
FcitxQtStringKeyValue arg;
arg.setKey("program");
arg.setValue(info.fileName());
list << arg;
if (!display_.isEmpty()) {
FcitxQtStringKeyValue arg2;
arg2.setKey("display");
arg2.setValue(display_);
list << arg2;
}
// Qt has good support for showing virtual keyboard, so we should
// disable the default behavior supported by fcitx5
FcitxQtStringKeyValue clientControlVirtualkeyboardShow;
clientControlVirtualkeyboardShow.setKey(
"clientControlVirtualkeyboardShow");
clientControlVirtualkeyboardShow.setValue("true");
list << clientControlVirtualkeyboardShow;
// Qt has poor support for hiding virtual keyboard, so we should enable
// the default behavior supported by fcitx5
FcitxQtStringKeyValue clientControlVirtualkeyboardHide;
clientControlVirtualkeyboardHide.setKey(
"clientControlVirtualkeyboardHide");
clientControlVirtualkeyboardHide.setValue("false");
list << clientControlVirtualkeyboardHide;
auto result = improxy_->CreateInputContext(list);
createInputContextWatcher_ = new QDBusPendingCallWatcher(result);
QObject::connect(createInputContextWatcher_,
&QDBusPendingCallWatcher::finished, q,
[this]() { createInputContextFinished(); });
}
void createInputContextFinished() {
Q_Q(FcitxQtInputContextProxy);
if (createInputContextWatcher_->isError()) {
cleanUp();
Q_EMIT q->inputContextCreationFailed();
return;
}
QDBusPendingReply<QDBusObjectPath, QByteArray> reply(
*createInputContextWatcher_);
icproxy_ = new FcitxQtInputContextProxyImpl(improxy_->service(),
reply.value().path(),
improxy_->connection(), q);
QObject::connect(icproxy_, &FcitxQtInputContextProxyImpl::CommitString,
q, &FcitxQtInputContextProxy::commitString);
QObject::connect(icproxy_, &FcitxQtInputContextProxyImpl::CurrentIM, q,
&FcitxQtInputContextProxy::currentIM);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::DeleteSurroundingText,
q, &FcitxQtInputContextProxy::deleteSurroundingText);
QObject::connect(icproxy_, &FcitxQtInputContextProxyImpl::ForwardKey, q,
&FcitxQtInputContextProxy::forwardKey);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::UpdateFormattedPreedit,
q, &FcitxQtInputContextProxy::updateFormattedPreedit);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::UpdateClientSideUI, q,
&FcitxQtInputContextProxy::updateClientSideUI);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::NotifyFocusOut, q,
&FcitxQtInputContextProxy::notifyFocusOut);
QObject::connect(
icproxy_,
&FcitxQtInputContextProxyImpl::VirtualKeyboardVisibilityChanged, q,
[this](bool visible) {
if (queryWatcher_) {
queryWatcher_->deleteLater();
queryWatcher_ = nullptr;
}
setVirtualKeyboardVisible(visible);
});
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
Q_EMIT q->inputContextCreated(reply.argumentAt<1>());
introspect();
virtualKeyboardVisibilityQuery();
}
void introspect() {
Q_Q(FcitxQtInputContextProxy);
if (introspectWatcher_) {
delete introspectWatcher_;
introspectWatcher_ = nullptr;
}
QDBusMessage call = QDBusMessage::createMethodCall(
icproxy_->service(), icproxy_->path(),
"org.freedesktop.DBus.Introspectable", "Introspect");
introspectWatcher_ = new QDBusPendingCallWatcher(
fcitxWatcher_->connection().asyncCall(call));
QObject::connect(introspectWatcher_, &QDBusPendingCallWatcher::finished,
q, [this]() { introspectFinished(); });
}
void introspectFinished() {
if (introspectWatcher_->isFinished() &&
!introspectWatcher_->isError()) {
QDBusPendingReply<QString> reply = *introspectWatcher_;
if (reply.value().contains("InvokeAction")) {
supportInvokeAction_ = true;
}
}
delete introspectWatcher_;
introspectWatcher_ = nullptr;
}
void virtualKeyboardVisibilityQuery() {
Q_Q(FcitxQtInputContextProxy);
if (queryWatcher_) {
delete queryWatcher_;
queryWatcher_ = nullptr;
}
queryWatcher_ =
new QDBusPendingCallWatcher(icproxy_->IsVirtualKeyboardVisible());
QObject::connect(
queryWatcher_, &QDBusPendingCallWatcher::finished, q,
[this]() { virtualKeyboardVisibilityQueryFinished(); });
}
void virtualKeyboardVisibilityQueryFinished() {
if (queryWatcher_ && queryWatcher_->isFinished() &&
!queryWatcher_->isError()) {
QDBusPendingReply<bool> reply = *queryWatcher_;
setVirtualKeyboardVisible(reply.value());
}
delete queryWatcher_;
queryWatcher_ = nullptr;
}
void setVirtualKeyboardVisible(bool visible) {
Q_Q(FcitxQtInputContextProxy);
if (isVirtualKeyboardVisible_ != visible) {
isVirtualKeyboardVisible_ = visible;
Q_EMIT q->virtualKeyboardVisibilityChanged(
isVirtualKeyboardVisible_);
}
}
FcitxQtInputContextProxy *q_ptr;
Q_DECLARE_PUBLIC(FcitxQtInputContextProxy);
FcitxQtWatcher *fcitxWatcher_;
QDBusServiceWatcher watcher_;
FcitxQtInputMethodProxy *improxy_ = nullptr;
FcitxQtInputContextProxyImpl *icproxy_ = nullptr;
bool isVirtualKeyboardVisible_ = false;
bool supportInvokeAction_ = false;
QDBusPendingCallWatcher *createInputContextWatcher_ = nullptr;
QDBusPendingCallWatcher *introspectWatcher_ = nullptr;
QDBusPendingCallWatcher *queryWatcher_ = nullptr;
QString display_;
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_P_H_

View File

@@ -0,0 +1,31 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputcontextproxyimpl -c
* FcitxQtInputContextProxyImpl interfaces/org.fcitx.Fcitx.InputContext1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitxqtinputcontextproxyimpl.h"
namespace fcitx {
/*
* Implementation of interface class FcitxQtInputContextProxyImpl
*/
FcitxQtInputContextProxyImpl::FcitxQtInputContextProxyImpl(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
FcitxQtInputContextProxyImpl::~FcitxQtInputContextProxyImpl()
{
}
}

View File

@@ -0,0 +1,178 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputcontextproxyimpl -c
* FcitxQtInputContextProxyImpl interfaces/org.fcitx.Fcitx.InputContext1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITXQTINPUTCONTEXTPROXYIMPL_H
#define FCITXQTINPUTCONTEXTPROXYIMPL_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "fcitxqtdbustypes.h"
#include "fcitx5qt5dbusaddons_export.h"
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.InputContext1
*/
class FCITX5QT5DBUSADDONS_EXPORT FcitxQtInputContextProxyImpl: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.fcitx.Fcitx.InputContext1"; }
public:
FcitxQtInputContextProxyImpl(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~FcitxQtInputContextProxyImpl();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> DestroyIC()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("DestroyIC"), argumentList);
}
inline QDBusPendingReply<> FocusIn()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("FocusIn"), argumentList);
}
inline QDBusPendingReply<> FocusOut()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("FocusOut"), argumentList);
}
inline QDBusPendingReply<> HideVirtualKeyboard()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("HideVirtualKeyboard"), argumentList);
}
inline QDBusPendingReply<> InvokeAction(unsigned int action, int cursor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(action)
<< QVariant::fromValue(cursor);
return asyncCallWithArgumentList(QStringLiteral("InvokeAction"),
argumentList);
}
inline QDBusPendingReply<bool> IsVirtualKeyboardVisible() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(
QStringLiteral("IsVirtualKeyboardVisible"), argumentList);
}
inline QDBusPendingReply<> NextPage()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("NextPage"), argumentList);
}
inline QDBusPendingReply<> PrevPage()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("PrevPage"), argumentList);
}
inline QDBusPendingReply<bool>
ProcessKeyEvent(unsigned int keyval, unsigned int keycode,
unsigned int state, bool type, unsigned int time) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(keyval) << QVariant::fromValue(keycode) << QVariant::fromValue(state) << QVariant::fromValue(type) << QVariant::fromValue(time);
return asyncCallWithArgumentList(QStringLiteral("ProcessKeyEvent"), argumentList);
}
inline QDBusPendingReply<> Reset()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Reset"), argumentList);
}
inline QDBusPendingReply<> SelectCandidate(int index)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(index);
return asyncCallWithArgumentList(QStringLiteral("SelectCandidate"), argumentList);
}
inline QDBusPendingReply<> SetCapability(qulonglong caps)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
return asyncCallWithArgumentList(QStringLiteral("SetCapability"), argumentList);
}
inline QDBusPendingReply<> SetCursorRect(int x, int y, int w, int h)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
return asyncCallWithArgumentList(QStringLiteral("SetCursorRect"), argumentList);
}
inline QDBusPendingReply<> SetCursorRectV2(int x, int y, int w, int h, double scale)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h) << QVariant::fromValue(scale);
return asyncCallWithArgumentList(QStringLiteral("SetCursorRectV2"), argumentList);
}
inline QDBusPendingReply<> SetSupportedCapability(qulonglong caps) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
return asyncCallWithArgumentList(
QStringLiteral("SetSupportedCapability"), argumentList);
}
inline QDBusPendingReply<> SetSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(text) << QVariant::fromValue(cursor) << QVariant::fromValue(anchor);
return asyncCallWithArgumentList(QStringLiteral("SetSurroundingText"), argumentList);
}
inline QDBusPendingReply<> SetSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(cursor) << QVariant::fromValue(anchor);
return asyncCallWithArgumentList(QStringLiteral("SetSurroundingTextPosition"), argumentList);
}
inline QDBusPendingReply<> ShowVirtualKeyboard()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("ShowVirtualKeyboard"), argumentList);
}
Q_SIGNALS: // SIGNALS
void CommitString(const QString &str);
void CurrentIM(const QString &name, const QString &uniqueName, const QString &langCode);
void DeleteSurroundingText(int offset, unsigned int nchar);
void ForwardKey(unsigned int keyval, unsigned int state, bool type);
void NotifyFocusOut();
void UpdateClientSideUI(FcitxQtFormattedPreeditList preedit, int cursorpos, FcitxQtFormattedPreeditList auxUp, FcitxQtFormattedPreeditList auxDown, FcitxQtStringKeyValueList candidates, int candidateIndex, int layoutHint, bool hasPrev, bool hasNext);
void UpdateFormattedPreedit(FcitxQtFormattedPreeditList str, int cursorpos);
void VirtualKeyboardVisibilityChanged(bool visible);
};
}
#endif

View File

@@ -0,0 +1,31 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputmethodproxy -c
* FcitxQtInputMethodProxy interfaces/org.fcitx.Fcitx.InputMethod1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitxqtinputmethodproxy.h"
namespace fcitx {
/*
* Implementation of interface class FcitxQtInputMethodProxy
*/
FcitxQtInputMethodProxy::FcitxQtInputMethodProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
FcitxQtInputMethodProxy::~FcitxQtInputMethodProxy()
{
}
}

View File

@@ -0,0 +1,67 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputmethodproxy -c
* FcitxQtInputMethodProxy interfaces/org.fcitx.Fcitx.InputMethod1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITXQTINPUTMETHODPROXY_H
#define FCITXQTINPUTMETHODPROXY_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "fcitxqtdbustypes.h"
#include "fcitx5qt5dbusaddons_export.h"
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.InputMethod1
*/
class FCITX5QT5DBUSADDONS_EXPORT FcitxQtInputMethodProxy: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.fcitx.Fcitx.InputMethod1"; }
public:
FcitxQtInputMethodProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~FcitxQtInputMethodProxy();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<QDBusObjectPath, QByteArray> CreateInputContext(FcitxQtStringKeyValueList in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("CreateInputContext"), argumentList);
}
inline QDBusReply<QDBusObjectPath> CreateInputContext(FcitxQtStringKeyValueList in0, QByteArray &out1)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("CreateInputContext"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
out1 = qdbus_cast<QByteArray>(reply.arguments().at(1));
}
return reply;
}
Q_SIGNALS: // SIGNALS
};
}
#endif

View File

@@ -0,0 +1,137 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitxqtwatcher_p.h"
#include <QDBusConnectionInterface>
namespace fcitx {
FcitxQtWatcher::FcitxQtWatcher(QObject *parent)
: QObject(parent), d_ptr(new FcitxQtWatcherPrivate(this)) {}
FcitxQtWatcher::FcitxQtWatcher(const QDBusConnection &connection,
QObject *parent)
: FcitxQtWatcher(parent) {
setConnection(connection);
}
FcitxQtWatcher::~FcitxQtWatcher() { delete d_ptr; }
bool FcitxQtWatcher::availability() const {
Q_D(const FcitxQtWatcher);
return d->availability_;
}
void FcitxQtWatcher::setConnection(const QDBusConnection &connection) {
Q_D(FcitxQtWatcher);
return d->serviceWatcher_.setConnection(connection);
}
QDBusConnection FcitxQtWatcher::connection() const {
Q_D(const FcitxQtWatcher);
return d->serviceWatcher_.connection();
}
void FcitxQtWatcher::setWatchPortal(bool portal) {
Q_D(FcitxQtWatcher);
d->watchPortal_ = portal;
}
bool FcitxQtWatcher::watchPortal() const {
Q_D(const FcitxQtWatcher);
return d->watchPortal_;
}
QString FcitxQtWatcher::serviceName() const {
Q_D(const FcitxQtWatcher);
if (d->mainPresent_) {
return FCITX_MAIN_SERVICE_NAME;
}
if (d->portalPresent_) {
return FCITX_PORTAL_SERVICE_NAME;
}
return QString();
}
void FcitxQtWatcher::setAvailability(bool availability) {
Q_D(FcitxQtWatcher);
if (d->availability_ != availability) {
d->availability_ = availability;
Q_EMIT availabilityChanged(d->availability_);
}
}
void FcitxQtWatcher::watch() {
Q_D(FcitxQtWatcher);
if (d->watched_) {
return;
}
connect(&d->serviceWatcher_, &QDBusServiceWatcher::serviceOwnerChanged,
this, &FcitxQtWatcher::imChanged);
d->serviceWatcher_.addWatchedService(FCITX_MAIN_SERVICE_NAME);
if (d->watchPortal_) {
d->serviceWatcher_.addWatchedService(FCITX_PORTAL_SERVICE_NAME);
}
if (connection().interface()->isServiceRegistered(
FCITX_MAIN_SERVICE_NAME)) {
d->mainPresent_ = true;
}
if (d->watchPortal_ && connection().interface()->isServiceRegistered(
FCITX_PORTAL_SERVICE_NAME)) {
d->portalPresent_ = true;
}
updateAvailability();
d->watched_ = true;
}
void FcitxQtWatcher::unwatch() {
Q_D(FcitxQtWatcher);
if (!d->watched_) {
return;
}
disconnect(&d->serviceWatcher_, &QDBusServiceWatcher::serviceOwnerChanged,
this, &FcitxQtWatcher::imChanged);
d->mainPresent_ = false;
d->portalPresent_ = false;
d->watched_ = false;
updateAvailability();
}
bool FcitxQtWatcher::isWatching() const {
Q_D(const FcitxQtWatcher);
return d->watched_;
}
void FcitxQtWatcher::imChanged(const QString &service, const QString &,
const QString &newOwner) {
Q_D(FcitxQtWatcher);
if (service == FCITX_MAIN_SERVICE_NAME) {
if (!newOwner.isEmpty()) {
d->mainPresent_ = true;
} else {
d->mainPresent_ = false;
}
} else if (service == FCITX_PORTAL_SERVICE_NAME) {
if (!newOwner.isEmpty()) {
d->portalPresent_ = true;
} else {
d->portalPresent_ = false;
}
}
updateAvailability();
}
void FcitxQtWatcher::updateAvailability() {
Q_D(FcitxQtWatcher);
setAvailability(d->mainPresent_ || d->portalPresent_);
}
} // namespace fcitx

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTWATCHER_H_
#define _DBUSADDONS_FCITXQTWATCHER_H_
#include "fcitx5qt5dbusaddons_export.h"
#include <QDBusConnection>
#include <QObject>
namespace fcitx {
class FcitxQtWatcherPrivate;
class FCITX5QT5DBUSADDONS_EXPORT FcitxQtWatcher : public QObject {
Q_OBJECT
public:
explicit FcitxQtWatcher(QObject *parent = nullptr);
explicit FcitxQtWatcher(const QDBusConnection &connection,
QObject *parent = nullptr);
~FcitxQtWatcher();
void watch();
void unwatch();
void setConnection(const QDBusConnection &connection);
QDBusConnection connection() const;
void setWatchPortal(bool portal);
bool watchPortal() const;
bool isWatching() const;
bool availability() const;
QString serviceName() const;
Q_SIGNALS:
void availabilityChanged(bool);
private Q_SLOTS:
void imChanged(const QString &service, const QString &oldOwner,
const QString &newOwner);
private:
void setAvailability(bool availability);
void updateAvailability();
FcitxQtWatcherPrivate *const d_ptr;
Q_DECLARE_PRIVATE(FcitxQtWatcher);
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTWATCHER_H_

View File

@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTWATCHER_P_H_
#define _DBUSADDONS_FCITXQTWATCHER_P_H_
#include "fcitxqtwatcher.h"
#include <QDBusServiceWatcher>
#define FCITX_MAIN_SERVICE_NAME "org.fcitx.Fcitx5"
#define FCITX_PORTAL_SERVICE_NAME "org.freedesktop.portal.Fcitx"
namespace fcitx {
class FcitxQtWatcherPrivate {
public:
FcitxQtWatcherPrivate(FcitxQtWatcher *q) : serviceWatcher_(q) {}
QDBusServiceWatcher serviceWatcher_;
bool watchPortal_ = false;
bool availability_ = false;
bool mainPresent_ = false;
bool portalPresent_ = false;
bool watched_ = false;
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTWATCHER_P_H_

View File

@@ -0,0 +1,5 @@
#!/bin/sh
qdbusxml2cpp-qt5 -N -p fcitxqtinputcontextproxyimpl -c FcitxQtInputContextProxyImpl interfaces/org.fcitx.Fcitx.InputContext1.xml -i fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
qdbusxml2cpp-qt5 -N -p fcitxqtinputmethodproxy -c FcitxQtInputMethodProxy interfaces/org.fcitx.Fcitx.InputMethod1.xml -i fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h
qdbusxml2cpp-qt5 -N -p fcitxqtcontrollerproxy -c FcitxQtControllerProxy interfaces/org.fcitx.Fcitx.Controller1.xml -i fcitxqtdbustypes.h -i fcitx5qt5dbusaddons_export.h

View File

@@ -0,0 +1,117 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.fcitx.Fcitx.Controller1">
<method name="Exit">
</method>
<method name="Restart">
</method>
<method name="Configure">
</method>
<method name="ConfigureAddon">
<arg type="s" direction="in"/>
</method>
<method name="ConfigureIM">
<arg type="s" direction="in"/>
</method>
<method name="CurrentUI">
<arg type="s" direction="out"/>
</method>
<method name="AddonForIM">
<arg type="s" direction="in"/>
<arg type="s" direction="out"/>
</method>
<method name="Activate">
</method>
<method name="Toggle">
</method>
<method name="ResetIMList">
</method>
<method name="State">
<arg type="i" direction="out"/>
</method>
<method name="ReloadConfig">
</method>
<method name="ReloadAddonConfig">
<arg type="s" direction="in"/>
</method>
<method name="CurrentInputMethod">
<arg type="s" direction="out"/>
</method>
<method name="SetCurrentIM">
<arg type="s" direction="in"/>
</method>
<method name="FullInputMethodGroupInfo">
<arg type="s" direction="in"/>
<arg type="s" name="groupName" direction="out"/>
<arg type="s" name="defaultInputMethod" direction="out"/>
<arg type="s" name="defaultLayout" direction="out"/>
<arg type="a{sv}" name="properties" direction="out"/>
<arg type="a(sssssssbsa{sv})" name="inputMethodEntryList" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="QVariantMap" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out4" value="FcitxQtFullInputMethodEntryList" />
</method>
<method name="InputMethodGroupInfo">
<arg type="s" direction="in"/>
<arg type="s" name="layout" direction="out"/>
<arg type="a(ss)" name="items" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="FcitxQtStringKeyValueList" />
</method>
<method name="InputMethodGroups">
<arg type="as" direction="out"/>
</method>
<method name="AvailableInputMethods">
<arg type="a(ssssssb)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FcitxQtInputMethodEntryList" />
</method>
<signal name="InputMethodGroupsChanged">
</signal>
<method name="AvailableKeyboardLayouts">
<arg type="a(ssasa(ssas))" direction="out" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FcitxQtLayoutInfoList" />
</method>
<method name="SetInputMethodGroupInfo">
<arg type="s" name="name" direction="in"/>
<arg type="s" name="layout" direction="in"/>
<arg type="a(ss)" name="entries" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="FcitxQtStringKeyValueList" />
</method>
<method name="AddInputMethodGroup">
<arg type="s" direction="in"/>
</method>
<method name="RemoveInputMethodGroup">
<arg type="s" direction="in"/>
</method>
<method name="GetConfig">
<arg type="s" direction="in"/>
<arg type="v" direction="out"/>
<arg type="a(sa(sssva{sv}))" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="FcitxQtConfigTypeList" />
</method>
<method name="SetConfig">
<arg type="s" direction="in"/>
<arg type="v" direction="in"/>
</method>
<method name="GetAddons">
<arg type="a(sssibb)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FcitxQtAddonInfoList" />
</method>
<method name="GetAddonsV2">
<arg type="a(sssibbbasas)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FcitxQtAddonInfoV2List" />
</method>
<method name="SetAddonsState">
<arg type="a(sb)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FcitxQtAddonStateList" />
</method>
<method name="Refresh">
</method>
<method name="CheckUpdate">
<arg type="b" direction="out"/>
</method>
<method name="CanRestart">
<arg type="b" direction="out"/>
</method>
</interface>
</node>

View File

@@ -0,0 +1,117 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.fcitx.Fcitx.InputContext1">
<method name="FocusIn">
</method>
<method name="FocusOut">
</method>
<method name="Reset">
</method>
<method name="SetCursorRect">
<arg name="x" direction="in" type="i"/>
<arg name="y" direction="in" type="i"/>
<arg name="w" direction="in" type="i"/>
<arg name="h" direction="in" type="i"/>
</method>
<method name="SetCursorRectV2">
<arg name="x" direction="in" type="i"/>
<arg name="y" direction="in" type="i"/>
<arg name="w" direction="in" type="i"/>
<arg name="h" direction="in" type="i"/>
<arg name="scale" direction="in" type="d"/>
</method>
<method name="SetSupportedCapability">
<arg name="caps" direction="in" type="t"/>
</method>
<method name="SetCapability">
<arg name="caps" direction="in" type="t"/>
</method>
<method name="SetSurroundingText">
<arg name="text" direction="in" type="s"/>
<arg name="cursor" direction="in" type="u"/>
<arg name="anchor" direction="in" type="u"/>
</method>
<method name="SetSurroundingTextPosition">
<arg name="cursor" direction="in" type="u"/>
<arg name="anchor" direction="in" type="u"/>
</method>
<method name="DestroyIC">
</method>
<method name="ProcessKeyEvent">
<arg name="keyval" direction="in" type="u"/>
<arg name="keycode" direction="in" type="u"/>
<arg name="state" direction="in" type="u"/>
<arg name="type" direction="in" type="b"/>
<arg name="time" direction="in" type="u"/>
<arg name="ret" direction="out" type="b"/>
</method>
<method name="PrevPage">
</method>
<method name="NextPage">
</method>
<method name="SelectCandidate">
<arg name="index" direction="in" type="i"/>
</method>
<method name="InvokeAction">
<arg name="action" direction="in" type="u"/>
<arg name="cursor" direction="in" type="i"/>
</method>
<method name="ShowVirtualKeyboard">
</method>
<method name="HideVirtualKeyboard">
</method>
<method name="IsVirtualKeyboardVisible">
<arg name="visible" direction="out" type="b"/>
</method>
<signal name="CommitString">
<arg name="str" type="s"/>
</signal>
<signal name="CurrentIM">
<arg name="name" type="s"/>
<arg name="uniqueName" type="s"/>
<arg name="langCode" type="s"/>
</signal>
<signal name="UpdateFormattedPreedit">
<arg name="str" type="a(si)" />
<arg name="cursorpos" type="i"/>
<!-- qt4 / 5 seems use in/out differently -->
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FcitxQtFormattedPreeditList" />
</signal>
<signal name="UpdateClientSideUI">
<arg name="preedit" type="a(si)" />
<arg name="cursorpos" type="i"/>
<arg name="auxUp" type="a(si)" />
<arg name="auxDown" type="a(si)" />
<arg name="candidates" type="a(ss)" />
<arg name="candidateIndex" type="i"/>
<arg name="layoutHint" type="i"/>
<arg name="hasPrev" type="b" />
<arg name="hasNext" type="b" />
<!-- qt4 / 5 seems use in/out differently -->
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.In4" value="FcitxQtFormattedPreeditList" />
<annotation name="org.qtproject.QtDBus.QtTypeName.Out4" value="FcitxQtStringKeyValueList" />
</signal>
<signal name="DeleteSurroundingText">
<arg name="offset" type="i"/>
<arg name="nchar" type="u"/>
</signal>
<signal name="ForwardKey">
<arg name="keyval" type="u"/>
<arg name="state" type="u"/>
<arg name="type" type="b"/>
</signal>
<signal name="NotifyFocusOut">
</signal>
<signal name="VirtualKeyboardVisibilityChanged">
<arg name="visible" type="b"/>
</signal>
</interface>
</node>

View File

@@ -0,0 +1,12 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.fcitx.Fcitx.InputMethod1">
<method name="CreateInputContext">
<arg type="a(ss)" direction="in"/>
<arg type="o" direction="out"/>
<arg type="ay" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FcitxQtStringKeyValueList" />
</method>
</interface>
</node>

View File

@@ -0,0 +1,25 @@
set(QT_WRAPPER_SRCS
main.cpp
wrapperapp.cpp
mainwindow.cpp
)
add_executable(fcitx5-qt5-gui-wrapper ${QT_WRAPPER_SRCS})
set_target_properties(fcitx5-qt5-gui-wrapper
PROPERTIES AUTOMOC TRUE AUTOUIC TRUE AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h")
target_link_libraries(fcitx5-qt5-gui-wrapper
Fcitx5::Utils
Qt5::Core
Qt5::Gui
Qt5::Widgets
Fcitx5Qt5::DBusAddons
Fcitx5Qt5::WidgetsAddons
)
install(TARGETS fcitx5-qt5-gui-wrapper DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}")
configure_file(org.fcitx.fcitx5-qt5-gui-wrapper.desktop.in.in ${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-qt5-gui-wrapper.desktop.in @ONLY)
fcitx5_translate_desktop_file(${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-qt5-gui-wrapper.desktop.in
org.fcitx.fcitx5-qt5-gui-wrapper.desktop)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-qt5-gui-wrapper.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)

View File

@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: 2017~2017 xzhao <i@xuzhao.net>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "wrapperapp.h"
#include <QCommandLineParser>
#include <locale.h>
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
QGuiApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
fcitx::WrapperApp app(argc, argv);
app.init();
return app.exec();
}

View File

@@ -0,0 +1,150 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: 2017~2017 xzhao <i@xuzhao.net>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "mainwindow.h"
#include "fcitxqtconfiguifactory.h"
#include "fcitxqtcontrollerproxy.h"
#include "fcitxqtwatcher.h"
#include <QDebug>
#include <QLocale>
#include <QMessageBox>
#include <QPushButton>
#include <QWindow>
#include <fcitx-utils/i18n.h>
namespace fcitx {
MainWindow::MainWindow(const QString &path, FcitxQtConfigUIWidget *pluginWidget,
QWidget *parent)
: QDialog(parent), path_(path), watcher_(new FcitxQtWatcher(this)),
pluginWidget_(pluginWidget), proxy_(0) {
setupUi(this);
watcher_->setConnection(QDBusConnection::sessionBus());
verticalLayout->insertWidget(0, pluginWidget_);
buttonBox->button(QDialogButtonBox::Ok)->setText(_("&Ok"));
buttonBox->button(QDialogButtonBox::Apply)->setText(_("&Apply"));
buttonBox->button(QDialogButtonBox::Reset)->setText(_("&Reset"));
buttonBox->button(QDialogButtonBox::Close)->setText(_("&Close"));
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
buttonBox->button(QDialogButtonBox::Reset)->setEnabled(false);
setWindowIcon(QIcon::fromTheme(pluginWidget_->icon()));
setWindowTitle(pluginWidget_->title());
connect(pluginWidget_, &FcitxQtConfigUIWidget::changed, this,
&MainWindow::changed);
if (pluginWidget_->asyncSave()) {
connect(pluginWidget_, &FcitxQtConfigUIWidget::saveFinished, this,
&MainWindow::saveFinished);
}
connect(pluginWidget_, &FcitxQtConfigUIWidget::saveSubConfig, this,
&MainWindow::saveSubConfig);
connect(buttonBox, &QDialogButtonBox::clicked, this, &MainWindow::clicked);
connect(watcher_, &FcitxQtWatcher::availabilityChanged, this,
&MainWindow::availabilityChanged);
watcher_->watch();
}
void MainWindow::availabilityChanged(bool avail) {
if (!avail) {
return;
}
if (proxy_) {
delete proxy_;
}
proxy_ = new FcitxQtControllerProxy(watcher_->serviceName(),
QLatin1String("/controller"),
watcher_->connection(), this);
}
void MainWindow::clicked(QAbstractButton *button) {
QDialogButtonBox::StandardButton standardButton =
buttonBox->standardButton(button);
if (standardButton == QDialogButtonBox::Apply ||
standardButton == QDialogButtonBox::Ok) {
if (pluginWidget_->asyncSave())
pluginWidget_->setEnabled(false);
if (standardButton == QDialogButtonBox::Ok) {
closeAfterSave_ = true;
}
pluginWidget_->save();
if (!pluginWidget_->asyncSave())
saveFinished();
} else if (standardButton == QDialogButtonBox::Close) {
qApp->quit();
} else if (standardButton == QDialogButtonBox::Reset) {
pluginWidget_->load();
}
}
void MainWindow::saveFinished() {
if (proxy_) {
// Pass some arbitrary thing.
auto watcher = new QDBusPendingCallWatcher(
proxy_->SetConfig(path_, QDBusVariant(0)), this);
connect(watcher, &QDBusPendingCallWatcher::finished, this,
&MainWindow::saveFinishedPhase2);
} else {
saveFinishedPhase2(nullptr);
}
}
void MainWindow::saveFinishedPhase2(QDBusPendingCallWatcher *watcher) {
if (watcher) {
watcher->deleteLater();
}
if (pluginWidget_->asyncSave()) {
pluginWidget_->setEnabled(true);
}
if (!watcher || watcher->isError()) {
QMessageBox::warning(
this, _("Failed to notify Fcitx"),
_("Failed to notify Fcitx about the configuration change."));
closeAfterSave_ = false;
return;
}
if (closeAfterSave_) {
qApp->quit();
}
}
void MainWindow::saveSubConfig(const QString &path) {
if (proxy_) {
// Pass some arbitrary thing.
proxy_->SetConfig(path, QDBusVariant(0));
}
}
void MainWindow::changed(bool changed) {
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(changed);
buttonBox->button(QDialogButtonBox::Apply)->setEnabled(changed);
buttonBox->button(QDialogButtonBox::Reset)->setEnabled(changed);
}
void MainWindow::setParentWindow(WId id) { wid_ = id; }
void MainWindow::showEvent(QShowEvent *event) {
if (!wid_) {
return;
}
setAttribute(Qt::WA_NativeWindow, true);
QWindow *subWindow = windowHandle();
Q_ASSERT(subWindow);
QWindow *mainWindow = QWindow::fromWinId(wid_);
wid_ = 0;
if (!mainWindow) {
// foreign windows not supported on all platforms
return;
}
connect(this, &QObject::destroyed, mainWindow, &QObject::deleteLater);
subWindow->setTransientParent(mainWindow);
QDialog::showEvent(event);
}
} // namespace fcitx

View File

@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2012~2012 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: 2017~2017 xzhao
* i@xuzhao.net
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef FCITX5QT_GUIWRAPPER_MAINWINDOW_H
#define FCITX5QT_GUIWRAPPER_MAINWINDOW_H
#include <QDialog>
#include "fcitxqtconfiguiwidget.h"
#include "ui_mainwindow.h"
#include <QDBusPendingCallWatcher>
namespace fcitx {
class FcitxQtControllerProxy;
class FcitxQtWatcher;
class MainWindow : public QDialog, public Ui::MainWindow {
Q_OBJECT
public:
explicit MainWindow(const QString &path,
FcitxQtConfigUIWidget *pluginWidget,
QWidget *parent = 0);
void setParentWindow(WId id);
public Q_SLOTS:
void changed(bool changed);
void clicked(QAbstractButton *button);
void availabilityChanged(bool avail);
void saveSubConfig(const QString &path);
protected:
void showEvent(QShowEvent *event) override;
private Q_SLOTS:
void saveFinished();
void saveFinishedPhase2(QDBusPendingCallWatcher *watcher);
private:
QString path_;
FcitxQtWatcher *watcher_;
FcitxQtConfigUIWidget *pluginWidget_;
FcitxQtControllerProxy *proxy_;
WId wid_ = 0;
bool closeAfterSave_ = false;
};
} // namespace fcitx
#endif // FCITXQT5_GUIWRAPPER_MAINWINDOW_H

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QWidget" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Name=Fcitx 5 Qt5 Gui Wrapper
GenericName=Input Method Configuration helper
Comment=Load configuration plugin for Fcitx Addon
Icon=fcitx
Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/fcitx5-qt5-gui-wrapper
Type=Application
Categories=Settings;
NoDisplay=true

View File

@@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: 2012~2012 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: 2017~2017 xzhao <i@xuzhao.net>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <QDebug>
#include "fcitxqtconfiguifactory.h"
#include "mainwindow.h"
#include "wrapperapp.h"
#include <QCommandLineParser>
#include <QWindow>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/standardpath.h>
namespace fcitx {
WrapperApp::WrapperApp(int &argc, char **argv)
: QApplication(argc, argv), factory_(new FcitxQtConfigUIFactory(this)),
mainWindow_(0) {
setApplicationName(QLatin1String(
"fcitx5-qt" QT_STRINGIFY(QT_VERSION_MAJOR) "-gui-wrapper"));
setApplicationVersion(QLatin1String(FCITX5_QT_VERSION));
setOrganizationDomain("fcitx.org");
}
void WrapperApp::init() {
QCommandLineParser parser;
parser.setApplicationDescription(_("A launcher for Fcitx Gui plugin."));
parser.addHelpOption();
parser.addOptions({
{{"w", "winid"}, _("Parent window ID"), _("winid")},
{{"t", "test"}, _("Test if config exists")},
});
parser.addPositionalArgument(_("path"), _("Config path"));
parser.process(*this);
auto args = parser.positionalArguments();
if (args.empty()) {
qWarning("Missing path argument.");
::exit(1);
return;
}
QString path = args[0];
if (!path.startsWith("fcitx://config/addon/")) {
path.prepend("fcitx://config/addon/");
}
if (parser.isSet("test")) {
if (factory_->test(path)) {
::exit(0);
} else {
::exit(1);
}
} else {
WId winid = 0;
bool ok = false;
if (parser.isSet("winid")) {
winid = parser.value("winid").toLong(&ok, 0);
}
FcitxQtConfigUIWidget *widget = factory_->create(path);
if (!widget) {
qWarning("Could not find plugin for file.");
QMetaObject::invokeMethod(this, "errorExit", Qt::QueuedConnection);
return;
}
mainWindow_ = new MainWindow(path, widget);
if (ok && winid) {
mainWindow_->setParentWindow(winid);
}
QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection);
}
}
void WrapperApp::run() {
mainWindow_->exec();
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
}
WrapperApp::~WrapperApp() {
if (mainWindow_) {
delete mainWindow_;
}
}
void WrapperApp::errorExit() { exit(1); }
} // namespace fcitx

View File

@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2012~2012 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: 2017~2017 xzhao <i@xuzhao.net>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _GUIWRAPPER_WRAPPERAPP_H_
#define _GUIWRAPPER_WRAPPERAPP_H_
#include "mainwindow.h"
#include <QApplication>
namespace fcitx {
class FcitxQtConfigUIFactory;
class WrapperApp : public QApplication {
Q_OBJECT
public:
WrapperApp(int &argc, char **argv);
virtual ~WrapperApp();
void init();
public Q_SLOTS:
void run();
private Q_SLOTS:
void errorExit();
private:
FcitxQtConfigUIFactory *factory_;
MainWindow *mainWindow_;
};
} // namespace fcitx
#endif // _GUIWRAPPER_WRAPPERAPP_H_

View File

@@ -0,0 +1,5 @@
add_executable(fcitx5-qt5-immodule-probing main.cpp)
target_include_directories(fcitx5-qt5-immodule-probing PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
target_link_libraries(fcitx5-qt5-immodule-probing Qt5::Gui)
install(TARGETS fcitx5-qt5-immodule-probing DESTINATION "${CMAKE_INSTALL_BINDIR}")

View File

@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2023~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include <QGuiApplication>
#include <iostream>
#include <private/qguiapplication_p.h>
#include <qpa/qplatforminputcontext.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatformintegration.h>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
std::cout << "QT_QPA_PLATFORM=" << app.platformName().toStdString()
<< std::endl;
std::cout << "QT_IM_MODULE="
<< QPlatformInputContextFactory::requested().toStdString()
<< std::endl;
auto inputContext =
QGuiApplicationPrivate::platformIntegration()->inputContext();
std::cout << "IM_MODULE_CLASSNAME=";
if (inputContext) {
std::cout << inputContext->metaObject()->className();
}
std::cout << std::endl;
return 0;
}

View File

@@ -0,0 +1,57 @@
set(FCITX5_QT_EXTRA_PLUGIN_NAME "")
if (WITH_FCITX_PLUGIN_NAME)
set(FCITX5_QT_EXTRA_PLUGIN_NAME "\"fcitx\",")
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/fcitx5.json.in" "${CMAKE_CURRENT_BINARY_DIR}/fcitx5.json")
set(plugin_SRCS
fcitx4watcher.cpp
fcitx4inputcontextproxy.cpp
fcitx4inputcontextproxyimpl.cpp
fcitx4inputmethodproxy.cpp
hybridinputcontext.cpp
qfcitxplatforminputcontext.cpp
fcitxcandidatewindow.cpp
fcitxtheme.cpp
font.cpp
qtkey.cpp
main.cpp
)
if (BUILD_ONLY_PLUGIN AND BUILD_STATIC_PLUGIN)
set(plugin_SRCS ${plugin_SRCS} $<TARGET_OBJECTS:Fcitx5Qt5DBusAddons>)
endif()
add_library(fcitx5platforminputcontextplugin ${PLUGIN_LIBRARY_TYPE} ${plugin_SRCS})
set_target_properties(fcitx5platforminputcontextplugin PROPERTIES
AUTOMOC TRUE
)
target_include_directories(fcitx5platforminputcontextplugin PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/common")
if (BUILD_ONLY_PLUGIN AND BUILD_STATIC_PLUGIN)
target_compile_definitions(fcitx5platforminputcontextplugin PRIVATE "-DQT_STATICPLUGIN")
endif()
target_compile_definitions(fcitx5platforminputcontextplugin PRIVATE "-DFCITX_PLUGIN_DATA_FILE_PATH=\"${CMAKE_CURRENT_BINARY_DIR}/fcitx5.json\"")
if (WITH_FCITX_PLUGIN_NAME)
# This is not really necessary, but can trigger a cmake rebuild.
target_compile_definitions(fcitx5platforminputcontextplugin PRIVATE "-DFCITX5_QT_WITH_FCITX_NAME")
endif()
target_link_libraries(fcitx5platforminputcontextplugin
Qt5::Core
Qt5::Gui
Qt5::DBus
Qt5::Widgets
Fcitx5Qt5::DBusAddons
XKBCommon::XKBCommon
)
if (ENABLE_X11)
target_link_libraries(fcitx5platforminputcontextplugin XCB::XCB)
target_compile_definitions(fcitx5platforminputcontextplugin PRIVATE "-DENABLE_X11")
endif()
include(ECMQueryQmake)
query_qmake(_QT5PLUGINDIR QT_INSTALL_PLUGINS)
set(CMAKE_INSTALL_QT5PLUGINDIR ${_QT5PLUGINDIR} CACHE PATH "Qt5 plugin dir")
install(TARGETS fcitx5platforminputcontextplugin DESTINATION ${CMAKE_INSTALL_QT5PLUGINDIR}/platforminputcontexts)

View File

@@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2012~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitx4inputcontextproxy_p.h"
#include <QCoreApplication>
#include <QDBusConnectionInterface>
#include <QDBusInterface>
#include <QDBusMetaType>
#include <QFileInfo>
#include <QTimer>
namespace fcitx {
Fcitx4InputContextProxy::Fcitx4InputContextProxy(Fcitx4Watcher *watcher,
QObject *parent)
: QObject(parent),
d_ptr(new Fcitx4InputContextProxyPrivate(watcher, this)) {}
Fcitx4InputContextProxy::~Fcitx4InputContextProxy() { delete d_ptr; }
void Fcitx4InputContextProxy::setDisplay(const QString &display) {
Q_D(Fcitx4InputContextProxy);
d->display_ = display;
}
const QString &Fcitx4InputContextProxy::display() const {
Q_D(const Fcitx4InputContextProxy);
return d->display_;
}
bool Fcitx4InputContextProxy::isValid() const {
Q_D(const Fcitx4InputContextProxy);
return d->isValid();
}
QDBusPendingReply<> Fcitx4InputContextProxy::focusIn() {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->FocusIn();
}
QDBusPendingReply<> Fcitx4InputContextProxy::focusOut() {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->FocusOut();
}
QDBusPendingReply<int> Fcitx4InputContextProxy::processKeyEvent(
unsigned int keyval, unsigned int keycode, unsigned int state, int type,
unsigned int time) {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->ProcessKeyEvent(keyval, keycode, state, type, time);
}
QDBusPendingReply<> Fcitx4InputContextProxy::reset() {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->Reset();
}
QDBusPendingReply<> Fcitx4InputContextProxy::setCapability(unsigned int caps) {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->SetCapacity(caps);
}
QDBusPendingReply<> Fcitx4InputContextProxy::setCursorRect(int x, int y, int w,
int h) {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->SetCursorRect(x, y, w, h);
}
QDBusPendingReply<> Fcitx4InputContextProxy::setSurroundingText(
const QString &text, unsigned int cursor, unsigned int anchor) {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->SetSurroundingText(text, cursor, anchor);
}
QDBusPendingReply<>
Fcitx4InputContextProxy::setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
Q_D(Fcitx4InputContextProxy);
return d->icproxy_->SetSurroundingTextPosition(cursor, anchor);
}
} // namespace fcitx

View File

@@ -0,0 +1,67 @@
/*
* SPDX-FileCopyrightText: 2012~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _FCITX4INPUTCONTEXTPROXY_H_
#define _FCITX4INPUTCONTEXTPROXY_H_
#include "fcitxqtdbustypes.h"
#include <QDBusConnection>
#include <QDBusPendingReply>
#include <QDBusServiceWatcher>
#include <QObject>
class QDBusPendingCallWatcher;
namespace fcitx {
class Fcitx4Watcher;
class Fcitx4InputContextProxyPrivate;
class Fcitx4InputContextProxy : public QObject {
Q_OBJECT
public:
Fcitx4InputContextProxy(Fcitx4Watcher *watcher, QObject *parent);
~Fcitx4InputContextProxy();
bool isValid() const;
void setDisplay(const QString &display);
const QString &display() const;
public Q_SLOTS:
QDBusPendingReply<> focusIn();
QDBusPendingReply<> focusOut();
QDBusPendingReply<int> processKeyEvent(unsigned int keyval,
unsigned int keycode,
unsigned int state, int type,
unsigned int time);
QDBusPendingReply<> reset();
QDBusPendingReply<> setCapability(unsigned int caps);
QDBusPendingReply<> setCursorRect(int x, int y, int w, int h);
QDBusPendingReply<> setSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor);
QDBusPendingReply<> setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor);
Q_SIGNALS:
void commitString(const QString &str);
void currentIM(const QString &name, const QString &uniqueName,
const QString &langCode);
void deleteSurroundingText(int offset, unsigned int nchar);
void forwardKey(unsigned int keyval, unsigned int state, bool isRelease);
void updateFormattedPreedit(const FcitxQtFormattedPreeditList &str,
int cursorpos);
void inputContextCreated();
private:
Fcitx4InputContextProxyPrivate *const d_ptr;
Q_DECLARE_PRIVATE(Fcitx4InputContextProxy);
};
} // namespace fcitx
#endif // _FCITX4INPUTCONTEXTPROXY_H_

View File

@@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2012~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _FCITX4INPUTCONTEXTPROXY_P_H_
#define _FCITX4INPUTCONTEXTPROXY_P_H_
#include "fcitx4inputcontextproxy.h"
#include "fcitx4inputcontextproxyimpl.h"
#include "fcitx4inputmethodproxy.h"
#include "fcitx4watcher.h"
#include <QDBusServiceWatcher>
#include <cstddef>
#include <unistd.h>
namespace fcitx {
class Fcitx4InputContextProxyPrivate {
public:
Fcitx4InputContextProxyPrivate(Fcitx4Watcher *watcher,
Fcitx4InputContextProxy *q)
: q_ptr(q), fcitxWatcher_(watcher), watcher_(q) {
registerFcitxQtDBusTypes();
QObject::connect(fcitxWatcher_, &Fcitx4Watcher::availabilityChanged, q,
[this]() { availabilityChanged(); });
watcher_.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QObject::connect(&watcher_, &QDBusServiceWatcher::serviceUnregistered,
q, [this]() {
cleanUp();
availabilityChanged();
});
availabilityChanged();
}
~Fcitx4InputContextProxyPrivate() {
if (isValid()) {
icproxy_->DestroyIC();
}
cleanUp();
}
bool isValid() const { return (icproxy_ && icproxy_->isValid()); }
void availabilityChanged() {
QTimer::singleShot(100, q_ptr, [this]() { recheck(); });
}
void recheck() {
if (!isValid() && fcitxWatcher_->availability()) {
createInputContext();
}
if (!fcitxWatcher_->availability()) {
cleanUp();
}
}
void cleanUp() {
auto services = watcher_.watchedServices();
for (const auto &service : services) {
watcher_.removeWatchedService(service);
}
delete improxy_;
improxy_ = nullptr;
delete icproxy_;
icproxy_ = nullptr;
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
}
void createInputContext() {
Q_Q(Fcitx4InputContextProxy);
if (!fcitxWatcher_->availability()) {
return;
}
cleanUp();
auto service = fcitxWatcher_->service();
auto connection = fcitxWatcher_->connection();
auto owner = connection.interface()->serviceOwner(service);
if (!owner.isValid()) {
return;
}
watcher_.setConnection(connection);
watcher_.setWatchedServices(QStringList() << owner);
// Avoid race, query again.
if (!connection.interface()->isServiceRegistered(owner)) {
cleanUp();
return;
}
QFileInfo info(QCoreApplication::applicationFilePath());
improxy_ =
new Fcitx4InputMethodProxy(owner, "/inputmethod", connection, q);
auto result = improxy_->CreateICv3(info.fileName(), getpid());
createInputContextWatcher_ = new QDBusPendingCallWatcher(result);
QObject::connect(createInputContextWatcher_,
&QDBusPendingCallWatcher::finished, q,
[this]() { createInputContextFinished(); });
}
void createInputContextFinished() {
Q_Q(Fcitx4InputContextProxy);
if (createInputContextWatcher_->isError()) {
cleanUp();
return;
}
QDBusPendingReply<int, bool, unsigned int, unsigned int, unsigned int,
unsigned int>
reply(*createInputContextWatcher_);
QString path = QString("/inputcontext_%1").arg(reply.value());
icproxy_ = new Fcitx4InputContextProxyImpl(improxy_->service(), path,
improxy_->connection(), q);
QObject::connect(icproxy_, &Fcitx4InputContextProxyImpl::CommitString,
q, &Fcitx4InputContextProxy::commitString);
QObject::connect(icproxy_, &Fcitx4InputContextProxyImpl::CurrentIM, q,
&Fcitx4InputContextProxy::currentIM);
QObject::connect(icproxy_,
&Fcitx4InputContextProxyImpl::DeleteSurroundingText, q,
&Fcitx4InputContextProxy::deleteSurroundingText);
QObject::connect(icproxy_, &Fcitx4InputContextProxyImpl::ForwardKey, q,
&Fcitx4InputContextProxy::forwardKey);
QObject::connect(icproxy_,
&Fcitx4InputContextProxyImpl::UpdateFormattedPreedit,
q, &Fcitx4InputContextProxy::updateFormattedPreedit);
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
Q_EMIT q->inputContextCreated();
}
Fcitx4InputContextProxy *q_ptr;
Q_DECLARE_PUBLIC(Fcitx4InputContextProxy);
Fcitx4Watcher *fcitxWatcher_;
QDBusServiceWatcher watcher_;
Fcitx4InputMethodProxy *improxy_ = nullptr;
Fcitx4InputContextProxyImpl *icproxy_ = nullptr;
QDBusPendingCallWatcher *createInputContextWatcher_ = nullptr;
QString display_;
};
} // namespace fcitx
#endif // _FCITX4INPUTCONTEXTPROXY_P_H_

View File

@@ -0,0 +1,30 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitx4inputcontextproxyimpl -c
* Fcitx4InputContextProxy org.fcitx.Fcitx.InputContext.xml
* org.fcitx.Fcitx.InputContext
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitx4inputcontextproxyimpl.h"
namespace fcitx {
/*
* Implementation of interface class Fcitx4InputContextProxy
*/
Fcitx4InputContextProxyImpl::Fcitx4InputContextProxyImpl(
const QString &service, const QString &path,
const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection,
parent) {}
Fcitx4InputContextProxyImpl::~Fcitx4InputContextProxyImpl() {}
} // namespace fcitx

View File

@@ -0,0 +1,126 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitx4inputcontextproxyimpl -c
* Fcitx4InputContextProxyImpl org.fcitx.Fcitx.InputContext.xml
* org.fcitx.Fcitx.InputContext
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITX4INPUTCONTEXTPROXYIMPL_H
#define FCITX4INPUTCONTEXTPROXYIMPL_H
#include "fcitxqtdbustypes.h"
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.InputContext
*/
class Fcitx4InputContextProxyImpl : public QDBusAbstractInterface {
Q_OBJECT
public:
static inline const char *staticInterfaceName() {
return "org.fcitx.Fcitx.InputContext";
}
public:
Fcitx4InputContextProxyImpl(const QString &service, const QString &path,
const QDBusConnection &connection,
QObject *parent = nullptr);
~Fcitx4InputContextProxyImpl();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> DestroyIC() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("DestroyIC"),
argumentList);
}
inline QDBusPendingReply<> FocusIn() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("FocusIn"),
argumentList);
}
inline QDBusPendingReply<> FocusOut() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("FocusOut"),
argumentList);
}
inline QDBusPendingReply<int> ProcessKeyEvent(unsigned int keyval,
unsigned int keycode,
unsigned int state, int type,
unsigned int time) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(keyval)
<< QVariant::fromValue(keycode)
<< QVariant::fromValue(state) << QVariant::fromValue(type)
<< QVariant::fromValue(time);
return asyncCallWithArgumentList(QStringLiteral("ProcessKeyEvent"),
argumentList);
}
inline QDBusPendingReply<> Reset() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Reset"), argumentList);
}
inline QDBusPendingReply<> SetCapacity(unsigned int caps) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
return asyncCallWithArgumentList(QStringLiteral("SetCapacity"),
argumentList);
}
inline QDBusPendingReply<> SetCursorRect(int x, int y, int w, int h) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y)
<< QVariant::fromValue(w) << QVariant::fromValue(h);
return asyncCallWithArgumentList(QStringLiteral("SetCursorRect"),
argumentList);
}
inline QDBusPendingReply<> SetSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(text) << QVariant::fromValue(cursor)
<< QVariant::fromValue(anchor);
return asyncCallWithArgumentList(QStringLiteral("SetSurroundingText"),
argumentList);
}
inline QDBusPendingReply<> SetSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(cursor)
<< QVariant::fromValue(anchor);
return asyncCallWithArgumentList(
QStringLiteral("SetSurroundingTextPosition"), argumentList);
}
Q_SIGNALS: // SIGNALS
void CommitString(const QString &str);
void CurrentIM(const QString &name, const QString &uniqueName,
const QString &langCode);
void DeleteSurroundingText(int offset, unsigned int nchar);
void ForwardKey(unsigned int keyval, unsigned int state, int type);
void UpdateFormattedPreedit(FcitxQtFormattedPreeditList str, int cursorpos);
};
} // namespace fcitx
#endif

View File

@@ -0,0 +1,29 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitx4inputmethodproxy -c
* Fcitx4InputMethodProxy org.fcitx.Fcitx.InputMethod.xml
* org.fcitx.Fcitx.InputMethod
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitx4inputmethodproxy.h"
namespace fcitx {
/*
* Implementation of interface class Fcitx4InputMethodProxy
*/
Fcitx4InputMethodProxy::Fcitx4InputMethodProxy(
const QString &service, const QString &path,
const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection,
parent) {}
Fcitx4InputMethodProxy::~Fcitx4InputMethodProxy() {}
} // namespace fcitx

View File

@@ -0,0 +1,80 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitx4inputmethodproxy -c
* Fcitx4InputMethodProxy org.fcitx.Fcitx.InputMethod.xml
* org.fcitx.Fcitx.InputMethod
*
* qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITX4INPUTMETHODPROXY_H
#define FCITX4INPUTMETHODPROXY_H
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.InputMethod
*/
class Fcitx4InputMethodProxy : public QDBusAbstractInterface {
Q_OBJECT
public:
static inline const char *staticInterfaceName() {
return "org.fcitx.Fcitx.InputMethod";
}
public:
Fcitx4InputMethodProxy(const QString &service, const QString &path,
const QDBusConnection &connection,
QObject *parent = nullptr);
~Fcitx4InputMethodProxy();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<int, bool, unsigned int, unsigned int,
unsigned int, unsigned int>
CreateICv3(const QString &appname, int pid) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(appname)
<< QVariant::fromValue(pid);
return asyncCallWithArgumentList(QStringLiteral("CreateICv3"),
argumentList);
}
inline QDBusReply<int> CreateICv3(const QString &appname, int pid,
bool &enable, unsigned int &keyval1,
unsigned int &state1,
unsigned int &keyval2,
unsigned int &state2) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(appname)
<< QVariant::fromValue(pid);
QDBusMessage reply = callWithArgumentList(
QDBus::Block, QStringLiteral("CreateICv3"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage &&
reply.arguments().count() == 6) {
enable = qdbus_cast<bool>(reply.arguments().at(1));
keyval1 = qdbus_cast<unsigned int>(reply.arguments().at(2));
state1 = qdbus_cast<unsigned int>(reply.arguments().at(3));
keyval2 = qdbus_cast<unsigned int>(reply.arguments().at(4));
state2 = qdbus_cast<unsigned int>(reply.arguments().at(5));
}
return reply;
}
Q_SIGNALS: // SIGNALS
};
} // namespace fcitx
#endif

View File

@@ -0,0 +1,267 @@
/*
* SPDX-FileCopyrightText: 2011~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitx4watcher.h"
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusServiceWatcher>
#include <QDebug>
#include <QDir>
#include <QFileSystemWatcher>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
// utils function in fcitx-utils and fcitx-config
bool _pid_exists(pid_t pid) {
if (pid <= 0)
return 0;
return !(kill(pid, 0) && (errno == ESRCH));
}
int displayNumber() {
QByteArray display(qgetenv("DISPLAY"));
QByteArray displayNumber("0");
int pos = display.indexOf(':');
if (pos >= 0) {
++pos;
int pos2 = display.indexOf('.', pos);
if (pos2 > 0) {
displayNumber = display.mid(pos, pos2 - pos);
} else {
displayNumber = display.mid(pos);
}
}
bool ok;
int d = displayNumber.toInt(&ok);
if (ok) {
return d;
}
return 0;
}
QString socketFile() {
QString filename =
QString("%1-%2")
.arg(QString::fromLatin1(QDBusConnection::localMachineId()))
.arg(displayNumber());
QString home = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME"));
if (home.isEmpty()) {
home = QDir::homePath().append(QLatin1String("/.config"));
}
return QString("%1/fcitx/dbus/%2").arg(home).arg(filename);
}
namespace fcitx {
QString newUniqueConnectionName() {
static int idx = 0;
const auto newIdx = idx++;
return QString("_fcitx4_%1").arg(newIdx);
}
Fcitx4Watcher::Fcitx4Watcher(QDBusConnection sessionBus, QObject *parent)
: QObject(parent), connection_(nullptr), sessionBus_(sessionBus),
socketFile_(socketFile()),
serviceName_(QString("org.fcitx.Fcitx-%1").arg(displayNumber())),
availability_(false), uniqueConnectionName_(newUniqueConnectionName()) {}
Fcitx4Watcher::~Fcitx4Watcher() {
cleanUpConnection();
unwatchSocketFile();
}
bool Fcitx4Watcher::availability() const { return availability_; }
QDBusConnection Fcitx4Watcher::connection() const {
if (connection_) {
return *connection_;
}
return sessionBus_;
}
QString Fcitx4Watcher::service() const {
if (connection_) {
return serviceName_;
}
if (mainPresent_) {
return serviceName_;
}
return QString();
}
void Fcitx4Watcher::setAvailability(bool availability) {
if (availability_ != availability) {
availability_ = availability;
Q_EMIT availabilityChanged(availability_);
}
}
void Fcitx4Watcher::watch() {
if (watched_) {
return;
}
serviceWatcher_ = new QDBusServiceWatcher(this);
connect(serviceWatcher_, &QDBusServiceWatcher::serviceOwnerChanged, this,
&Fcitx4Watcher::imChanged);
serviceWatcher_->setConnection(sessionBus_);
serviceWatcher_->addWatchedService(serviceName_);
if (sessionBus_.interface()->isServiceRegistered(serviceName_)) {
mainPresent_ = true;
}
watchSocketFile();
createConnection();
updateAvailability();
watched_ = true;
}
void Fcitx4Watcher::unwatch() {
if (!watched_) {
return;
}
delete serviceWatcher_;
serviceWatcher_ = nullptr;
unwatchSocketFile();
cleanUpConnection();
mainPresent_ = false;
watched_ = false;
updateAvailability();
}
QString Fcitx4Watcher::address() {
QString addr;
QByteArray addrVar = qgetenv("FCITX_DBUS_ADDRESS");
if (!addrVar.isNull())
return QString::fromLocal8Bit(addrVar);
QFile file(socketFile_);
if (!file.open(QIODevice::ReadOnly))
return QString();
const int BUFSIZE = 1024;
char buffer[BUFSIZE];
size_t sz = file.read(buffer, BUFSIZE);
file.close();
if (sz == 0)
return QString();
char *p = buffer;
while (*p)
p++;
size_t addrlen = p - buffer;
if (sz != addrlen + 2 * sizeof(pid_t) + 1)
return QString();
/* skip '\0' */
p++;
pid_t *ppid = (pid_t *)p;
pid_t daemonpid = ppid[0];
pid_t fcitxpid = ppid[1];
if (!_pid_exists(daemonpid) || !_pid_exists(fcitxpid))
return QString();
addr = QLatin1String(buffer);
return addr;
}
void Fcitx4Watcher::cleanUpConnection() {
QDBusConnection::disconnectFromBus(uniqueConnectionName_);
delete connection_;
connection_ = nullptr;
}
void Fcitx4Watcher::socketFileChanged() {
cleanUpConnection();
createConnection();
}
void Fcitx4Watcher::createConnection() {
QString addr = address();
if (!addr.isNull()) {
QDBusConnection connection(
QDBusConnection::connectToBus(addr, uniqueConnectionName_));
if (connection.isConnected()) {
connection_ = new QDBusConnection(connection);
} else {
QDBusConnection::disconnectFromBus(uniqueConnectionName_);
}
}
if (connection_) {
connection_->connect("org.freedesktop.DBus.Local",
"/org/freedesktop/DBus/Local",
"org.freedesktop.DBus.Local", "Disconnected", this,
SLOT(dbusDisconnected()));
unwatchSocketFile();
}
updateAvailability();
}
void Fcitx4Watcher::dbusDisconnected() {
cleanUpConnection();
watchSocketFile();
// Try recreation immediately to avoid race.
createConnection();
}
void Fcitx4Watcher::watchSocketFile() {
if (socketFile_.isEmpty()) {
return;
}
QFileInfo info(socketFile_);
QDir dir(info.path());
if (!dir.exists()) {
QDir rt(QDir::root());
rt.mkpath(info.path());
}
fsWatcher_ = new QFileSystemWatcher(this);
fsWatcher_->addPath(info.path());
if (info.exists()) {
fsWatcher_->addPath(info.filePath());
}
connect(fsWatcher_, &QFileSystemWatcher::fileChanged, this,
&Fcitx4Watcher::socketFileChanged);
connect(fsWatcher_, &QFileSystemWatcher::directoryChanged, this,
&Fcitx4Watcher::socketFileChanged);
}
void Fcitx4Watcher::unwatchSocketFile() {
if (fsWatcher_) {
fsWatcher_->disconnect(this);
fsWatcher_->deleteLater();
fsWatcher_ = nullptr;
}
}
void Fcitx4Watcher::imChanged(const QString &service, const QString &,
const QString &newOwner) {
if (service == serviceName_) {
if (!newOwner.isEmpty()) {
mainPresent_ = true;
} else {
mainPresent_ = false;
}
}
updateAvailability();
}
void Fcitx4Watcher::updateAvailability() {
setAvailability(mainPresent_ || connection_);
}
} // namespace fcitx

View File

@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2011~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef FCITXWATCHER_H_
#define FCITXWATCHER_H_
#include <QDBusConnection>
#include <QObject>
class QFileSystemWatcher;
class QDBusServiceWatcher;
namespace fcitx {
// A FcitxQtConnection replacement, to implement compatibility with fcitx 5.
// Since we have three thing to monitor, the situation becomes much more
// complexer.
class Fcitx4Watcher : public QObject {
Q_OBJECT
public:
explicit Fcitx4Watcher(QDBusConnection sessionBus,
QObject *parent = nullptr);
~Fcitx4Watcher();
void watch();
void unwatch();
bool availability() const;
QDBusConnection connection() const;
QString service() const;
Q_SIGNALS:
void availabilityChanged(bool);
private Q_SLOTS:
void dbusDisconnected();
void socketFileChanged();
void imChanged(const QString &service, const QString &oldOwner,
const QString &newOwner);
private:
QString address();
void watchSocketFile();
void unwatchSocketFile();
void createConnection();
void cleanUpConnection();
void setAvailability(bool availability);
void updateAvailability();
QFileSystemWatcher *fsWatcher_ = nullptr;
QDBusServiceWatcher *serviceWatcher_ = nullptr;
QDBusConnection *connection_;
QDBusConnection sessionBus_;
QString socketFile_;
QString serviceName_;
bool availability_ = false;
bool mainPresent_ = false;
bool watched_ = false;
QString uniqueConnectionName_;
};
} // namespace fcitx
#endif // FCITXWATCHER_H_

View File

@@ -0,0 +1,6 @@
{
"Keys": [
@FCITX5_QT_EXTRA_PLUGIN_NAME@
"fcitx5"
]
}

View File

@@ -0,0 +1,791 @@
/*
* SPDX-FileCopyrightText: 2021~2021 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitxcandidatewindow.h"
#include "fcitxflags.h"
#include "fcitxtheme.h"
#include "qfcitxplatforminputcontext.h"
#include <QDebug>
#include <QExposeEvent>
#include <QFont>
#include <QGuiApplication>
#include <QMouseEvent>
#include <QPalette>
#include <QResizeEvent>
#include <QScreen>
#include <QTextLayout>
#include <QVariant>
#include <QtMath>
#include <utility>
#if defined(FCITX_ENABLE_QT6_WAYLAND_WORKAROUND) && \
QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtWaylandClient/private/qwayland-xdg-shell.h>
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandintegration_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/wayland-xdg-shell-client-protocol.h>
#include <qpa/qplatformnativeinterface.h>
#endif
namespace fcitx {
namespace {
#if defined(FCITX_ENABLE_QT6_WAYLAND_WORKAROUND) && \
QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
class XdgWmBase : public QtWayland::xdg_wm_base {
public:
using xdg_wm_base::xdg_wm_base;
protected:
// This is required for all xdg_wm_base bind.
void xdg_wm_base_ping(uint32_t serial) override { pong(serial); }
};
#endif
void doLayout(QTextLayout &layout) {
QFontMetrics fontMetrics(layout.font());
auto minH = fontMetrics.ascent() + fontMetrics.descent();
layout.setCacheEnabled(true);
layout.beginLayout();
int height = 0;
while (1) {
QTextLine line = layout.createLine();
if (!line.isValid())
break;
line.setLineWidth(INT_MAX);
line.setLeadingIncluded(true);
line.setPosition(
QPoint(0, height - line.ascent() + fontMetrics.ascent()));
height += minH;
}
layout.endLayout();
}
} // namespace
class MultilineText {
public:
MultilineText(const QFont &font, const QString &text) {
QStringList lines = text.split("\n");
int width = 0;
QFontMetrics fontMetrics(font);
fontHeight_ = fontMetrics.ascent() + fontMetrics.descent();
for (const auto &line : lines) {
layouts_.emplace_back(std::make_unique<QTextLayout>(line));
layouts_.back()->setFont(font);
doLayout(*layouts_.back());
width = std::max(width,
layouts_.back()->boundingRect().toRect().width());
}
boundingRect_.setTopLeft(QPoint(0, 0));
boundingRect_.setSize(QSize(width, lines.size() * fontHeight_));
}
bool isEmpty() const { return layouts_.empty(); }
void draw(QPainter *painter, QColor color, QPoint position) {
painter->save();
painter->setPen(color);
int currentY = 0;
for (const auto &layout : layouts_) {
layout->draw(painter, position + QPoint(0, currentY));
currentY += fontHeight_;
}
painter->restore();
}
QRect boundingRect() { return boundingRect_; }
private:
std::vector<std::unique_ptr<QTextLayout>> layouts_;
int fontHeight_;
QRect boundingRect_;
};
FcitxCandidateWindow::FcitxCandidateWindow(QWindow *window,
QFcitxPlatformInputContext *context)
: QRasterWindow(), context_(context), theme_(context->theme()),
parent_(window) {
constexpr Qt::WindowFlags commonFlags = Qt::FramelessWindowHint |
Qt::WindowDoesNotAcceptFocus |
Qt::NoDropShadowWindowHint;
if (isWayland_) {
// Qt::ToolTip ensures wayland doesn't grab focus.
// Not using Qt::BypassWindowManagerHint ensures wayland handle
// fractional scale.
setFlags(Qt::ToolTip | commonFlags);
#if defined(FCITX_ENABLE_QT6_WAYLAND_WORKAROUND) && \
QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
if (auto instance = QtWaylandClient::QWaylandIntegration::instance()) {
for (QtWaylandClient::QWaylandDisplay::RegistryGlobal global :
instance->display()->globals()) {
if (global.interface == QLatin1String("xdg_wm_base")) {
xdgWmBase_.reset(
new XdgWmBase(instance->display()->wl_registry(),
global.id, global.version));
break;
}
}
}
setProperty("_q_waylandPopupAnchor",
QVariant::fromValue(Qt::BottomEdge | Qt::LeftEdge));
setProperty("_q_waylandPopupGravity",
QVariant::fromValue(Qt::BottomEdge | Qt::RightEdge));
setProperty(
"_q_waylandPopupConstraintAdjustment",
static_cast<unsigned int>(
QtWayland::xdg_positioner::constraint_adjustment_slide_x |
QtWayland::xdg_positioner::constraint_adjustment_flip_y));
#endif
} else {
// Qt::Popup ensures X11 doesn't apply tooltip animation under kwin.
setFlags(Qt::Popup | Qt::BypassWindowManagerHint | commonFlags);
}
if (isWayland_) {
setTransientParent(parent_);
}
QSurfaceFormat surfaceFormat = format();
surfaceFormat.setAlphaBufferSize(8);
setFormat(surfaceFormat);
connect(this, &QWindow::visibleChanged, this, [this] { hoverIndex_ = -1; });
}
FcitxCandidateWindow::~FcitxCandidateWindow() {}
bool FcitxCandidateWindow::event(QEvent *event) {
if (event->type() == QEvent::Leave) {
auto oldHighlight = highlight();
hoverIndex_ = -1;
if (highlight() != oldHighlight) {
update();
}
}
return QRasterWindow::event(event);
}
void FcitxCandidateWindow::render(QPainter *painter) {
theme_->paint(painter, theme_->background(),
QRect(QPoint(0, 0), actualSize_));
auto contentMargin = theme_->contentMargin();
const QPoint topLeft(contentMargin.left(), contentMargin.top());
painter->setPen(theme_->normalColor());
auto minH =
theme_->fontMetrics().ascent() + theme_->fontMetrics().descent();
auto textMargin = theme_->textMargin();
auto extraW = textMargin.left() + textMargin.right();
auto extraH = textMargin.top() + textMargin.bottom();
size_t currentHeight = 0;
if (!upperLayout_.text().isEmpty()) {
upperLayout_.draw(
painter, topLeft + QPoint(textMargin.left(), textMargin.top()));
// Draw cursor
currentHeight += minH + extraH;
if (cursor_ >= 0) {
auto line = upperLayout_.lineForTextPosition(cursor_);
if (line.isValid()) {
int cursorX = line.cursorToX(cursor_);
line.lineNumber();
painter->save();
QPen pen = painter->pen();
pen.setWidth(2);
painter->setPen(pen);
QPoint start = topLeft + QPoint(textMargin.left() + cursorX + 1,
textMargin.top() +
line.lineNumber() * minH);
painter->drawLine(start, start + QPoint(0, minH));
painter->restore();
}
}
}
if (!lowerLayout_.text().isEmpty()) {
lowerLayout_.draw(painter,
topLeft + QPoint(textMargin.left(),
textMargin.top() + currentHeight));
currentHeight += minH + extraH;
}
bool vertical = theme_->vertical();
if (layoutHint_ == FcitxCandidateLayoutHint::Vertical) {
vertical = true;
} else if (layoutHint_ == FcitxCandidateLayoutHint::Horizontal) {
vertical = false;
}
candidateRegions_.clear();
candidateRegions_.reserve(labelLayouts_.size());
size_t wholeW = 0, wholeH = 0;
// size of text = textMargin + actual text size.
// HighLight = HighLight margin + TEXT.
// Click region = HighLight - click
for (size_t i = 0; i < labelLayouts_.size(); i++) {
int x, y;
if (vertical) {
x = 0;
y = currentHeight + wholeH;
} else {
x = wholeW;
y = currentHeight;
}
x += textMargin.left();
y += textMargin.top();
int labelW = 0, labelH = 0, candidateW = 0, candidateH = 0;
if (!labelLayouts_[i]->isEmpty()) {
auto size = labelLayouts_[i]->boundingRect();
labelW = size.width();
labelH = size.height();
}
if (!candidateLayouts_[i]->isEmpty()) {
auto size = candidateLayouts_[i]->boundingRect();
candidateW = size.width();
candidateH = size.height();
}
int vheight;
if (vertical) {
vheight = std::max({minH, labelH, candidateH});
wholeH += vheight + extraH;
} else {
vheight = candidatesHeight_ - extraH;
wholeW += candidateW + labelW + extraW;
}
QMargins highlightMargin = theme_->highlightMargin();
QMargins clickMargin = theme_->highlightClickMargin();
auto highlightWidth = labelW + candidateW;
bool fullWidthHighlight = true;
if (fullWidthHighlight && vertical) {
// Last candidate, fill.
highlightWidth = actualSize_.width() - contentMargin.left() -
contentMargin.right() - textMargin.left() -
textMargin.right();
}
const int highlightIndex = highlight();
QColor color = theme_->normalColor();
if (highlightIndex >= 0 && i == static_cast<size_t>(highlightIndex)) {
// Paint highlight
theme_->paint(
painter, theme_->highlight(),
QRect(topLeft + QPoint(x, y) -
QPoint(highlightMargin.left(), highlightMargin.top()),
QSize(highlightWidth + highlightMargin.left() +
highlightMargin.right(),
vheight + highlightMargin.top() +
highlightMargin.bottom())));
color = theme_->highlightCandidateColor();
}
QRect candidateRegion(
topLeft + QPoint(x, y) -
QPoint(highlightMargin.left(), highlightMargin.right()) +
QPoint(clickMargin.left(), clickMargin.right()),
QSize(highlightWidth + highlightMargin.left() +
highlightMargin.right() - clickMargin.left() -
clickMargin.right(),
vheight + highlightMargin.top() + highlightMargin.bottom() -
clickMargin.top() - clickMargin.bottom()));
candidateRegions_.push_back(candidateRegion);
if (!labelLayouts_[i]->isEmpty()) {
labelLayouts_[i]->draw(painter, color, topLeft + QPoint(x, y));
}
if (!candidateLayouts_[i]->isEmpty()) {
candidateLayouts_[i]->draw(painter, color,
topLeft + QPoint(x + labelW, y));
}
}
prevRegion_ = QRect();
nextRegion_ = QRect();
if (labelLayouts_.size() && (hasPrev_ || hasNext_)) {
if (theme_->prev().valid() && theme_->next().valid()) {
int prevY = 0, nextY = 0;
if (theme_->buttonAlignment() == "Top") {
prevY = contentMargin.top();
nextY = contentMargin.top();
} else if (theme_->buttonAlignment() == "First Candidate") {
prevY = candidateRegions_.front().top() +
(candidateRegions_.front().height() -
theme_->prev().height()) /
2.0;
nextY = candidateRegions_.front().top() +
(candidateRegions_.front().height() -
theme_->next().height()) /
2.0;
} else if (theme_->buttonAlignment() == "Center") {
prevY = contentMargin.top() +
(actualSize_.height() - contentMargin.top() -
contentMargin.bottom() - theme_->prev().height()) /
2.0;
nextY = contentMargin.top() +
(actualSize_.height() - contentMargin.top() -
contentMargin.bottom() - theme_->next().height()) /
2.0;
} else if (theme_->buttonAlignment() == "Last Candidate") {
prevY = candidateRegions_.back().top() +
(candidateRegions_.back().height() -
theme_->prev().height()) /
2.0;
nextY = candidateRegions_.back().top() +
(candidateRegions_.back().height() -
theme_->next().height()) /
2.0;
} else {
prevY = actualSize_.height() - contentMargin.bottom() -
theme_->prev().height();
nextY = actualSize_.height() - contentMargin.bottom() -
theme_->next().height();
}
nextRegion_ =
QRect(QPoint(actualSize_.width() - contentMargin.right() -
theme_->prev().width(),
nextY),
theme_->next().size());
double alpha = 1.0;
if (!hasNext_) {
alpha = 0.3;
} else if (nextHovered_) {
alpha = 0.7;
}
theme_->paint(painter, theme_->next(), nextRegion_.topLeft(),
alpha);
nextRegion_ = nextRegion_.marginsRemoved(theme_->next().margin());
prevRegion_ = QRect(
QPoint(actualSize_.width() - contentMargin.right() -
theme_->next().width() - theme_->prev().width(),
prevY),
theme_->prev().size());
alpha = 1.0;
if (!hasPrev_) {
alpha = 0.3;
} else if (prevHovered_) {
alpha = 0.7;
}
theme_->paint(painter, theme_->prev(), prevRegion_.topLeft(),
alpha);
prevRegion_ = prevRegion_.marginsRemoved(theme_->prev().margin());
}
}
}
void UpdateLayout(QTextLayout &layout, const FcitxTheme &theme,
std::initializer_list<
std::reference_wrapper<const FcitxQtFormattedPreeditList>>
texts) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
layout.clearFormats();
#endif
layout.setFont(theme.font());
QVector<QTextLayout::FormatRange> formats;
QString str;
int pos = 0;
for (const auto &text : texts) {
for (const auto &preedit : text.get()) {
str += preedit.string();
QTextCharFormat format;
if (preedit.format() & FcitxTextFormatFlag_Underline) {
format.setUnderlineStyle(QTextCharFormat::DashUnderline);
}
if (preedit.format() & FcitxTextFormatFlag_Strike) {
format.setFontStrikeOut(true);
}
if (preedit.format() & FcitxTextFormatFlag_Bold) {
format.setFontWeight(QFont::Bold);
}
if (preedit.format() & FcitxTextFormatFlag_Italic) {
format.setFontItalic(true);
}
if (preedit.format() & FcitxTextFormatFlag_HighLight) {
format.setBackground(theme.highlightBackgroundColor());
format.setForeground(theme.highlightColor());
}
formats.append(QTextLayout::FormatRange{
pos, static_cast<int>(preedit.string().length()), format});
pos += preedit.string().length();
}
}
layout.setText(str);
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
layout.setFormats(formats);
#endif
}
void FcitxCandidateWindow::updateClientSideUI(
const FcitxQtFormattedPreeditList &preedit, int cursorpos,
const FcitxQtFormattedPreeditList &auxUp,
const FcitxQtFormattedPreeditList &auxDown,
const FcitxQtStringKeyValueList &candidates, int candidateIndex,
int layoutHint, bool hasPrev, bool hasNext) {
bool preeditVisible = !preedit.isEmpty();
bool auxUpVisbile = !auxUp.isEmpty();
bool auxDownVisible = !auxDown.isEmpty();
bool candidatesVisible = !candidates.isEmpty();
bool visible =
preeditVisible || auxUpVisbile || auxDownVisible || candidatesVisible;
auto window = context_->focusWindowWrapper();
if (!theme_ || !visible || !window || window != parent_) {
hide();
return;
}
UpdateLayout(upperLayout_, *theme_, {auxUp, preedit});
if (cursorpos >= 0) {
int auxUpLength = 0;
for (const auto &auxUpText : auxUp) {
auxUpLength += auxUpText.string().length();
}
// Get the preedit part
auto preeditString = upperLayout_.text().mid(auxUpLength).toUtf8();
preeditString = preeditString.mid(0, cursorpos);
cursor_ = auxUpLength + QString::fromUtf8(preeditString).length();
} else {
cursor_ = -1;
}
doLayout(upperLayout_);
UpdateLayout(lowerLayout_, *theme_, {auxDown});
doLayout(lowerLayout_);
labelLayouts_.clear();
candidateLayouts_.clear();
for (int i = 0; i < candidates.size(); i++) {
labelLayouts_.emplace_back(std::make_unique<MultilineText>(
theme_->font(), candidates[i].key()));
candidateLayouts_.emplace_back(std::make_unique<MultilineText>(
theme_->font(), candidates[i].value()));
}
highlight_ = candidateIndex;
hasPrev_ = hasPrev;
hasNext_ = hasNext;
layoutHint_ = static_cast<FcitxCandidateLayoutHint>(layoutHint);
actualSize_ = sizeHint();
if (actualSize_.width() <= 0 || actualSize_.height() <= 0) {
hide();
return;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QSize sizeWithoutShadow = actualSize_.shrunkBy(theme_->shadowMargin());
#else
QSize sizeWithoutShadow =
actualSize_ -
QSize(theme_->shadowMargin().left() + theme_->shadowMargin().right(),
theme_->shadowMargin().top() + theme_->shadowMargin().bottom());
#endif
if (sizeWithoutShadow.width() < 0) {
sizeWithoutShadow.setWidth(0);
}
if (sizeWithoutShadow.height() < 0) {
sizeWithoutShadow.setHeight(0);
}
if (size() != actualSize_) {
resize(actualSize_);
}
update();
QRect cursorRect = context_->cursorRectangleWrapper();
QRect screenGeometry;
#if defined(FCITX_ENABLE_QT6_WAYLAND_WORKAROUND) && \
QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
if (isWayland_) {
auto *waylandWindow =
static_cast<QtWaylandClient::QWaylandWindow *>(window->handle());
const auto windowMargins = waylandWindow->windowContentMargins() -
waylandWindow->clientSideMargins();
auto windowGeometry = waylandWindow->windowContentGeometry();
if (!cursorRect.isValid()) {
if (cursorRect.width() <= 0) {
cursorRect.setWidth(1);
}
if (cursorRect.height() <= 0) {
cursorRect.setHeight(1);
}
}
QRect nativeCursorRect = QHighDpi::toNativePixels(cursorRect, this);
// valid the anchor rect.
if (!nativeCursorRect.intersects(windowGeometry)) {
if (nativeCursorRect.right() < windowGeometry.left()) {
nativeCursorRect.setLeft(windowGeometry.left());
nativeCursorRect.setWidth(1);
}
if (nativeCursorRect.left() > windowGeometry.right()) {
nativeCursorRect.setLeft(windowGeometry.right());
nativeCursorRect.setWidth(1);
}
if (nativeCursorRect.bottom() < windowGeometry.top()) {
nativeCursorRect.setTop(windowGeometry.top());
nativeCursorRect.setHeight(1);
}
if (nativeCursorRect.top() > windowGeometry.bottom()) {
nativeCursorRect.setTop(windowGeometry.bottom());
nativeCursorRect.setHeight(1);
}
}
bool wasVisible = isVisible();
bool cursorRectChanged = false;
if (property("_q_waylandPopupAnchorRect") != nativeCursorRect) {
cursorRectChanged = true;
setProperty("_q_waylandPopupAnchorRect", nativeCursorRect);
}
// This try to ensure xdg_popup is available.
show();
xdg_popup *xdgPopup = static_cast<xdg_popup *>(
QGuiApplication::platformNativeInterface()->nativeResourceForWindow(
"xdg_popup", this));
if (xdgWmBase_ && xdgPopup &&
xdg_popup_get_version(xdgPopup) >=
XDG_POPUP_REPOSITION_SINCE_VERSION) {
nativeCursorRect.translate(-windowMargins.left(),
-windowMargins.top());
auto *positioner =
new QtWayland::xdg_positioner(xdgWmBase_->create_positioner());
positioner->set_anchor_rect(
nativeCursorRect.x(), nativeCursorRect.y(),
nativeCursorRect.width(), nativeCursorRect.height());
positioner->set_anchor(
QtWayland::xdg_positioner::anchor_bottom_left);
positioner->set_gravity(
QtWayland::xdg_positioner::gravity_bottom_right);
auto *waylandCandidateWindow =
static_cast<QtWaylandClient::QWaylandWindow *>(handle());
QRect nativeGeometry =
waylandCandidateWindow->windowContentGeometry();
positioner->set_size(nativeGeometry.width(),
nativeGeometry.height());
positioner->set_reactive();
positioner->set_constraint_adjustment(
QtWayland::xdg_positioner::constraint_adjustment_slide_x |
QtWayland::xdg_positioner::constraint_adjustment_flip_y);
xdg_popup_reposition(xdgPopup, positioner->object(),
repositionToken_++);
positioner->destroy();
return;
}
// Check if we need remap.
// If it was invisible, nothing need to be done.
// If cursor rect changed, the window must be remapped.
// If adjustment is already happening (flip/slide), then remap.
// If we predict adjustment may be happening, then remap.
const auto predictGeometry =
QRect(QPoint(cursorRect.x(), cursorRect.y() + cursorRect.height()),
actualSize_);
if (wasVisible &&
(cursorRectChanged || position() != predictGeometry.topLeft() ||
!windowGeometry.contains(predictGeometry))) {
hide();
show();
}
return;
}
#endif
// Try to apply the screen edge detection over the window, because if we
// intent to use this with wayland. It we have no information above screen
// edge.
if (isWayland_) {
screenGeometry = window->frameGeometry();
cursorRect.translate(window->framePosition());
auto margins = window->frameMargins();
cursorRect.translate(margins.left(), margins.top());
} else {
screenGeometry = window->screen()->geometry();
auto pos = window->mapToGlobal(cursorRect.topLeft());
cursorRect.moveTo(pos);
}
int x = cursorRect.left();
int y = cursorRect.bottom();
if (cursorRect.left() + sizeWithoutShadow.width() >
screenGeometry.right()) {
x = screenGeometry.right() - sizeWithoutShadow.width() + 1;
}
if (x < screenGeometry.left()) {
x = screenGeometry.left();
}
if (y + sizeWithoutShadow.height() > screenGeometry.bottom()) {
if (y > screenGeometry.bottom()) {
y = screenGeometry.bottom() - sizeWithoutShadow.height() - 40;
} else { /* better position the window */
y = y - sizeWithoutShadow.height() -
((cursorRect.height() == 0) ? 40 : cursorRect.height());
}
}
if (y < screenGeometry.top()) {
y = screenGeometry.top();
}
QPoint newPosition(x, y);
newPosition -=
QPoint(theme_->shadowMargin().left(), theme_->shadowMargin().top());
if (newPosition != position()) {
if (isWayland_ && isVisible()) {
hide();
}
setPosition(newPosition);
}
show();
}
void FcitxCandidateWindow::mouseMoveEvent(QMouseEvent *event) {
bool needRepaint = false;
bool prevHovered = false;
bool nextHovered = false;
auto oldHighlight = highlight();
hoverIndex_ = -1;
prevHovered = prevRegion_.contains(event->pos());
if (!prevHovered) {
nextHovered = nextRegion_.contains(event->pos());
if (!nextHovered) {
for (int idx = 0, e = candidateRegions_.size(); idx < e; idx++) {
if (candidateRegions_[idx].contains(event->pos())) {
hoverIndex_ = idx;
break;
}
}
}
}
needRepaint = needRepaint || prevHovered_ != prevHovered;
prevHovered_ = prevHovered;
needRepaint = needRepaint || nextHovered_ != nextHovered;
nextHovered_ = nextHovered;
needRepaint = needRepaint || oldHighlight != highlight();
if (needRepaint) {
update();
}
}
void FcitxCandidateWindow::mouseReleaseEvent(QMouseEvent *event) {
if (event->button() != Qt::LeftButton) {
return;
}
if (prevRegion_.contains(event->pos())) {
Q_EMIT prevClicked();
return;
}
if (nextRegion_.contains(event->pos())) {
Q_EMIT nextClicked();
return;
}
for (int idx = 0, e = candidateRegions_.size(); idx < e; idx++) {
if (candidateRegions_[idx].contains(event->pos())) {
Q_EMIT candidateSelected(idx);
return;
}
}
}
QSize FcitxCandidateWindow::sizeHint() {
auto minH =
theme_->fontMetrics().ascent() + theme_->fontMetrics().descent();
size_t width = 0;
size_t height = 0;
auto updateIfLarger = [](size_t &m, size_t n) {
if (n > m) {
m = n;
}
};
auto textMargin = theme_->textMargin();
auto extraW = textMargin.left() + textMargin.right();
auto extraH = textMargin.top() + textMargin.bottom();
if (!upperLayout_.text().isEmpty()) {
auto size = upperLayout_.boundingRect();
height += minH + extraH;
updateIfLarger(width, size.width() + extraW);
}
if (!lowerLayout_.text().isEmpty()) {
auto size = lowerLayout_.boundingRect();
height += minH + extraH;
updateIfLarger(width, size.width() + extraW);
}
bool vertical = theme_->vertical();
if (layoutHint_ == FcitxCandidateLayoutHint::Vertical) {
vertical = true;
} else if (layoutHint_ == FcitxCandidateLayoutHint::Horizontal) {
vertical = false;
}
size_t wholeH = 0, wholeW = 0;
for (size_t i = 0; i < labelLayouts_.size(); i++) {
size_t candidateW = 0, candidateH = 0;
if (!labelLayouts_[i]->isEmpty()) {
auto size = labelLayouts_[i]->boundingRect();
candidateW += size.width();
updateIfLarger(candidateH,
std::max(minH, qCeil(size.height())) + extraH);
}
if (!candidateLayouts_[i]->isEmpty()) {
auto size = candidateLayouts_[i]->boundingRect();
candidateW += size.width();
updateIfLarger(candidateH,
std::max(minH, qCeil(size.height())) + extraH);
}
candidateW += extraW;
if (vertical) {
wholeH += candidateH;
updateIfLarger(wholeW, candidateW);
} else {
wholeW += candidateW;
updateIfLarger(wholeH, candidateH);
}
}
updateIfLarger(width, wholeW);
candidatesHeight_ = wholeH;
height += wholeH;
auto contentMargin = theme_->contentMargin();
width += contentMargin.left() + contentMargin.right();
height += contentMargin.top() + contentMargin.bottom();
if (!labelLayouts_.empty() && (hasPrev_ || hasNext_)) {
if (theme_->prev().valid() && theme_->next().valid()) {
width += theme_->prev().width() + theme_->next().width();
}
}
return {static_cast<int>(width), static_cast<int>(height)};
}
void FcitxCandidateWindow::wheelEvent(QWheelEvent *event) {
if (!theme_ || !theme_->wheelForPaging()) {
return;
}
accAngle_ += event->angleDelta().y();
auto angleForClick = 120;
while (accAngle_ >= angleForClick) {
accAngle_ -= angleForClick;
Q_EMIT prevClicked();
}
while (accAngle_ <= -angleForClick) {
accAngle_ += angleForClick;
Q_EMIT nextClicked();
}
}
void FcitxCandidateWindow::paintEvent(QPaintEvent *) {
QPainter p(this);
render(&p);
}
} // namespace fcitx

View File

@@ -0,0 +1,105 @@
/*
* SPDX-FileCopyrightText: 2021~2021 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _PLATFORMINPUTCONTEXT_FCITXCANDIDATEWINDOW_H_
#define _PLATFORMINPUTCONTEXT_FCITXCANDIDATEWINDOW_H_
#include "fcitxflags.h"
#include "fcitxqtdbustypes.h"
#include <QGuiApplication>
#include <QPainter>
#include <QPointer>
#include <QRasterWindow>
#include <QTextLayout>
#include <memory>
#include <qscopedpointer.h>
#include <vector>
#if defined(FCITX_ENABLE_QT6_WAYLAND_WORKAROUND) && \
QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
#include <QtWaylandClient/private/qwayland-xdg-shell.h>
#endif
namespace fcitx {
class FcitxTheme;
class MultilineText;
class QFcitxPlatformInputContext;
class FcitxCandidateWindow : public QRasterWindow {
Q_OBJECT
public:
explicit FcitxCandidateWindow(QWindow *window,
QFcitxPlatformInputContext *context);
~FcitxCandidateWindow();
void render(QPainter *painter);
public Q_SLOTS:
void updateClientSideUI(const FcitxQtFormattedPreeditList &preedit,
int cursorpos,
const FcitxQtFormattedPreeditList &auxUp,
const FcitxQtFormattedPreeditList &auxDown,
const FcitxQtStringKeyValueList &candidates,
int candidateIndex, int layoutHint, bool hasPrev,
bool hasNext);
QSize sizeHint();
Q_SIGNALS:
void candidateSelected(int i);
void prevClicked();
void nextClicked();
protected:
bool event(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
void wheelEvent(QWheelEvent *) override;
int highlight() const {
int highlightIndex = (hoverIndex_ >= 0) ? hoverIndex_ : highlight_;
return highlightIndex;
}
private:
const bool isWayland_ =
QGuiApplication::platformName().startsWith("wayland");
uint32_t repositionToken_ = 0;
QSize actualSize_;
QPointer<QFcitxPlatformInputContext> context_;
QPointer<FcitxTheme> theme_;
QTextLayout upperLayout_;
QTextLayout lowerLayout_;
std::vector<std::unique_ptr<MultilineText>> candidateLayouts_;
std::vector<std::unique_ptr<MultilineText>> labelLayouts_;
int cursor_ = -1;
int highlight_ = -1;
int hoverIndex_ = -1;
int accAngle_ = 0;
bool prevHovered_ = false;
bool nextHovered_ = false;
bool hasPrev_ = false;
bool hasNext_ = false;
FcitxCandidateLayoutHint layoutHint_ = FcitxCandidateLayoutHint::NotSet;
int candidatesHeight_ = 0;
QRect prevRegion_;
QRect nextRegion_;
std::vector<QRect> candidateRegions_;
QPointer<QWindow> parent_;
#if defined(FCITX_ENABLE_QT6_WAYLAND_WORKAROUND) && \
QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
QScopedPointer<QtWayland::xdg_wm_base> xdgWmBase_;
#endif
};
} // namespace fcitx
#endif // _PLATFORMINPUTCONTEXT_FCITXCANDIDATEWINDOW_H_

View File

@@ -0,0 +1,451 @@
/*
* SPDX-FileCopyrightText: 2021~2021 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitxtheme.h"
#include "font.h"
#include <QDebug>
#include <QMargins>
#include <QPixmap>
#include <QSettings>
#include <QStandardPaths>
namespace fcitx {
bool readBool(const QSettings &settings, const QString &name,
bool defaultValue) {
return settings.value(name, defaultValue ? "True" : "False").toString() ==
"True";
}
QMargins readMargin(const QSettings &settings) {
settings.allKeys();
return QMargins(settings.value("Left", 0).toInt(),
settings.value("Top", 0).toInt(),
settings.value("Right", 0).toInt(),
settings.value("Bottom", 0).toInt());
}
QColor readColor(const QSettings &settings, const QString &name,
const QString &defaultValue) {
QString colorString = settings.value(name, defaultValue).toString();
QColor color(defaultValue);
if (colorString.startsWith("#")) {
if (colorString.size() == 7) {
// Parse #RRGGBB
color = QColor(colorString.toUpper());
} else if (colorString.size() == 9) {
// Qt accept "#AARRGGBB"
auto newColorString =
QString("#%1%2")
.arg(colorString.mid(7, 2), colorString.mid(1, 6))
.toUpper();
color = QColor(newColorString);
}
}
return color;
}
void BackgroundImage::load(const QString &name, QSettings &settings) {
settings.allKeys();
image_ = QPixmap();
overlay_ = QPixmap();
if (auto image = settings.value("Image").toString(); !image.isEmpty()) {
auto file = QStandardPaths::locate(
QStandardPaths::GenericDataLocation,
QString("fcitx5/themes/%1/%2").arg(name, image));
image_.load(file);
}
if (auto image = settings.value("Overlay").toString(); !image.isEmpty()) {
auto file = QStandardPaths::locate(
QStandardPaths::GenericDataLocation,
QString("fcitx5/themes/%1/%2").arg(name, image));
overlay_.load(file);
}
settings.beginGroup("Margin");
margin_ = readMargin(settings);
settings.endGroup();
if (image_.isNull()) {
QColor color = readColor(settings, "Color", "#ffffff");
QColor borderColor = readColor(settings, "BorderColor", "#00ffffff");
int borderWidth = settings.value("BorderWidth", 0).toInt();
fillBackground(borderColor, color, borderWidth);
}
settings.beginGroup("OverlayClipMargin");
overlayClipMargin_ = readMargin(settings);
settings.endGroup();
hideOverlayIfOversize_ =
settings.value("HideOverlayIfOversize", "False").toString() == "True";
overlayOffsetX_ = settings.value("OverlayOffsetX", 0).toInt();
overlayOffsetY_ = settings.value("OverlayOffsetY", 0).toInt();
gravity_ = settings.value("Gravity", "TopLeft").toString();
}
void BackgroundImage::loadFromValue(const QColor &border,
const QColor &background, QMargins margin,
int borderWidth) {
image_ = QPixmap();
overlay_ = QPixmap();
margin_ = margin;
fillBackground(border, background, borderWidth);
overlayClipMargin_ = QMargins();
hideOverlayIfOversize_ = false;
overlayOffsetX_ = 0;
overlayOffsetY_ = 0;
gravity_ = QString();
}
void BackgroundImage::fillBackground(const QColor &border,
const QColor &background,
int borderWidth) {
image_ = QPixmap(margin_.left() + margin_.right() + 1,
margin_.top() + margin_.bottom() + 1);
borderWidth = std::min({borderWidth, margin_.left(), margin_.right(),
margin_.top(), margin_.bottom()});
borderWidth = std::max(0, borderWidth);
QPainter painter;
painter.begin(&image_);
painter.setCompositionMode(QPainter::CompositionMode_Source);
if (borderWidth) {
painter.fillRect(image_.rect(), border);
}
painter.fillRect(QRect(borderWidth, borderWidth,
image_.width() - borderWidth * 2,
image_.height() - borderWidth * 2),
background);
painter.end();
}
void ActionImage::load(const QString &name, QSettings &settings) {
settings.allKeys();
image_ = QPixmap();
valid_ = false;
if (auto image = settings.value("Image").toString(); !image.isEmpty()) {
auto file = QStandardPaths::locate(
QStandardPaths::GenericDataLocation,
QString("fcitx5/themes/%1/%2").arg(name, image));
image_.load(file);
valid_ = !image_.isNull();
}
settings.beginGroup("ClickMargin");
margin_ = readMargin(settings);
settings.endGroup();
}
void ActionImage::reset() {
image_ = QPixmap();
valid_ = false;
margin_ = QMargins(0, 0, 0, 0);
}
FcitxTheme::FcitxTheme(QObject *parent)
: QObject(parent), configPath_(QStandardPaths::writableLocation(
QStandardPaths::GenericConfigLocation)
.append("/fcitx5/conf/classicui.conf")),
watcher_(new QFileSystemWatcher) {
connect(watcher_, &QFileSystemWatcher::fileChanged, this,
&FcitxTheme::configChanged);
watcher_->addPath(configPath_);
configChanged();
}
FcitxTheme::~FcitxTheme() {}
void FcitxTheme::configChanged() {
// Since fcitx is doing things like delete and move, we need to re-add the
// path.
watcher_->removePath(configPath_);
watcher_->addPath(configPath_);
QSettings settings(configPath_, QSettings::IniFormat);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
settings.setIniCodec("UTF-8");
#endif
settings.childGroups();
font_ = parseFont(settings.value("Font", "Sans Serif 9").toString());
fontMetrics_ = QFontMetrics(font_);
vertical_ =
settings.value("Vertical Candidate List", "False").toString() == "True";
wheelForPaging_ =
settings.value("WheelForPaging", "True").toString() == "True";
theme_ = settings.value("Theme", "default").toString();
themeChanged();
}
void FcitxTheme::themeChanged() {
if (!themeConfigPath_.isEmpty()) {
watcher_->removePath(themeConfigPath_);
}
auto themeConfig = QString("/fcitx5/themes/%1/theme.conf").arg(theme_);
themeConfigPath_ =
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
.append(themeConfig);
auto file = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
themeConfig);
if (file.isEmpty()) {
file = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
"fcitx5/themes/default/theme.conf");
themeConfigPath_ = QStandardPaths::writableLocation(
QStandardPaths::GenericDataLocation)
.append("fcitx5/themes/default/theme.conf");
theme_ = "default";
}
watcher_->addPath(themeConfigPath_);
// We can not locate default theme.
if (file.isEmpty()) {
normalColor_ = QColor("#000000");
highlightCandidateColor_ = QColor("#ffffff");
fullWidthHighlight_ = true;
highlightColor_ = QColor("#ffffff");
highlightBackgroundColor_ = QColor("#a5a5a5");
contentMargin_ = QMargins{2, 2, 2, 2};
textMargin_ = QMargins{5, 5, 5, 5};
highlightClickMargin_ = QMargins{0, 0, 0, 0};
shadowMargin_ = QMargins{0, 0, 0, 0};
background_.loadFromValue(highlightBackgroundColor_, highlightColor_,
contentMargin_, 2);
highlight_.loadFromValue(highlightBackgroundColor_,
highlightBackgroundColor_, textMargin_, 0);
prev_.reset();
next_.reset();
return;
}
QSettings settings(file, QSettings::IniFormat);
settings.childGroups();
settings.beginGroup("InputPanel");
normalColor_ = readColor(settings, "NormalColor", "#000000");
highlightCandidateColor_ =
readColor(settings, "HighlightCandidateColor", "#ffffff");
fullWidthHighlight_ = readBool(settings, "FullWidthHighlight", true);
highlightColor_ = readColor(settings, "HighlightColor", "#ffffff");
highlightBackgroundColor_ =
readColor(settings, "HighlightBackgroundColor", "#a5a5a5");
buttonAlignment_ =
settings.value("PageButtonAlignment", "Bottom").toString();
settings.beginGroup("ContentMargin");
contentMargin_ = readMargin(settings);
settings.endGroup();
settings.beginGroup("TextMargin");
textMargin_ = readMargin(settings);
settings.endGroup();
settings.beginGroup("ShadowMargin");
shadowMargin_ = readMargin(settings);
settings.endGroup();
settings.beginGroup("Background");
background_.load(theme_, settings);
settings.endGroup();
settings.beginGroup("Highlight");
highlight_.load(theme_, settings);
settings.beginGroup("HighlightClickMargin");
highlightClickMargin_ = readMargin(settings);
settings.endGroup();
settings.endGroup();
settings.beginGroup("PrevPage");
prev_.load(theme_, settings);
settings.endGroup();
settings.beginGroup("NextPage");
next_.load(theme_, settings);
settings.endGroup();
}
} // namespace fcitx
void fcitx::FcitxTheme::paint(QPainter *painter,
const fcitx::BackgroundImage &image,
QRect region) {
auto marginTop = image.margin_.top();
auto marginBottom = image.margin_.bottom();
auto marginLeft = image.margin_.left();
auto marginRight = image.margin_.right();
int resizeHeight = image.image_.height() - marginTop - marginBottom;
int resizeWidth = image.image_.width() - marginLeft - marginRight;
if (resizeHeight <= 0) {
resizeHeight = 1;
}
if (resizeWidth <= 0) {
resizeWidth = 1;
}
if (region.height() < 0) {
region.setHeight(resizeHeight);
}
if (region.width() < 0) {
region.setWidth(resizeWidth);
}
/*
* 7 8 9
* 4 5 6
* 1 2 3
*/
if (marginLeft && marginBottom) {
/* part 1 */
painter->drawPixmap(
QRect(0, region.height() - marginBottom, marginLeft, marginBottom)
.translated(region.topLeft()),
image.image_,
QRect(0, marginTop + resizeHeight, marginLeft, marginBottom));
}
if (marginRight && marginBottom) {
/* part 3 */
painter->drawPixmap(
QRect(region.width() - marginRight, region.height() - marginBottom,
marginRight, marginBottom)
.translated(region.topLeft()),
image.image_,
QRect(marginLeft + resizeWidth, marginTop + resizeHeight,
marginRight, marginBottom));
}
if (marginLeft && marginTop) {
/* part 7 */
painter->drawPixmap(
QRect(0, 0, marginLeft, marginTop).translated(region.topLeft()),
image.image_, QRect(0, 0, marginLeft, marginTop));
}
if (marginRight && marginTop) {
/* part 9 */
painter->drawPixmap(
QRect(region.width() - marginRight, 0, marginRight, marginTop)
.translated(region.topLeft()),
image.image_,
QRect(marginLeft + resizeWidth, 0, marginRight, marginTop));
}
/* part 2 & 8 */
if (marginTop) {
painter->drawPixmap(
QRect(marginLeft, 0, region.width() - marginLeft - marginRight,
marginTop)
.translated(region.topLeft()),
image.image_, QRect(marginLeft, 0, resizeWidth, marginTop));
}
if (marginBottom) {
painter->drawPixmap(QRect(marginLeft, region.height() - marginBottom,
region.width() - marginLeft - marginRight,
marginBottom)
.translated(region.topLeft()),
image.image_,
QRect(marginLeft, marginTop + resizeHeight,
resizeWidth, marginBottom));
}
/* part 4 & 6 */
if (marginLeft) {
painter->drawPixmap(QRect(0, marginTop, marginLeft,
region.height() - marginTop - marginBottom)
.translated(region.topLeft()),
image.image_,
QRect(0, marginTop, marginLeft, resizeHeight));
}
if (marginRight) {
painter->drawPixmap(QRect(region.width() - marginRight, marginTop,
marginRight,
region.height() - marginTop - marginBottom)
.translated(region.topLeft()),
image.image_,
QRect(marginLeft + resizeWidth, marginTop,
marginRight, resizeHeight));
}
/* part 5 */
{
painter->drawPixmap(
QRect(marginLeft, marginTop,
region.width() - marginLeft - marginRight,
region.height() - marginTop - marginBottom)
.translated(region.topLeft()),
image.image_,
QRect(marginLeft, marginTop, resizeWidth, resizeHeight));
}
if (image.overlay_.isNull()) {
return;
}
auto clipWidth = region.width() - image.overlayClipMargin_.left() -
image.overlayClipMargin_.right();
auto clipHeight = region.height() - image.overlayClipMargin_.top() -
image.overlayClipMargin_.bottom();
if (clipWidth <= 0 || clipHeight <= 0) {
return;
}
QRect clipRect(region.topLeft() + QPoint(image.overlayClipMargin_.left(),
image.overlayClipMargin_.top()),
QSize(clipWidth, clipHeight));
int x = 0, y = 0;
if (image.gravity_ == "Top Left" || image.gravity_ == "Center Left" ||
image.gravity_ == "Bottom Left") {
x = image.overlayOffsetX_;
} else if (image.gravity_ == "Top Center" || image.gravity_ == "Center" ||
image.gravity_ == "Bottom Center") {
x = (region.width() - image.overlay_.width()) / 2 +
image.overlayOffsetX_;
} else {
x = region.width() - image.overlay_.width() - image.overlayOffsetX_;
}
if (image.gravity_ == "Top Left" || image.gravity_ == "Top Center" ||
image.gravity_ == "Top Right") {
y = image.overlayOffsetY_;
} else if (image.gravity_ == "Center Left" || image.gravity_ == "Center" ||
image.gravity_ == "Center Right") {
y = (region.height() - image.overlay_.height()) / 2 +
image.overlayOffsetY_;
} else {
y = region.height() - image.overlay_.height() - image.overlayOffsetY_;
}
QRect rect(QPoint(x, y) + region.topLeft(), image.overlay_.size());
QRect finalRect = rect.intersected(clipRect);
if (finalRect.isEmpty()) {
return;
}
if (image.hideOverlayIfOversize_ && !clipRect.contains(rect)) {
return;
}
painter->save();
painter->setClipRect(clipRect);
painter->drawPixmap(rect, image.overlay_);
painter->restore();
}
void fcitx::FcitxTheme::paint(QPainter *painter,
const fcitx::ActionImage &image, QPoint position,
float alpha) {
painter->save();
painter->setOpacity(alpha);
painter->drawPixmap(position, image.image_);
painter->restore();
}
QMargins fcitx::FcitxTheme::highlightMargin() const {
return highlight_.margin_;
}

View File

@@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2021~2021 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _PLATFORMINPUTCONTEXT_FCITXTHEME_H_
#define _PLATFORMINPUTCONTEXT_FCITXTHEME_H_
#include <QColor>
#include <QFileSystemWatcher>
#include <QFont>
#include <QFontMetrics>
#include <QMargins>
#include <QObject>
#include <QPainter>
#include <QPixmap>
#include <QSettings>
namespace fcitx {
class BackgroundImage {
friend class FcitxTheme;
public:
void load(const QString &name, QSettings &settings);
void loadFromValue(const QColor &border, const QColor &background,
QMargins margin, int borderWidth);
private:
void fillBackground(const QColor &border, const QColor &background,
int borderWidth);
QPixmap image_, overlay_;
QMargins margin_, overlayClipMargin_;
bool hideOverlayIfOversize_ = false;
QString gravity_;
int overlayOffsetX_ = 0;
int overlayOffsetY_ = 0;
};
class ActionImage {
friend class FcitxTheme;
public:
void load(const QString &name, QSettings &settings);
void reset();
bool valid() const { return valid_; }
int width() const { return image_.width(); }
int height() const { return image_.height(); }
QSize size() const { return image_.size(); }
const QMargins &margin() const { return margin_; }
private:
bool valid_ = false;
QPixmap image_;
QMargins margin_;
};
class FcitxTheme : public QObject {
Q_OBJECT
public:
FcitxTheme(QObject *parent = nullptr);
~FcitxTheme();
void paint(QPainter *painter, const BackgroundImage &image, QRect region);
void paint(QPainter *painter, const ActionImage &image, QPoint position,
float alpha);
const auto &background() const { return background_; }
const auto &highlight() const { return highlight_; }
const auto &prev() const { return prev_; }
const auto &next() const { return next_; }
const auto &font() const { return font_; }
const auto &fontMetrics() const { return fontMetrics_; }
const auto &highlightBackgroundColor() const {
return highlightBackgroundColor_;
}
const auto &highlightColor() const { return highlightColor_; }
const auto &buttonAlignment() const { return buttonAlignment_; }
auto contentMargin() const { return contentMargin_; }
auto textMargin() const { return textMargin_; }
auto highlightClickMargin() const { return highlightClickMargin_; }
QMargins highlightMargin() const;
auto shadowMargin() const { return shadowMargin_; }
auto normalColor() const { return normalColor_; }
auto highlightCandidateColor() const { return highlightCandidateColor_; }
auto vertical() const { return vertical_; }
auto wheelForPaging() const { return wheelForPaging_; }
private Q_SLOTS:
void configChanged();
void themeChanged();
private:
QString configPath_;
QString themeConfigPath_;
QFileSystemWatcher *watcher_;
QFont font_;
QFontMetrics fontMetrics_{font_};
bool vertical_ = false;
bool wheelForPaging_ = true;
QString theme_ = "default";
BackgroundImage background_;
BackgroundImage highlight_;
ActionImage prev_;
ActionImage next_;
QColor normalColor_{Qt::black};
QColor highlightCandidateColor_{Qt::white};
bool fullWidthHighlight_ = true;
QColor highlightColor_{Qt::white};
QColor highlightBackgroundColor_{0xa5, 0xa5, 0xa5};
QString buttonAlignment_;
QMargins highlightClickMargin_;
QMargins contentMargin_;
QMargins textMargin_;
QMargins shadowMargin_;
};
} // namespace fcitx
#endif // _PLATFORMINPUTCONTEXT_FCITXTHEME_H_

View File

@@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#include "font.h"
#include <QMap>
QFont fcitx::parseFont(const QString &string) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
auto list = string.split(" ", QString::SkipEmptyParts);
#else
auto list = string.split(" ", Qt::SkipEmptyParts);
#endif
int size = 9; // Default size.
if (!list.empty()) {
bool ok = false;
auto fontSize = list.back().toInt(&ok);
if (ok) {
if (fontSize > 0) {
size = fontSize;
}
list.pop_back();
}
}
QFont::Style style = QFont::StyleNormal;
QFont::Weight weight = QFont::Normal;
const QMap<QString, QFont::Weight> strToWeight = {
{"Thin", QFont::Thin},
{"Ultra-Light", QFont::Thin},
{"Extra-Light", QFont::ExtraLight},
{"Light", QFont::Light},
{"Semi-Light", QFont::Light},
{"Demi-Light", QFont::Light},
{"Book", QFont::Light},
{"Regular", QFont::Normal},
{"Medium", QFont::Medium},
{"Semi-Bold", QFont::Medium},
{"Demi-Bold", QFont::DemiBold},
{"Bold", QFont::Bold},
{"Ultra-Bold", QFont::Bold},
{"Extra-Bold", QFont::ExtraBold},
{"Black", QFont::Black},
{"Ultra-Black", QFont::Black},
{"Extra-Black", QFont::Black},
};
const QMap<QString, QFont::Style> strToStyle = {
{"Italic", QFont::StyleItalic}, {"Oblique", QFont::StyleOblique}};
while (!list.empty()) {
if (strToWeight.contains(list.back())) {
weight = strToWeight.value(list.back(), QFont::Normal);
list.pop_back();
} else if (strToStyle.contains(list.back())) {
style = strToStyle.value(list.back(), QFont::StyleNormal);
list.pop_back();
} else {
break;
}
}
QString family = list.join(" ");
QFont font;
font.setFamily(family);
font.setWeight(weight);
font.setStyle(style);
font.setPointSize(size);
return font;
}

View File

@@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#ifndef _CONFIGLIB_FONT_H_
#define _CONFIGLIB_FONT_H_
#include <QFont>
#include <QString>
namespace fcitx {
QFont parseFont(const QString &str);
} // namespace fcitx
#endif // _CONFIGLIB_FONT_H_

View File

@@ -0,0 +1,280 @@
/*
* SPDX-FileCopyrightText: 2023~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "hybridinputcontext.h"
#include "fcitx4inputcontextproxy.h"
#include "fcitxqtinputcontextproxy.h"
#include "fcitxqtwatcher.h"
#include <cstddef>
namespace fcitx {
HybridInputContext::HybridInputContext(FcitxQtWatcher *watcher,
Fcitx4Watcher *fcitx4Watcher,
QObject *parent)
: QObject(parent), watcher_(watcher), fcitx4Watcher_(fcitx4Watcher) {
// We use a timer here to avoid recheck being triggered multiple times.
// For fcitx5, the fcitx4frontend and dbusfrontend will be initialized
// around the same time. 50ms is specifically selected to be smaller than
// the 100ms timer within input context.
timer_.setInterval(50);
timer_.setSingleShot(true);
connect(&timer_, &QTimer::timeout, this,
[this]() { doRecheck(/*skipFcitx5=*/false); });
connect(watcher_, &FcitxQtWatcher::availabilityChanged, this,
&HybridInputContext::recheck);
connect(fcitx4Watcher_, &Fcitx4Watcher::availabilityChanged, this,
&HybridInputContext::recheck);
recheck();
}
void HybridInputContext::recheck() { timer_.start(); }
void HybridInputContext::doRecheck(bool skipFcitx5) {
const bool fcitx5Available = !skipFcitx5 && watcher_->availability();
if (!fcitx5Available) {
delete proxy_;
proxy_ = nullptr;
}
if (!fcitx4Watcher_->availability()) {
delete proxy4_;
proxy4_ = nullptr;
}
if (fcitx5Available) {
delete proxy4_;
proxy4_ = nullptr;
if (!proxy_) {
proxy_ = new FcitxQtInputContextProxy(watcher_, this);
proxy_->setDisplay(display_);
connect(proxy_, &FcitxQtInputContextProxy::commitString, this,
&HybridInputContext::commitString);
connect(proxy_, &FcitxQtInputContextProxy::currentIM, this,
&HybridInputContext::currentIM);
connect(proxy_, &FcitxQtInputContextProxy::deleteSurroundingText,
this, &HybridInputContext::deleteSurroundingText);
connect(proxy_, &FcitxQtInputContextProxy::forwardKey, this,
&HybridInputContext::forwardKey);
connect(proxy_, &FcitxQtInputContextProxy::updateFormattedPreedit,
this, &HybridInputContext::updateFormattedPreedit);
connect(proxy_, &FcitxQtInputContextProxy::updateClientSideUI, this,
&HybridInputContext::updateClientSideUI);
connect(proxy_, &FcitxQtInputContextProxy::inputContextCreated,
this, &HybridInputContext::inputContextCreated);
connect(proxy_,
&FcitxQtInputContextProxy::inputContextCreationFailed, this,
&HybridInputContext::inputContextCreationFailed);
connect(proxy_, &FcitxQtInputContextProxy::notifyFocusOut, this,
&HybridInputContext::notifyFocusOut);
connect(proxy_,
&FcitxQtInputContextProxy::virtualKeyboardVisibilityChanged,
this,
&HybridInputContext::virtualKeyboardVisibilityChanged);
}
} else if (fcitx4Watcher_->availability()) {
if (!proxy4_) {
proxy4_ = new Fcitx4InputContextProxy(fcitx4Watcher_, this);
connect(proxy4_, &Fcitx4InputContextProxy::commitString, this,
&HybridInputContext::commitString);
connect(proxy4_, &Fcitx4InputContextProxy::currentIM, this,
&HybridInputContext::currentIM);
connect(proxy4_, &Fcitx4InputContextProxy::deleteSurroundingText,
this, &HybridInputContext::deleteSurroundingText);
connect(proxy4_, &Fcitx4InputContextProxy::forwardKey, this,
&HybridInputContext::forwardKey);
connect(
proxy4_, &Fcitx4InputContextProxy::updateFormattedPreedit, this,
[this](const FcitxQtFormattedPreeditList &list, int cursorpos) {
auto newList = list;
for (auto item : newList) {
const qint32 underlineBit = (1 << 3);
// revert non underline and "underline"
item.setFormat(item.format() ^ underlineBit);
}
Q_EMIT updateFormattedPreedit(newList, cursorpos);
});
connect(proxy4_, &Fcitx4InputContextProxy::inputContextCreated,
this,
[this]() { Q_EMIT inputContextCreated(QByteArray()); });
}
}
}
void HybridInputContext::inputContextCreationFailed() {
doRecheck(/*skipFcitx5=*/true);
}
bool HybridInputContext::isValid() const {
if (proxy_) {
return proxy_->isValid();
} else if (proxy4_) {
return proxy4_->isValid();
}
return false;
}
void HybridInputContext::reset() {
if (proxy_) {
proxy_->reset();
} else if (proxy4_) {
proxy4_->reset();
}
}
void HybridInputContext::selectCandidate(int i) {
if (proxy_) {
proxy_->selectCandidate(i);
}
}
void HybridInputContext::prevPage() {
if (proxy_) {
proxy_->prevPage();
}
}
void HybridInputContext::nextPage() {
if (proxy_) {
proxy_->nextPage();
}
}
bool HybridInputContext::supportInvokeAction() const {
if (proxy_) {
return proxy_->supportInvokeAction();
}
return false;
}
void HybridInputContext::invokeAction(unsigned int action, int cursor) {
if (proxy_) {
proxy_->invokeAction(action, cursor);
}
}
void HybridInputContext::setSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor) {
if (proxy_) {
proxy_->setSurroundingText(text, cursor, anchor);
} else if (proxy4_) {
proxy4_->setSurroundingText(text, cursor, anchor);
}
}
void HybridInputContext::setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
if (proxy_) {
proxy_->setSurroundingTextPosition(cursor, anchor);
} else if (proxy4_) {
proxy4_->setSurroundingTextPosition(cursor, anchor);
}
}
void HybridInputContext::focusIn() {
if (proxy_) {
proxy_->focusIn();
} else if (proxy4_) {
proxy4_->focusIn();
}
}
void HybridInputContext::focusOut() {
if (proxy_) {
proxy_->focusOut();
} else if (proxy4_) {
proxy4_->focusOut();
}
}
void HybridInputContext::setCursorRectV2(int x, int y, int w, int h,
double scale) {
if (proxy_) {
proxy_->setCursorRectV2(x, y, w, h, scale);
} else if (proxy4_) {
proxy4_->setCursorRect(x, y, w, h);
}
}
void HybridInputContext::setCursorRect(int x, int y, int w, int h) {
if (proxy_) {
proxy_->setCursorRect(x, y, w, h);
} else if (proxy4_) {
proxy4_->setCursorRect(x, y, w, h);
}
}
void HybridInputContext::setSupportedCapability(quint64 supported) {
if (proxy_) {
proxy_->setSupportedCapability(supported);
}
}
void HybridInputContext::setCapability(quint64 capability) {
if (proxy_) {
proxy_->setCapability(capability);
} else if (proxy4_) {
proxy4_->setCapability(capability & 0xfffffffffULL);
}
}
void HybridInputContext::showVirtualKeyboard() {
if (proxy_) {
proxy_->showVirtualKeyboard();
}
}
void HybridInputContext::hideVirtualKeyboard() {
if (proxy_) {
proxy_->hideVirtualKeyboard();
}
}
bool HybridInputContext::isVirtualKeyboardVisible() const {
if (proxy_) {
return proxy_->isVirtualKeyboardVisible();
}
return false;
}
void HybridInputContext::setDisplay(const QString &display) {
if (proxy_) {
proxy_->setDisplay(display);
}
display_ = display;
}
QDBusPendingCall HybridInputContext::processKeyEvent(unsigned int keyval,
unsigned int keycode,
unsigned int state,
bool type,
unsigned int time) {
if (proxy_) {
return proxy_->processKeyEvent(keyval, keycode, state, type, time);
}
return proxy4_->processKeyEvent(keyval, keycode, state, type ? 1 : 0, time);
}
bool HybridInputContext::processKeyEventResult(const QDBusPendingCall &call) {
if (call.isError()) {
return false;
}
if (call.reply().signature() == "b") {
QDBusPendingReply<bool> reply = call;
return reply.value();
} else if (call.reply().signature() == "i") {
QDBusPendingReply<int> reply = call;
return reply.value() > 0;
}
return false;
}
} // namespace fcitx

View File

@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2023~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef HYBRIDINPUTCONTEXT_H
#define HYBRIDINPUTCONTEXT_H
#include "fcitx4inputcontextproxy.h"
#include "fcitx4watcher.h"
#include "fcitxqtdbustypes.h"
#include "fcitxqtinputcontextproxy.h"
#include "fcitxqtwatcher.h"
#include <QDBusPendingReply>
#include <QObject>
#include <QString>
#include <QTimer>
namespace fcitx {
class HybridInputContext : public QObject {
Q_OBJECT
public:
HybridInputContext(FcitxQtWatcher *watcher, Fcitx4Watcher *fcitx4Watcher,
QObject *parent);
void focusIn();
void focusOut();
void setSurroundingText(const QString &text, unsigned int cursor,
unsigned int anchor);
void setSurroundingTextPosition(unsigned int cursor, unsigned int anchor);
void prevPage();
void nextPage();
void reset();
void selectCandidate(int index);
bool supportInvokeAction() const;
void invokeAction(unsigned int action, int cursor);
bool isValid() const;
void showVirtualKeyboard();
void hideVirtualKeyboard();
bool isVirtualKeyboardVisible() const;
void setDisplay(const QString &display);
void setCapability(quint64 capability);
void setCursorRect(int x, int y, int w, int h);
void setCursorRectV2(int x, int y, int w, int h, double scale);
void setSupportedCapability(quint64 supported);
QDBusPendingCall processKeyEvent(unsigned int keyval, unsigned int keycode,
unsigned int state, bool type,
unsigned int time);
static bool processKeyEventResult(const QDBusPendingCall &call);
Q_SIGNALS:
void commitString(const QString &str);
void currentIM(const QString &name, const QString &uniqueName,
const QString &langCode);
void deleteSurroundingText(int offset, unsigned int nchar);
void forwardKey(unsigned int keyval, unsigned int state, bool isRelease);
void updateFormattedPreedit(const FcitxQtFormattedPreeditList &str,
int cursorpos);
void updateClientSideUI(const FcitxQtFormattedPreeditList &preedit,
int cursorpos,
const FcitxQtFormattedPreeditList &auxUp,
const FcitxQtFormattedPreeditList &auxDown,
const FcitxQtStringKeyValueList &candidates,
int candidateIndex, int layoutHint, bool hasPrev,
bool hasNext);
void inputContextCreated(const QByteArray &uuid);
void notifyFocusOut();
void virtualKeyboardVisibilityChanged(bool visible);
private Q_SLOTS:
void recheck();
void doRecheck(bool skipFcitx5);
void inputContextCreationFailed();
private:
QTimer timer_;
FcitxQtWatcher *watcher_;
Fcitx4Watcher *fcitx4Watcher_;
FcitxQtInputContextProxy *proxy_ = nullptr;
Fcitx4InputContextProxy *proxy4_ = nullptr;
QString display_;
};
} // namespace fcitx
#endif

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "main.h"
fcitx::QFcitxPlatformInputContext *
QFcitx5PlatformInputContextPlugin::create(const QString &system,
const QStringList &paramList) {
Q_UNUSED(paramList);
if (system.compare(system, QStringLiteral("fcitx5"), Qt::CaseInsensitive) ==
0 ||
system.compare(system, QStringLiteral("fcitx"), Qt::CaseInsensitive) ==
0) {
return new fcitx::QFcitxPlatformInputContext;
}
return 0;
}

View File

@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef MAIN_H
#define MAIN_H
#include <QStringList>
#include <qpa/qplatforminputcontextplugin_p.h>
#include "qfcitxplatforminputcontext.h"
class QFcitx5PlatformInputContextPlugin : public QPlatformInputContextPlugin {
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformInputContextFactoryInterface_iid FILE
FCITX_PLUGIN_DATA_FILE_PATH)
public:
fcitx::QFcitxPlatformInputContext *
create(const QString &system, const QStringList &paramList) override;
};
#endif // MAIN_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef QFCITXPLATFORMINPUTCONTEXT_H
#define QFCITXPLATFORMINPUTCONTEXT_H
#include "fcitxcandidatewindow.h"
#include "fcitxqtwatcher.h"
#include "hybridinputcontext.h"
#include <QDBusConnection>
#include <QDBusPendingCallWatcher>
#include <QDBusServiceWatcher>
#include <QGuiApplication>
#include <QKeyEvent>
#include <QPointer>
#include <QRect>
#include <QWindow>
#include <memory>
#include <qpa/qplatforminputcontext.h>
#include <unordered_map>
#include <xkbcommon/xkbcommon-compose.h>
namespace fcitx {
class FcitxQtConnection;
class QFcitxPlatformInputContext;
class FcitxQtICData : public QObject {
public:
FcitxQtICData(QFcitxPlatformInputContext *context, QWindow *window);
FcitxQtICData(const FcitxQtICData &that) = delete;
~FcitxQtICData() override;
FcitxCandidateWindow *candidateWindow();
QWindow *window() { return window_.data(); }
void resetCandidateWindow();
quint64 capability = 0;
HybridInputContext *proxy;
QRect rect;
// Last key event forwarded.
std::unique_ptr<QKeyEvent> event;
QString surroundingText;
int surroundingAnchor = -1;
int surroundingCursor = -1;
bool expectingMicroFocusChange = false;
bool eventFilter(QObject *watched, QEvent *event) override;
private:
QFcitxPlatformInputContext *context_;
QPointer<QWindow> window_;
QPointer<FcitxCandidateWindow> candidateWindow_;
};
class ProcessKeyWatcher : public QDBusPendingCallWatcher {
Q_OBJECT
public:
ProcessKeyWatcher(const QKeyEvent &event, QWindow *window,
const QDBusPendingCall &call, QObject *parent = nullptr)
: QDBusPendingCallWatcher(call, parent),
event_(event.type(), event.key(), event.modifiers(),
event.nativeScanCode(), event.nativeVirtualKey(),
event.nativeModifiers(), event.text(), event.isAutoRepeat(),
event.count()),
window_(window) {}
const QKeyEvent &keyEvent() { return event_; }
QWindow *window() { return window_.data(); }
private:
QKeyEvent event_;
QPointer<QWindow> window_;
};
struct XkbContextDeleter {
static inline void cleanup(struct xkb_context *pointer) {
if (pointer) {
xkb_context_unref(pointer);
}
}
};
struct XkbComposeTableDeleter {
static inline void cleanup(struct xkb_compose_table *pointer) {
if (pointer) {
xkb_compose_table_unref(pointer);
}
}
};
struct XkbComposeStateDeleter {
static inline void cleanup(struct xkb_compose_state *pointer) {
if (pointer) {
xkb_compose_state_unref(pointer);
}
}
};
class QFcitxPlatformInputContext : public QPlatformInputContext {
Q_OBJECT
public:
QFcitxPlatformInputContext();
~QFcitxPlatformInputContext() override;
bool isValid() const override;
void setFocusObject(QObject *object) override;
void invokeAction(QInputMethod::Action imAction,
int cursorPosition) override;
void reset() override;
void commit() override;
void update(Qt::InputMethodQueries queries) override;
bool filterEvent(const QEvent *event) override;
QLocale locale() const override;
bool hasCapability(Capability capability) const override;
void showInputPanel() override;
void hideInputPanel() override;
bool isInputPanelVisible() const override;
auto *watcher() { return watcher_; }
auto *fcitx4Watcher() { return fcitx4Watcher_; }
// Use Wrapper as suffix to avoid upstream add function with same name.
QObject *focusObjectWrapper() const;
QWindow *focusWindowWrapper() const;
QRect cursorRectangleWrapper() const;
// Initialize theme object on demand.
FcitxTheme *theme();
bool hasPreedit() const { return !preeditList_.isEmpty(); }
public Q_SLOTS:
void cursorRectChanged();
void commitString(const QString &str);
void updateFormattedPreedit(const FcitxQtFormattedPreeditList &preeditList,
int cursorPos);
void deleteSurroundingText(int offset, unsigned int nchar);
void forwardKey(unsigned int keyval, unsigned int state, bool type);
void createInputContextFinished(const QByteArray &uuid);
void cleanUp();
void windowDestroyed(QObject *object);
void updateCurrentIM(const QString &name, const QString &uniqueName,
const QString &langCode);
void updateClientSideUI(const FcitxQtFormattedPreeditList &preedit,
int cursorpos,
const FcitxQtFormattedPreeditList &auxUp,
const FcitxQtFormattedPreeditList &auxDown,
const FcitxQtStringKeyValueList &candidates,
int candidateIndex, int layoutHint, bool hasPrev,
bool hasNext);
void serverSideFocusOut();
bool commitPreedit(QPointer<QObject> input = qApp->focusObject());
private Q_SLOTS:
void processKeyEventFinished(QDBusPendingCallWatcher *);
private:
bool processCompose(unsigned int keyval, unsigned int state,
bool isRelease);
QKeyEvent *createKeyEvent(unsigned int keyval, unsigned int state,
bool isRelease, const QKeyEvent *event);
void forwardEvent(QWindow *window, const QKeyEvent &event);
void addCapability(FcitxQtICData &data, quint64 capability,
bool forceUpdate = false) {
auto newcaps = data.capability | capability;
if (data.capability != newcaps || forceUpdate) {
data.capability = newcaps;
updateCapability(data);
}
}
void removeCapability(FcitxQtICData &data, quint64 capability,
bool forceUpdate = false) {
auto newcaps = data.capability & (~capability);
if (data.capability != newcaps || forceUpdate) {
data.capability = newcaps;
updateCapability(data);
}
}
void updateCapability(const FcitxQtICData &data);
void createICData(QWindow *w);
HybridInputContext *validIC() const;
HybridInputContext *validICByWindow(QWindow *window) const;
bool filterEventFallback(unsigned int keyval, unsigned int keycode,
unsigned int state, bool isRelease);
void updateCursorRect();
bool objectAcceptsInputMethod() const;
bool shouldDisableInputMethod() const;
void updateInputPanelVisible();
FcitxQtWatcher *watcher_;
Fcitx4Watcher *fcitx4Watcher_;
QString preedit_;
QString commitPreedit_;
FcitxQtFormattedPreeditList preeditList_;
int cursorPos_;
bool useSurroundingText_;
bool syncMode_;
std::unordered_map<QWindow *, FcitxQtICData> icMap_;
QPointer<QWindow> lastWindow_;
QPointer<QObject> lastObject_;
bool destroy_;
bool virtualKeyboardVisible_;
QScopedPointer<struct xkb_context, XkbContextDeleter> xkbContext_;
QScopedPointer<struct xkb_compose_table, XkbComposeTableDeleter>
xkbComposeTable_;
QScopedPointer<struct xkb_compose_state, XkbComposeStateDeleter>
xkbComposeState_;
QLocale locale_;
FcitxTheme *theme_ = nullptr;
bool inputPanelVisible_ = false;
};
} // namespace fcitx
#endif // QFCITXPLATFORMINPUTCONTEXT_H

View File

@@ -0,0 +1,364 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "qtkey.h"
#include <QHash>
#include <QString>
#include <ctype.h>
#include <qnamespace.h>
#include <unordered_map>
#include <xkbcommon/xkbcommon.h>
const std::unordered_map<uint32_t, int> &KeyTbl() {
static std::unordered_map<uint32_t, int> keyTbl{
std::make_pair(XKB_KEY_KP_Space, Qt::Key_Space),
std::make_pair(XKB_KEY_KP_Tab, Qt::Key_Tab),
std::make_pair(XKB_KEY_KP_Enter, Qt::Key_Enter),
std::make_pair(XKB_KEY_KP_F1, Qt::Key_F1),
std::make_pair(XKB_KEY_KP_F2, Qt::Key_F2),
std::make_pair(XKB_KEY_KP_F3, Qt::Key_F3),
std::make_pair(XKB_KEY_KP_F4, Qt::Key_F4),
std::make_pair(XKB_KEY_KP_Home, Qt::Key_Home),
std::make_pair(XKB_KEY_KP_Left, Qt::Key_Left),
std::make_pair(XKB_KEY_KP_Up, Qt::Key_Up),
std::make_pair(XKB_KEY_KP_Right, Qt::Key_Right),
std::make_pair(XKB_KEY_KP_Down, Qt::Key_Down),
std::make_pair(XKB_KEY_KP_Page_Up, Qt::Key_PageUp),
std::make_pair(XKB_KEY_KP_Page_Down, Qt::Key_PageDown),
std::make_pair(XKB_KEY_KP_End, Qt::Key_End),
std::make_pair(XKB_KEY_KP_Begin, Qt::Key_Clear),
std::make_pair(XKB_KEY_KP_Insert, Qt::Key_Insert),
std::make_pair(XKB_KEY_KP_Delete, Qt::Key_Delete),
std::make_pair(XKB_KEY_KP_Equal, Qt::Key_Equal),
std::make_pair(XKB_KEY_KP_Multiply, Qt::Key_multiply),
std::make_pair(XKB_KEY_KP_Add, Qt::Key_Plus),
std::make_pair(XKB_KEY_KP_Separator, Qt::Key_Comma),
std::make_pair(XKB_KEY_KP_Subtract, Qt::Key_Minus),
std::make_pair(XKB_KEY_KP_Decimal, Qt::Key_Period),
std::make_pair(XKB_KEY_KP_Divide, Qt::Key_Slash),
std::make_pair(XKB_KEY_KP_0, Qt::Key_0),
std::make_pair(XKB_KEY_KP_1, Qt::Key_1),
std::make_pair(XKB_KEY_KP_2, Qt::Key_2),
std::make_pair(XKB_KEY_KP_3, Qt::Key_3),
std::make_pair(XKB_KEY_KP_4, Qt::Key_4),
std::make_pair(XKB_KEY_KP_5, Qt::Key_5),
std::make_pair(XKB_KEY_KP_6, Qt::Key_6),
std::make_pair(XKB_KEY_KP_7, Qt::Key_7),
std::make_pair(XKB_KEY_KP_8, Qt::Key_8),
std::make_pair(XKB_KEY_KP_9, Qt::Key_9),
std::make_pair(XKB_KEY_Escape, Qt::Key_Escape),
std::make_pair(XKB_KEY_Tab, Qt::Key_Tab),
std::make_pair(XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab),
std::make_pair(XKB_KEY_BackSpace, Qt::Key_Backspace),
std::make_pair(XKB_KEY_Return, Qt::Key_Return),
std::make_pair(XKB_KEY_KP_Enter, Qt::Key_Enter),
std::make_pair(XKB_KEY_Insert, Qt::Key_Insert),
std::make_pair(XKB_KEY_Delete, Qt::Key_Delete),
std::make_pair(XKB_KEY_Clear, Qt::Key_Delete),
std::make_pair(XKB_KEY_Pause, Qt::Key_Pause),
std::make_pair(XKB_KEY_Print, Qt::Key_Print),
std::make_pair(XKB_KEY_Sys_Req, Qt::Key_SysReq),
std::make_pair(0x1005FF60, Qt::Key_SysReq),
std::make_pair(0x1007ff00, Qt::Key_SysReq),
std::make_pair(XKB_KEY_Home, Qt::Key_Home),
std::make_pair(XKB_KEY_End, Qt::Key_End),
std::make_pair(XKB_KEY_Left, Qt::Key_Left),
std::make_pair(XKB_KEY_Up, Qt::Key_Up),
std::make_pair(XKB_KEY_Right, Qt::Key_Right),
std::make_pair(XKB_KEY_Down, Qt::Key_Down),
std::make_pair(XKB_KEY_Page_Up, Qt::Key_PageUp),
std::make_pair(XKB_KEY_Page_Down, Qt::Key_PageDown),
std::make_pair(XKB_KEY_Shift_L, Qt::Key_Shift),
std::make_pair(XKB_KEY_Shift_R, Qt::Key_Shift),
std::make_pair(XKB_KEY_Shift_Lock, Qt::Key_Shift),
std::make_pair(XKB_KEY_Control_L, Qt::Key_Control),
std::make_pair(XKB_KEY_Control_R, Qt::Key_Control),
std::make_pair(XKB_KEY_Meta_L, Qt::Key_Meta),
std::make_pair(XKB_KEY_Meta_R, Qt::Key_Meta),
std::make_pair(XKB_KEY_Alt_L, Qt::Key_Alt),
std::make_pair(XKB_KEY_Alt_R, Qt::Key_Alt),
std::make_pair(XKB_KEY_Caps_Lock, Qt::Key_CapsLock),
std::make_pair(XKB_KEY_Num_Lock, Qt::Key_NumLock),
std::make_pair(XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock),
std::make_pair(XKB_KEY_F1, Qt::Key_F1),
std::make_pair(XKB_KEY_F2, Qt::Key_F2),
std::make_pair(XKB_KEY_F3, Qt::Key_F3),
std::make_pair(XKB_KEY_F4, Qt::Key_F4),
std::make_pair(XKB_KEY_F5, Qt::Key_F5),
std::make_pair(XKB_KEY_F6, Qt::Key_F6),
std::make_pair(XKB_KEY_F7, Qt::Key_F7),
std::make_pair(XKB_KEY_F8, Qt::Key_F8),
std::make_pair(XKB_KEY_F9, Qt::Key_F9),
std::make_pair(XKB_KEY_F10, Qt::Key_F10),
std::make_pair(XKB_KEY_F11, Qt::Key_F11),
std::make_pair(XKB_KEY_F12, Qt::Key_F12),
std::make_pair(XKB_KEY_F13, Qt::Key_F13),
std::make_pair(XKB_KEY_F14, Qt::Key_F14),
std::make_pair(XKB_KEY_F15, Qt::Key_F15),
std::make_pair(XKB_KEY_F16, Qt::Key_F16),
std::make_pair(XKB_KEY_F17, Qt::Key_F17),
std::make_pair(XKB_KEY_F18, Qt::Key_F18),
std::make_pair(XKB_KEY_F19, Qt::Key_F19),
std::make_pair(XKB_KEY_F20, Qt::Key_F20),
std::make_pair(XKB_KEY_F21, Qt::Key_F21),
std::make_pair(XKB_KEY_F22, Qt::Key_F22),
std::make_pair(XKB_KEY_F23, Qt::Key_F23),
std::make_pair(XKB_KEY_F24, Qt::Key_F24),
std::make_pair(XKB_KEY_F25, Qt::Key_F25),
std::make_pair(XKB_KEY_F26, Qt::Key_F26),
std::make_pair(XKB_KEY_F27, Qt::Key_F27),
std::make_pair(XKB_KEY_F28, Qt::Key_F28),
std::make_pair(XKB_KEY_F29, Qt::Key_F29),
std::make_pair(XKB_KEY_F30, Qt::Key_F30),
std::make_pair(XKB_KEY_F31, Qt::Key_F31),
std::make_pair(XKB_KEY_F32, Qt::Key_F32),
std::make_pair(XKB_KEY_F33, Qt::Key_F33),
std::make_pair(XKB_KEY_F34, Qt::Key_F34),
std::make_pair(XKB_KEY_F35, Qt::Key_F35),
std::make_pair(XKB_KEY_Super_L, Qt::Key_Super_L),
std::make_pair(XKB_KEY_Super_R, Qt::Key_Super_R),
std::make_pair(XKB_KEY_Menu, Qt::Key_Menu),
std::make_pair(XKB_KEY_Hyper_L, Qt::Key_Hyper_L),
std::make_pair(XKB_KEY_Hyper_R, Qt::Key_Hyper_R),
std::make_pair(XKB_KEY_Help, Qt::Key_Help),
std::make_pair(XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr),
std::make_pair(XKB_KEY_Multi_key, Qt::Key_Multi_key),
std::make_pair(XKB_KEY_Codeinput, Qt::Key_Codeinput),
std::make_pair(XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate),
std::make_pair(XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate),
std::make_pair(XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate),
std::make_pair(XKB_KEY_Mode_switch, Qt::Key_Mode_switch),
std::make_pair(XKB_KEY_script_switch, Qt::Key_Mode_switch),
std::make_pair(XKB_KEY_Kanji, Qt::Key_Kanji),
std::make_pair(XKB_KEY_Muhenkan, Qt::Key_Muhenkan),
std::make_pair(XKB_KEY_Henkan, Qt::Key_Henkan),
std::make_pair(XKB_KEY_Romaji, Qt::Key_Romaji),
std::make_pair(XKB_KEY_Hiragana, Qt::Key_Hiragana),
std::make_pair(XKB_KEY_Katakana, Qt::Key_Katakana),
std::make_pair(XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana),
std::make_pair(XKB_KEY_Zenkaku, Qt::Key_Zenkaku),
std::make_pair(XKB_KEY_Hankaku, Qt::Key_Hankaku),
std::make_pair(XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku),
std::make_pair(XKB_KEY_Touroku, Qt::Key_Touroku),
std::make_pair(XKB_KEY_Massyo, Qt::Key_Massyo),
std::make_pair(XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock),
std::make_pair(XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift),
std::make_pair(XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift),
std::make_pair(XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle),
std::make_pair(XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput),
std::make_pair(XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate),
std::make_pair(XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate),
std::make_pair(XKB_KEY_Hangul, Qt::Key_Hangul),
std::make_pair(XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start),
std::make_pair(XKB_KEY_Hangul_End, Qt::Key_Hangul_End),
std::make_pair(XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja),
std::make_pair(XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo),
std::make_pair(XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja),
std::make_pair(XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput),
std::make_pair(XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja),
std::make_pair(XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja),
std::make_pair(XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja),
std::make_pair(XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja),
std::make_pair(XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate),
std::make_pair(XKB_KEY_Hangul_MultipleCandidate,
Qt::Key_MultipleCandidate),
std::make_pair(XKB_KEY_Hangul_PreviousCandidate,
Qt::Key_PreviousCandidate),
std::make_pair(XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special),
std::make_pair(XKB_KEY_Hangul_switch, Qt::Key_Mode_switch),
std::make_pair(XKB_KEY_dead_grave, Qt::Key_Dead_Grave),
std::make_pair(XKB_KEY_dead_acute, Qt::Key_Dead_Acute),
std::make_pair(XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex),
std::make_pair(XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde),
std::make_pair(XKB_KEY_dead_macron, Qt::Key_Dead_Macron),
std::make_pair(XKB_KEY_dead_breve, Qt::Key_Dead_Breve),
std::make_pair(XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot),
std::make_pair(XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis),
std::make_pair(XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering),
std::make_pair(XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute),
std::make_pair(XKB_KEY_dead_caron, Qt::Key_Dead_Caron),
std::make_pair(XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla),
std::make_pair(XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek),
std::make_pair(XKB_KEY_dead_iota, Qt::Key_Dead_Iota),
std::make_pair(XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound),
std::make_pair(XKB_KEY_dead_semivoiced_sound,
Qt::Key_Dead_Semivoiced_Sound),
std::make_pair(XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot),
std::make_pair(XKB_KEY_dead_hook, Qt::Key_Dead_Hook),
std::make_pair(XKB_KEY_dead_horn, Qt::Key_Dead_Horn),
std::make_pair(XKB_KEY_XF86Back, Qt::Key_Back),
std::make_pair(XKB_KEY_XF86Forward, Qt::Key_Forward),
std::make_pair(XKB_KEY_XF86Stop, Qt::Key_Stop),
std::make_pair(XKB_KEY_XF86Refresh, Qt::Key_Refresh),
std::make_pair(XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown),
std::make_pair(XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute),
std::make_pair(XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp),
std::make_pair(XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay),
std::make_pair(XKB_KEY_XF86AudioStop, Qt::Key_MediaStop),
std::make_pair(XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious),
std::make_pair(XKB_KEY_XF86AudioNext, Qt::Key_MediaNext),
std::make_pair(XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord),
std::make_pair(XKB_KEY_XF86AudioPause, Qt::Key_MediaPause),
std::make_pair(XKB_KEY_XF86HomePage, Qt::Key_HomePage),
std::make_pair(XKB_KEY_XF86Favorites, Qt::Key_Favorites),
std::make_pair(XKB_KEY_XF86Search, Qt::Key_Search),
std::make_pair(XKB_KEY_XF86Standby, Qt::Key_Standby),
std::make_pair(XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl),
std::make_pair(XKB_KEY_XF86Mail, Qt::Key_LaunchMail),
std::make_pair(XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia),
std::make_pair(XKB_KEY_XF86MyComputer, Qt::Key_Launch0),
std::make_pair(XKB_KEY_XF86Calculator, Qt::Key_Launch1),
std::make_pair(XKB_KEY_XF86Launch0, Qt::Key_Launch2),
std::make_pair(XKB_KEY_XF86Launch1, Qt::Key_Launch3),
std::make_pair(XKB_KEY_XF86Launch2, Qt::Key_Launch4),
std::make_pair(XKB_KEY_XF86Launch3, Qt::Key_Launch5),
std::make_pair(XKB_KEY_XF86Launch4, Qt::Key_Launch6),
std::make_pair(XKB_KEY_XF86Launch5, Qt::Key_Launch7),
std::make_pair(XKB_KEY_XF86Launch6, Qt::Key_Launch8),
std::make_pair(XKB_KEY_XF86Launch7, Qt::Key_Launch9),
std::make_pair(XKB_KEY_XF86Launch8, Qt::Key_LaunchA),
std::make_pair(XKB_KEY_XF86Launch9, Qt::Key_LaunchB),
std::make_pair(XKB_KEY_XF86LaunchA, Qt::Key_LaunchC),
std::make_pair(XKB_KEY_XF86LaunchB, Qt::Key_LaunchD),
std::make_pair(XKB_KEY_XF86LaunchC, Qt::Key_LaunchE),
std::make_pair(XKB_KEY_XF86LaunchD, Qt::Key_LaunchF),
std::make_pair(XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp),
std::make_pair(XKB_KEY_XF86MonBrightnessDown,
Qt::Key_MonBrightnessDown),
std::make_pair(XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff),
std::make_pair(XKB_KEY_XF86KbdBrightnessUp,
Qt::Key_KeyboardBrightnessUp),
std::make_pair(XKB_KEY_XF86KbdBrightnessDown,
Qt::Key_KeyboardBrightnessDown),
std::make_pair(XKB_KEY_XF86PowerOff, Qt::Key_PowerOff),
std::make_pair(XKB_KEY_XF86WakeUp, Qt::Key_WakeUp),
std::make_pair(XKB_KEY_XF86Eject, Qt::Key_Eject),
std::make_pair(XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver),
std::make_pair(XKB_KEY_XF86WWW, Qt::Key_WWW),
std::make_pair(XKB_KEY_XF86Memo, Qt::Key_Memo),
std::make_pair(XKB_KEY_XF86LightBulb, Qt::Key_LightBulb),
std::make_pair(XKB_KEY_XF86Shop, Qt::Key_Shop),
std::make_pair(XKB_KEY_XF86History, Qt::Key_History),
std::make_pair(XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite),
std::make_pair(XKB_KEY_XF86HotLinks, Qt::Key_HotLinks),
std::make_pair(XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust),
std::make_pair(XKB_KEY_XF86Finance, Qt::Key_Finance),
std::make_pair(XKB_KEY_XF86Community, Qt::Key_Community),
std::make_pair(XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind),
std::make_pair(XKB_KEY_XF86BackForward, Qt::Key_BackForward),
std::make_pair(XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft),
std::make_pair(XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight),
std::make_pair(XKB_KEY_XF86Book, Qt::Key_Book),
std::make_pair(XKB_KEY_XF86CD, Qt::Key_CD),
std::make_pair(XKB_KEY_XF86Calculater, Qt::Key_Calculator),
std::make_pair(XKB_KEY_XF86ToDoList, Qt::Key_ToDoList),
std::make_pair(XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab),
std::make_pair(XKB_KEY_XF86Close, Qt::Key_Close),
std::make_pair(XKB_KEY_XF86Copy, Qt::Key_Copy),
std::make_pair(XKB_KEY_XF86Cut, Qt::Key_Cut),
std::make_pair(XKB_KEY_XF86Display, Qt::Key_Display),
std::make_pair(XKB_KEY_XF86DOS, Qt::Key_DOS),
std::make_pair(XKB_KEY_XF86Documents, Qt::Key_Documents),
std::make_pair(XKB_KEY_XF86Excel, Qt::Key_Excel),
std::make_pair(XKB_KEY_XF86Explorer, Qt::Key_Explorer),
std::make_pair(XKB_KEY_XF86Game, Qt::Key_Game),
std::make_pair(XKB_KEY_XF86Go, Qt::Key_Go),
std::make_pair(XKB_KEY_XF86iTouch, Qt::Key_iTouch),
std::make_pair(XKB_KEY_XF86LogOff, Qt::Key_LogOff),
std::make_pair(XKB_KEY_XF86Market, Qt::Key_Market),
std::make_pair(XKB_KEY_XF86Meeting, Qt::Key_Meeting),
std::make_pair(XKB_KEY_XF86MenuKB, Qt::Key_MenuKB),
std::make_pair(XKB_KEY_XF86MenuPB, Qt::Key_MenuPB),
std::make_pair(XKB_KEY_XF86MySites, Qt::Key_MySites),
std::make_pair(XKB_KEY_XF86News, Qt::Key_News),
std::make_pair(XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome),
std::make_pair(XKB_KEY_XF86Option, Qt::Key_Option),
std::make_pair(XKB_KEY_XF86Paste, Qt::Key_Paste),
std::make_pair(XKB_KEY_XF86Phone, Qt::Key_Phone),
std::make_pair(XKB_KEY_XF86Calendar, Qt::Key_Calendar),
std::make_pair(XKB_KEY_XF86Reply, Qt::Key_Reply),
std::make_pair(XKB_KEY_XF86Reload, Qt::Key_Reload),
std::make_pair(XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows),
std::make_pair(XKB_KEY_XF86RotationPB, Qt::Key_RotationPB),
std::make_pair(XKB_KEY_XF86RotationKB, Qt::Key_RotationKB),
std::make_pair(XKB_KEY_XF86Save, Qt::Key_Save),
std::make_pair(XKB_KEY_XF86Send, Qt::Key_Send),
std::make_pair(XKB_KEY_XF86Spell, Qt::Key_Spell),
std::make_pair(XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen),
std::make_pair(XKB_KEY_XF86Support, Qt::Key_Support),
std::make_pair(XKB_KEY_XF86TaskPane, Qt::Key_TaskPane),
std::make_pair(XKB_KEY_XF86Terminal, Qt::Key_Terminal),
std::make_pair(XKB_KEY_XF86Tools, Qt::Key_Tools),
std::make_pair(XKB_KEY_XF86Travel, Qt::Key_Travel),
std::make_pair(XKB_KEY_XF86Video, Qt::Key_Video),
std::make_pair(XKB_KEY_XF86Word, Qt::Key_Word),
std::make_pair(XKB_KEY_XF86Xfer, Qt::Key_Xfer),
std::make_pair(XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn),
std::make_pair(XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut),
std::make_pair(XKB_KEY_XF86Away, Qt::Key_Away),
std::make_pair(XKB_KEY_XF86Messenger, Qt::Key_Messenger),
std::make_pair(XKB_KEY_XF86WebCam, Qt::Key_WebCam),
std::make_pair(XKB_KEY_XF86MailForward, Qt::Key_MailForward),
std::make_pair(XKB_KEY_XF86Pictures, Qt::Key_Pictures),
std::make_pair(XKB_KEY_XF86Music, Qt::Key_Music),
std::make_pair(XKB_KEY_XF86Battery, Qt::Key_Battery),
std::make_pair(XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth),
std::make_pair(XKB_KEY_XF86WLAN, Qt::Key_WLAN),
std::make_pair(XKB_KEY_XF86UWB, Qt::Key_UWB),
std::make_pair(XKB_KEY_XF86AudioForward, Qt::Key_AudioForward),
std::make_pair(XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat),
std::make_pair(XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay),
std::make_pair(XKB_KEY_XF86Subtitle, Qt::Key_Subtitle),
std::make_pair(XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack),
std::make_pair(XKB_KEY_XF86Time, Qt::Key_Time),
std::make_pair(XKB_KEY_XF86Hibernate, Qt::Key_Hibernate),
std::make_pair(XKB_KEY_XF86View, Qt::Key_View),
std::make_pair(XKB_KEY_XF86TopMenu, Qt::Key_TopMenu),
std::make_pair(XKB_KEY_XF86PowerDown, Qt::Key_PowerDown),
std::make_pair(XKB_KEY_XF86Suspend, Qt::Key_Suspend),
std::make_pair(XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust),
std::make_pair(XKB_KEY_XF86LaunchE, Qt::Key_LaunchG),
std::make_pair(XKB_KEY_XF86LaunchF, Qt::Key_LaunchH),
std::make_pair(XKB_KEY_XF86Select, Qt::Key_Select),
std::make_pair(XKB_KEY_Cancel, Qt::Key_Cancel),
std::make_pair(XKB_KEY_Execute, Qt::Key_Execute),
std::make_pair(XKB_KEY_XF86Sleep, Qt::Key_Sleep),
};
return keyTbl;
}
int keysymToQtKey(uint32_t key) {
auto iter = KeyTbl().find(key);
if (iter != KeyTbl().end()) {
return iter->second;
}
return 0;
}
int keysymToQtKey(uint32_t keysym, const QString &text) {
int code = 0;
if (keysym < 128) {
// upper-case key, if known
code = isprint((int)keysym) ? toupper((int)keysym) : 0;
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f &&
text.unicode()->unicode() != 0x7f &&
!(keysym >= XKB_KEY_dead_grave &&
keysym <= XKB_KEY_dead_currency)) {
code = text.unicode()->toUpper().unicode();
} else {
// any other keys
code = keysymToQtKey(keysym);
}
return code;
}

View File

@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _PLATFORMINPUTCONTEXT_QTKEY_H_
#define _PLATFORMINPUTCONTEXT_QTKEY_H_
#include <QString>
#include <cstdint>
int keysymToQtKey(uint32_t keysym, const QString &text);
#endif // _PLATFORMINPUTCONTEXT_QTKEY_H_

View File

@@ -0,0 +1,26 @@
find_package(Qt5Concurrent REQUIRED)
set(QUICKPHRASE_EDITOR_SRCS
main.cpp
model.cpp
editor.cpp
editordialog.cpp
batchdialog.cpp
filelistmodel.cpp
)
add_library(fcitx-quickphrase-editor5-qt5
MODULE ${QUICKPHRASE_EDITOR_SRCS})
set_target_properties(fcitx-quickphrase-editor5-qt5 PROPERTIES
OUTPUT_NAME fcitx-quickphrase-editor5
AUTOMOC TRUE AUTOUIC TRUE AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h"
)
target_link_libraries(fcitx-quickphrase-editor5-qt5
Fcitx5::Utils
Qt5::Core
Qt5::Gui
Qt5::Concurrent
Fcitx5Qt5::WidgetsAddons
)
install(TARGETS fcitx-quickphrase-editor5-qt5 DESTINATION ${CMAKE_INSTALL_LIBDIR}/fcitx5/qt5)

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/batchdialog.cpp

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/batchdialog.h

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/batchdialog.ui

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/editor.cpp

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/editor.h

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/editor.ui

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/editordialog.cpp

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/editordialog.h

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/editordialog.ui

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/filelistmodel.cpp

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/filelistmodel.h

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/main.cpp

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/main.h

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/model.cpp

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/model.h

View File

@@ -0,0 +1 @@
../../qt6/quickphrase-editor/quickphrase-editor.json

View File

@@ -0,0 +1,71 @@
ecm_setup_version(PROJECT VARIABLE_PREFIX FCITX5QT5WIDGETSADDONS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt5widgetsaddons_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5WidgetsAddonsConfigVersion.cmake"
SOVERSION 2)
# create a Config.cmake and a ConfigVersion.cmake file and install them
set(CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/Fcitx5Qt5WidgetsAddons")
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/Fcitx5Qt5WidgetsAddonsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5WidgetsAddonsConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5WidgetsAddonsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt5WidgetsAddonsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel )
install(EXPORT Fcitx5Qt5WidgetsAddonsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE Fcitx5Qt5WidgetsAddonsTargets.cmake NAMESPACE Fcitx5Qt5:: )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt5widgetsaddons_version.h
DESTINATION ${Fcitx5Qt5_INCLUDE_INSTALL_DIR} COMPONENT Devel )
set(widgetsaddons_SOURCES
fcitxqtconfiguifactory.cpp
fcitxqtconfiguiplugin.cpp
fcitxqtconfiguiwidget.cpp
fcitxqtkeysequencewidget.cpp
qtkeytrans.cpp
)
set(widgetsaddons_HEADERS
fcitxqtconfiguifactory.h
fcitxqtconfiguiplugin.h
fcitxqtconfiguiwidget.h
fcitxqtkeysequencewidget.h
fcitxqti18nhelper.h
)
set(fcitxqtwidgetsaddons_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${FCITX54_FCITX5_UTILS_INCLUDE_DIRS}
)
add_library(Fcitx5Qt5WidgetsAddons SHARED ${widgetsaddons_SOURCES})
generate_export_header(Fcitx5Qt5WidgetsAddons BASE_NAME Fcitx5Qt5WidgetsAddons)
add_library(Fcitx5Qt5::WidgetsAddons ALIAS Fcitx5Qt5WidgetsAddons)
target_include_directories(Fcitx5Qt5WidgetsAddons PUBLIC "$<BUILD_INTERFACE:${fcitxqtwidgetsaddons_INCLUDE_DIRS}>")
target_include_directories(Fcitx5Qt5WidgetsAddons INTERFACE "$<INSTALL_INTERFACE:${Fcitx5Qt5_INCLUDE_INSTALL_DIR}/Fcitx5QtWidgetsAddons>")
set_target_properties(Fcitx5Qt5WidgetsAddons
PROPERTIES VERSION ${FCITX5QT5WIDGETSADDONS_VERSION}
AUTOMOC TRUE
SOVERSION ${FCITX5QT5WIDGETSADDONS_SOVERSION}
EXPORT_NAME WidgetsAddons
)
target_link_libraries(Fcitx5Qt5WidgetsAddons
PUBLIC
Fcitx5::Utils
Qt5::Core
Qt5::Widgets
)
install(TARGETS Fcitx5Qt5WidgetsAddons EXPORT Fcitx5Qt5WidgetsAddonsTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES ${widgetsaddons_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt5widgetsaddons_export.h
DESTINATION "${Fcitx5Qt5_INCLUDE_INSTALL_DIR}/Fcitx5QtWidgetsAddons")

View File

@@ -0,0 +1,16 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Fcitx5Utils)
find_dependency(Qt5Core @REQUIRED_QT5_VERSION@)
find_dependency(Qt5Gui @REQUIRED_QT5_VERSION@)
find_dependency(Qt5Widgets @REQUIRED_QT5_VERSION@)
include("${CMAKE_CURRENT_LIST_DIR}/Fcitx5Qt5WidgetsAddonsTargets.cmake")
if(NOT TARGET Fcitx5Qt5::gui-wrapper)
add_executable(Fcitx5Qt5::gui-wrapper IMPORTED)
set_target_properties(Fcitx5Qt5::gui-wrapper PROPERTIES
IMPORTED_LOCATION "@CMAKE_INSTALL_FULL_LIBEXECDIR@/fcitx5-qt5-gui-wrapper")
endif()

View File

@@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "fcitxqtconfiguifactory.h"
#include "fcitxqtconfiguifactory_p.h"
#include "fcitxqtconfiguiplugin.h"
#include <QDebug>
#include <QDir>
#include <QLibrary>
#include <QPluginLoader>
#include <QStandardPaths>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/standardpath.h>
namespace fcitx {
namespace {
constexpr char addonConfigPrefix[] = "fcitx://config/addon/";
QString normalizePath(const QString &file) {
auto path = file;
if (path.startsWith(addonConfigPrefix)) {
path.remove(0, sizeof(addonConfigPrefix) - 1);
}
return path;
}
} // namespace
FcitxQtConfigUIFactoryPrivate::FcitxQtConfigUIFactoryPrivate(
FcitxQtConfigUIFactory *factory)
: QObject(factory), q_ptr(factory) {}
FcitxQtConfigUIFactoryPrivate::~FcitxQtConfigUIFactoryPrivate() {}
FcitxQtConfigUIFactory::FcitxQtConfigUIFactory(QObject *parent)
: QObject(parent), d_ptr(new FcitxQtConfigUIFactoryPrivate(this)) {
Q_D(FcitxQtConfigUIFactory);
d->scan();
}
FcitxQtConfigUIFactory::~FcitxQtConfigUIFactory() {}
FcitxQtConfigUIWidget *FcitxQtConfigUIFactory::create(const QString &file) {
Q_D(FcitxQtConfigUIFactory);
auto path = normalizePath(file);
auto loader = d->plugins_.value(path);
if (!loader) {
return nullptr;
}
auto instance =
qobject_cast<FcitxQtConfigUIFactoryInterface *>(loader->instance());
if (!instance) {
return nullptr;
}
return instance->create(path.section('/', 1));
}
bool FcitxQtConfigUIFactory::test(const QString &file) {
Q_D(FcitxQtConfigUIFactory);
auto path = normalizePath(file);
return d->plugins_.contains(path);
}
void FcitxQtConfigUIFactoryPrivate::scan() {
fcitx::StandardPath::global().scanFiles(
fcitx::StandardPath::Type::Addon, "qt5",
[this](const std::string &path, const std::string &dirPath, bool user) {
do {
if (user) {
break;
}
QDir dir(QString::fromLocal8Bit(dirPath.c_str()));
QFileInfo fi(
dir.filePath(QString::fromLocal8Bit(path.c_str())));
QString filePath = fi.filePath(); // file name with path
QString fileName = fi.fileName(); // just file name
if (!QLibrary::isLibrary(filePath)) {
break;
}
QPluginLoader *loader = new QPluginLoader(filePath, this);
if (loader->metaData().value("IID") !=
QLatin1String(FcitxQtConfigUIFactoryInterface_iid)) {
delete loader;
break;
}
auto metadata = loader->metaData().value("MetaData").toObject();
auto files = metadata.value("files").toVariant().toStringList();
auto addon = metadata.value("addon").toVariant().toString();
for (const auto &file : files) {
plugins_[addon + "/" + file] = loader;
}
} while (0);
return true;
});
}
} // namespace fcitx

View File

@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_H_
#include <QMap>
#include <QObject>
#include <QStringList>
#include "fcitx5qt5widgetsaddons_export.h"
#include "fcitxqtconfiguiplugin.h"
#include "fcitxqtconfiguiwidget.h"
namespace fcitx {
class FcitxQtConfigUIFactoryPrivate;
/**
* ui plugin factory.
**/
class FCITX5QT5WIDGETSADDONS_EXPORT FcitxQtConfigUIFactory : public QObject {
Q_OBJECT
public:
/**
* create a plugin factory
*
* @param parent object parent
**/
explicit FcitxQtConfigUIFactory(QObject *parent = 0);
virtual ~FcitxQtConfigUIFactory();
/**
* create widget based on file name, it might return 0 if there is no match
*
* @param file file name need to be configured
* @return FcitxQtConfigUIWidget*
**/
FcitxQtConfigUIWidget *create(const QString &file);
/**
* a simplified version of create, but it just test if there is a valid
*entry or not
*
* @param file file name
* @return bool
**/
bool test(const QString &file);
private:
FcitxQtConfigUIFactoryPrivate *d_ptr;
Q_DECLARE_PRIVATE(FcitxQtConfigUIFactory);
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_H_

View File

@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_P_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_P_H_
#include "fcitxqtconfiguifactory.h"
#include <QObject>
#include <QPluginLoader>
#include <qpluginloader.h>
namespace fcitx {
class FcitxQtConfigUIFactoryPrivate : public QObject {
Q_OBJECT
public:
FcitxQtConfigUIFactoryPrivate(FcitxQtConfigUIFactory *conn);
virtual ~FcitxQtConfigUIFactoryPrivate();
FcitxQtConfigUIFactory *const q_ptr;
Q_DECLARE_PUBLIC(FcitxQtConfigUIFactory);
private:
void scan();
QMap<QString, QPluginLoader *> plugins_;
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_P_H_

View File

@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "fcitxqtconfiguiplugin.h"
namespace fcitx {
FcitxQtConfigUIPlugin::FcitxQtConfigUIPlugin(QObject *parent)
: QObject(parent) {}
FcitxQtConfigUIPlugin::~FcitxQtConfigUIPlugin() {}
} // namespace fcitx

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIPLUGIN_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIPLUGIN_H_
#include "fcitx5qt5widgetsaddons_export.h"
#include <QObject>
#include <QString>
#include <QStringList>
namespace fcitx {
class FcitxQtConfigUIWidget;
/**
* interface for qt config ui
*/
struct FCITX5QT5WIDGETSADDONS_EXPORT FcitxQtConfigUIFactoryInterface {
/**
* create new widget based on key
*
* @see FcitxQtConfigUIPlugin::files
*
* @return plugin name
*/
virtual FcitxQtConfigUIWidget *create(const QString &key) = 0;
};
#define FcitxQtConfigUIFactoryInterface_iid \
"org.fcitx.Fcitx.FcitxQtConfigUIFactoryInterface"
} // namespace fcitx
Q_DECLARE_INTERFACE(fcitx::FcitxQtConfigUIFactoryInterface,
FcitxQtConfigUIFactoryInterface_iid)
namespace fcitx {
/**
* base class for qt config ui
*/
class FCITX5QT5WIDGETSADDONS_EXPORT FcitxQtConfigUIPlugin
: public QObject,
public FcitxQtConfigUIFactoryInterface {
Q_OBJECT
Q_INTERFACES(fcitx::FcitxQtConfigUIFactoryInterface)
public:
explicit FcitxQtConfigUIPlugin(QObject *parent = 0);
virtual ~FcitxQtConfigUIPlugin();
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIPLUGIN_H_

View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "fcitxqtconfiguiwidget.h"
namespace fcitx {
FcitxQtConfigUIWidget::FcitxQtConfigUIWidget(QWidget *parent)
: QWidget(parent) {}
QString FcitxQtConfigUIWidget::icon() { return QLatin1String("fcitx"); }
bool FcitxQtConfigUIWidget::asyncSave() { return false; }
} // namespace fcitx

View File

@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIWIDGET_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIWIDGET_H_
#include "fcitx5qt5widgetsaddons_export.h"
#include <QtWidgets/QWidget>
namespace fcitx {
/**
* embedded gui for custom configuration
**/
class FCITX5QT5WIDGETSADDONS_EXPORT FcitxQtConfigUIWidget : public QWidget {
Q_OBJECT
public:
explicit FcitxQtConfigUIWidget(QWidget *parent = 0);
/**
* load the configuration, usually, this is being called upon a "reset"
*button clicked
* the outer gui will not call it for you for the first time, your
*initialization might
* want to call it by yourself.
*
* @return void
**/
virtual void load() = 0;
/**
* save the configuration
*
* @see asyncSave saveFinished
**/
virtual void save() = 0;
/**
* window title
*
* @return window title
**/
virtual QString title() = 0;
/**
* return the icon name of the window, see QIcon::fromTheme
*
* @return icon name
**/
virtual QString icon();
/**
* return the save function is async or not, default implementation is false
*
* @return bool
**/
virtual bool asyncSave();
Q_SIGNALS:
/**
* the configuration is changed or not, used to indicate parent gui
*
* @param changed is config changed
**/
void changed(bool changed);
/**
* if asyncSave return true, be sure to Q_EMIT this signal on all case
*
* @see asyncSave
**/
void saveFinished();
/// Save config for a specified path.
void saveSubConfig(const QString &path);
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIWIDGET_H_

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _WIDGETSADDONS_FCITXQTI18NHELPER_H_
#define _WIDGETSADDONS_FCITXQTI18NHELPER_H_
#include <QString>
#include <fcitx-utils/i18n.h>
namespace fcitx {
inline QString tr2fcitx(const char *message, const char *comment = nullptr) {
if (comment && comment[0] && message && message[0]) {
return QString(C_(comment, message));
} else if (message && message[0]) {
return QString(_(message));
} else {
return QString();
}
}
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTI18NHELPER_H_

View File

@@ -0,0 +1,604 @@
/*
* SPDX-FileCopyrightText: 2013~2020 CSSlayer <wengxt@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*/
/* this is forked from kdelibs/kdeui/kkeysequencewidget.cpp */
/*
Original Copyright header
SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org>
SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "fcitxqtkeysequencewidget.h"
#include "fcitxqtkeysequencewidget_p.h"
#include "qtkeytrans.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QHash>
#include <QKeyEvent>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QTimer>
#include <QToolButton>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/key.h>
Q_LOGGING_CATEGORY(fcitx5qtKeysequenceWidget, "fcitx5.qt.keysequencewidget")
namespace fcitx {
namespace {
bool isX11LikePlatform() {
return QGuiApplication::platformName() == "xcb" ||
QGuiApplication::platformName().startsWith("wayland");
}
bool keyQtToFcitx(int keyQt, const QString &text, FcitxQtModifierSide side,
Key &outkey) {
int key = keyQt & (~Qt::KeyboardModifierMask);
int state = keyQt & Qt::KeyboardModifierMask;
int sym;
unsigned int states;
if (!keyQtToSym(key, Qt::KeyboardModifiers(state), text, sym, states)) {
return false;
}
if (side == MS_Right) {
switch (sym) {
case FcitxKey_Control_L:
sym = FcitxKey_Control_R;
break;
case FcitxKey_Alt_L:
sym = FcitxKey_Alt_R;
break;
case FcitxKey_Shift_L:
sym = FcitxKey_Shift_R;
break;
case FcitxKey_Super_L:
sym = FcitxKey_Super_R;
break;
}
}
outkey = Key(static_cast<KeySym>(sym), KeyStates(states));
return true;
}
} // namespace
class FcitxQtKeySequenceWidgetPrivate {
public:
FcitxQtKeySequenceWidgetPrivate(FcitxQtKeySequenceWidget *q);
void init();
static bool isOkWhenModifierless(int keyQt);
void updateShortcutDisplay();
void startRecording();
void controlModifierlessTimout() {
if (keySequence_.size() != 0 && !modifierKeys_) {
// No modifier key pressed currently. Start the timout
modifierlessTimeout_.start(600);
} else {
// A modifier is pressed. Stop the timeout
modifierlessTimeout_.stop();
}
}
void cancelRecording() {
keySequence_ = oldKeySequence_;
doneRecording();
}
// private slot
void doneRecording();
// members
FcitxQtKeySequenceWidget *const q;
QHBoxLayout *layout_ = nullptr;
FcitxQtKeySequenceButton *keyButton_ = nullptr;
QToolButton *clearButton_ = nullptr;
QAction *keyCodeModeAction_ = nullptr;
QList<Key> keySequence_;
QList<Key> oldKeySequence_;
QTimer modifierlessTimeout_;
bool allowModifierless_ = false;
KeyStates modifierKeys_;
unsigned int qtModifierKeys_ = 0;
bool isRecording_ = false;
bool multiKeyShortcutsAllowed_ = false;
bool allowModifierOnly_ = false;
bool modifierAllowed_ = true;
bool keycodeAllowed_ = true;
};
FcitxQtKeySequenceWidgetPrivate::FcitxQtKeySequenceWidgetPrivate(
FcitxQtKeySequenceWidget *q)
: q(q) {}
FcitxQtKeySequenceWidget::FcitxQtKeySequenceWidget(QWidget *parent)
: QWidget(parent), d(new FcitxQtKeySequenceWidgetPrivate(this)) {
d->init();
setFocusProxy(d->keyButton_);
connect(d->keyButton_, &QPushButton::clicked, this,
&FcitxQtKeySequenceWidget::captureKeySequence);
connect(d->clearButton_, &QPushButton::clicked, this,
&FcitxQtKeySequenceWidget::clearKeySequence);
connect(&d->modifierlessTimeout_, &QTimer::timeout, this,
[this]() { d->doneRecording(); });
d->updateShortcutDisplay();
}
void FcitxQtKeySequenceWidgetPrivate::init() {
layout_ = new QHBoxLayout(q);
layout_->setContentsMargins(0, 0, 0, 0);
keyButton_ = new FcitxQtKeySequenceButton(this, q);
keyButton_->setFocusPolicy(Qt::StrongFocus);
keyButton_->setIcon(QIcon::fromTheme("configure"));
layout_->addWidget(keyButton_);
clearButton_ = new QToolButton(q);
layout_->addWidget(clearButton_);
keyCodeModeAction_ = new QAction(_("Key code mode"));
keyCodeModeAction_->setCheckable(true);
keyCodeModeAction_->setEnabled(isX11LikePlatform());
q->setContextMenuPolicy(Qt::ActionsContextMenu);
q->addAction(keyCodeModeAction_);
if (qApp->isLeftToRight())
clearButton_->setIcon(QIcon::fromTheme("edit-clear-locationbar-rtl"));
else
clearButton_->setIcon(QIcon::fromTheme("edit-clear-locationbar-ltr"));
q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
}
FcitxQtKeySequenceWidget::~FcitxQtKeySequenceWidget() { delete d; }
bool FcitxQtKeySequenceWidget::multiKeyShortcutsAllowed() const {
return d->multiKeyShortcutsAllowed_;
}
void FcitxQtKeySequenceWidget::setMultiKeyShortcutsAllowed(bool allowed) {
d->multiKeyShortcutsAllowed_ = allowed;
}
bool FcitxQtKeySequenceWidget::isModifierAllowed() const {
return d->modifierAllowed_;
}
void FcitxQtKeySequenceWidget::setModifierAllowed(bool allowed) {
d->modifierAllowed_ = allowed;
}
bool FcitxQtKeySequenceWidget::isKeycodeAllowed() const {
return d->keycodeAllowed_;
}
void FcitxQtKeySequenceWidget::setKeycodeAllowed(bool allowed) {
if (d->keycodeAllowed_ == allowed) {
return;
}
d->keycodeAllowed_ = allowed;
if (allowed) {
d->keyCodeModeAction_->setChecked(false);
addAction(d->keyCodeModeAction_);
} else {
removeAction(d->keyCodeModeAction_);
}
}
void FcitxQtKeySequenceWidget::setModifierlessAllowed(bool allow) {
d->allowModifierless_ = allow;
}
bool FcitxQtKeySequenceWidget::isModifierlessAllowed() {
return d->allowModifierless_;
}
bool FcitxQtKeySequenceWidget::isModifierOnlyAllowed() {
return d->allowModifierOnly_;
}
bool FcitxQtKeySequenceWidget::isModifierlessAllowed() const {
return d->allowModifierless_;
}
bool FcitxQtKeySequenceWidget::isModifierOnlyAllowed() const {
return d->allowModifierOnly_;
}
void FcitxQtKeySequenceWidget::setModifierOnlyAllowed(bool allow) {
d->allowModifierOnly_ = allow;
}
void FcitxQtKeySequenceWidget::setClearButtonShown(bool show) {
d->clearButton_->setVisible(show);
}
bool FcitxQtKeySequenceWidget::isClearButtonVisible() const {
return d->clearButton_->isVisible();
}
// slot
void FcitxQtKeySequenceWidget::captureKeySequence() { d->startRecording(); }
const QList<Key> &FcitxQtKeySequenceWidget::keySequence() const {
return d->keySequence_;
}
// slot
void FcitxQtKeySequenceWidget::setKeySequence(const QList<Key> &seq) {
// oldKeySequence holds the key sequence before recording started, if
// setKeySequence()
// is called while not recording then set oldKeySequence to the existing
// sequence so
// that the keySequenceChanged() signal is emitted if the new and previous
// key
// sequences are different
if (!d->isRecording_) {
d->oldKeySequence_ = d->keySequence_;
}
d->keySequence_ = QList<Key>();
for (auto key : seq) {
d->keySequence_ << key;
}
d->doneRecording();
}
// slot
void FcitxQtKeySequenceWidget::clearKeySequence() {
setKeySequence(QList<Key>());
}
void FcitxQtKeySequenceWidgetPrivate::startRecording() {
modifierKeys_ = 0;
oldKeySequence_ = keySequence_;
keySequence_ = QList<Key>();
isRecording_ = true;
keyButton_->grabKeyboard();
if (!QWidget::keyboardGrabber()) {
qWarning() << "Failed to grab the keyboard! Most likely qt's nograb "
"option is active";
}
keyButton_->setDown(true);
updateShortcutDisplay();
}
void FcitxQtKeySequenceWidgetPrivate::doneRecording() {
modifierlessTimeout_.stop();
isRecording_ = false;
keyButton_->releaseKeyboard();
keyButton_->setDown(false);
if (keySequence_ == oldKeySequence_ && !allowModifierOnly_) {
// The sequence hasn't changed
updateShortcutDisplay();
return;
}
Q_EMIT q->keySequenceChanged(keySequence_);
updateShortcutDisplay();
}
void FcitxQtKeySequenceWidgetPrivate::updateShortcutDisplay() {
QString s = QString::fromUtf8(
Key::keyListToString(keySequence_, KeyStringFormat::Localized).c_str());
s.replace('&', QLatin1String("&&"));
if (isRecording_) {
if (modifierKeys_) {
if (!s.isEmpty())
s.append(",");
if (modifierKeys_ & KeyState::Super)
s += "Super+";
if (modifierKeys_ & KeyState::Ctrl)
s += "Control+";
if (modifierKeys_ & KeyState::Alt)
s += "Alt+";
if (modifierKeys_ & KeyState::Shift)
s += "Shift+";
if (modifierKeys_ & KeyState::Hyper)
s += "Hyper+";
} else if (keySequence_.size() == 0) {
s = "...";
}
// make it clear that input is still going on
s.append(" ...");
}
if (s.isEmpty()) {
s = _("Empty");
}
s.prepend(' ');
s.append(' ');
keyButton_->setText(s);
}
FcitxQtKeySequenceButton::~FcitxQtKeySequenceButton() {}
// prevent Qt from special casing Tab and Backtab
bool FcitxQtKeySequenceButton::event(QEvent *e) {
if (d->isRecording_ && e->type() == QEvent::KeyPress) {
keyPressEvent(static_cast<QKeyEvent *>(e));
return true;
}
// The shortcut 'alt+c' ( or any other dialog local action shortcut )
// ended the recording and triggered the action associated with the
// action. In case of 'alt+c' ending the dialog. It seems that those
// ShortcutOverride events get sent even if grabKeyboard() is active.
if (d->isRecording_ && e->type() == QEvent::ShortcutOverride) {
e->accept();
return true;
}
return QPushButton::event(e);
}
void FcitxQtKeySequenceButton::keyPressEvent(QKeyEvent *e) {
int keyQt = e->key();
if (keyQt == -1) {
// Qt sometimes returns garbage keycodes, I observed -1, if it doesn't
// know a key. We cannot do anything useful with those (several keys
// have -1, indistinguishable) and QKeySequence.toString() will also
// yield a garbage string.
QMessageBox::warning(
this, _("The key you just pressed is not supported by Qt."),
_("Unsupported Key"));
return d->cancelRecording();
}
// Same as Key::normalize();
unsigned int newQtModifiers =
e->modifiers() & (Qt::META | Qt::ALT | Qt::CTRL | Qt::SHIFT);
KeyStates newModifiers;
if (isX11LikePlatform()) {
newModifiers = KeyStates(e->nativeModifiers()) &
KeyStates{KeyState::Ctrl_Alt_Shift, KeyState::Hyper,
KeyState::Super};
newModifiers |=
Key::keySymToStates(static_cast<KeySym>(e->nativeVirtualKey()));
} else {
if (newQtModifiers & Qt::META) {
newModifiers |= KeyState::Super;
}
if (newQtModifiers & Qt::ALT) {
newModifiers |= KeyState::Alt;
}
if (newQtModifiers & Qt::CTRL) {
newModifiers |= KeyState::Ctrl;
}
if (newQtModifiers & Qt::SHIFT) {
newModifiers |= KeyState::Shift;
}
}
// don't have the return or space key appear as first key of the sequence
// when they
// were pressed to start editing - catch and them and imitate their effect
if (!d->isRecording_ &&
((keyQt == Qt::Key_Return || keyQt == Qt::Key_Space))) {
d->startRecording();
d->modifierKeys_ = newModifiers;
d->qtModifierKeys_ = newQtModifiers;
d->updateShortcutDisplay();
return;
}
// We get events even if recording isn't active.
if (!d->isRecording_)
return QPushButton::keyPressEvent(e);
e->accept();
d->modifierKeys_ = newModifiers;
d->qtModifierKeys_ = newQtModifiers;
switch (keyQt) {
case Qt::Key_AltGr: // or else we get unicode salad
return;
case Qt::Key_Shift:
case Qt::Key_Control:
case Qt::Key_Alt:
case Qt::Key_Super_L:
case Qt::Key_Super_R:
case Qt::Key_Hyper_L:
case Qt::Key_Hyper_R:
case Qt::Key_Meta:
case Qt::Key_Menu: // unused (yes, but why?)
d->controlModifierlessTimout();
d->updateShortcutDisplay();
break;
default:
// We now have a valid key press.
if (keyQt) {
if ((keyQt == Qt::Key_Backtab) &&
d->modifierKeys_.test(KeyState::Shift)) {
keyQt = Qt::Key_Tab | d->qtModifierKeys_;
} else {
keyQt |= d->qtModifierKeys_;
}
Key key;
if (d->keyCodeModeAction_->isChecked()) {
key = Key::fromKeyCode(e->nativeScanCode(), d->modifierKeys_);
} else {
if (isX11LikePlatform()) {
key = Key(static_cast<KeySym>(e->nativeVirtualKey()),
KeyStates(e->nativeModifiers()))
.normalize();
} else {
if (!keyQtToFcitx(keyQt, e->text(), MS_Unknown, key)) {
qCDebug(fcitx5qtKeysequenceWidget)
<< "FcitxQtKeySequenceButton::keyPressEvent() "
"Failed to "
"convert Qt key to fcitx: "
<< e;
}
}
}
// Check the first key.
if (d->keySequence_.size() == 0) {
if (!d->allowModifierless_ && key.states() == 0) {
return;
}
if (!d->modifierAllowed_ && key.states() != 0) {
return;
}
}
if (key.isValid()) {
d->keySequence_ << key;
}
if ((!d->multiKeyShortcutsAllowed_) ||
(d->keySequence_.size() >= 4)) {
d->doneRecording();
return;
}
d->controlModifierlessTimout();
d->updateShortcutDisplay();
}
}
}
void FcitxQtKeySequenceButton::keyReleaseEvent(QKeyEvent *e) {
if (e->key() == -1) {
// ignore garbage, see keyPressEvent()
return;
}
if (!d->isRecording_)
return QPushButton::keyReleaseEvent(e);
e->accept();
if (!d->multiKeyShortcutsAllowed_ && d->allowModifierOnly_ &&
(e->key() == Qt::Key_Shift || e->key() == Qt::Key_Control ||
e->key() == Qt::Key_Meta || e->key() == Qt::Key_Alt)) {
auto side = MS_Unknown;
if (isX11LikePlatform()) {
if (e->nativeVirtualKey() == FcitxKey_Control_L ||
e->nativeVirtualKey() == FcitxKey_Alt_L ||
e->nativeVirtualKey() == FcitxKey_Shift_L ||
e->nativeVirtualKey() == FcitxKey_Super_L) {
side = MS_Left;
}
if (e->nativeVirtualKey() == FcitxKey_Control_R ||
e->nativeVirtualKey() == FcitxKey_Alt_R ||
e->nativeVirtualKey() == FcitxKey_Shift_R ||
e->nativeVirtualKey() == FcitxKey_Super_R) {
side = MS_Right;
}
}
int keyQt = e->key() | d->qtModifierKeys_;
Key key;
if (keyQtToFcitx(keyQt, e->text(), side, key)) {
if (d->keyCodeModeAction_->isChecked()) {
key = Key::fromKeyCode(e->nativeScanCode(), key.states());
}
d->keySequence_ = QList<Key>({key});
}
d->doneRecording();
return;
}
unsigned int newQtModifiers =
e->modifiers() & (Qt::META | Qt::ALT | Qt::CTRL | Qt::SHIFT);
KeyStates newModifiers;
if (isX11LikePlatform()) {
newModifiers = KeyStates(e->nativeModifiers()) &
KeyStates{KeyState::Ctrl_Alt_Shift, KeyState::Hyper,
KeyState::Super};
newModifiers &=
~Key::keySymToStates(static_cast<KeySym>(e->nativeVirtualKey()));
} else {
if (newQtModifiers & Qt::META) {
newModifiers |= KeyState::Super;
}
if (newQtModifiers & Qt::ALT) {
newModifiers |= KeyState::Alt;
}
if (newQtModifiers & Qt::CTRL) {
newModifiers |= KeyState::Ctrl;
}
if (newQtModifiers & Qt::SHIFT) {
newModifiers |= KeyState::Shift;
}
}
// if a modifier that belongs to the shortcut was released...
if ((newModifiers & d->modifierKeys_) < d->modifierKeys_) {
d->modifierKeys_ = newModifiers;
d->controlModifierlessTimout();
d->updateShortcutDisplay();
}
}
// static
bool FcitxQtKeySequenceWidgetPrivate::isOkWhenModifierless(int keyQt) {
// this whole function is a hack, but especially the first line of code
if (QKeySequence(keyQt).toString().length() == 1)
return false;
switch (keyQt) {
case Qt::Key_Return:
case Qt::Key_Space:
case Qt::Key_Tab:
case Qt::Key_Backtab: // does this ever happen?
case Qt::Key_Backspace:
case Qt::Key_Delete:
return false;
default:
return true;
}
}
} // namespace fcitx
#include "moc_fcitxqtkeysequencewidget.cpp"

View File

@@ -0,0 +1,154 @@
/*
* SPDX-FileCopyrightText: 2013~2017 CSSlayer <wengxt@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*/
#ifndef _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_H_
#define _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_H_
/* this is forked from kdelibs/kdeui/kkeysequencewidget.h */
/*
Original Copyright header
This file is part of the KDE libraries
SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QList>
#include <QPushButton>
#include <fcitx-utils/key.h>
#include "fcitx5qt5widgetsaddons_export.h"
namespace fcitx {
enum FcitxQtModifierSide { MS_Unknown = 0, MS_Left = 1, MS_Right = 2 };
class FcitxQtKeySequenceWidgetPrivate;
class FCITX5QT5WIDGETSADDONS_EXPORT FcitxQtKeySequenceWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(bool multiKeyShortcutsAllowed READ multiKeyShortcutsAllowed WRITE
setMultiKeyShortcutsAllowed)
Q_PROPERTY(bool modifierlessAllowed READ isModifierlessAllowed WRITE
setModifierlessAllowed)
Q_PROPERTY(
bool modifierAllowed READ isModifierAllowed WRITE setModifierAllowed)
Q_PROPERTY(
bool keycodeAllowed READ isKeycodeAllowed WRITE setKeycodeAllowed)
Q_PROPERTY(bool modifierOnlyAllowed READ isModifierOnlyAllowed WRITE
setModifierOnlyAllowed)
public:
/**
* Constructor.
*/
explicit FcitxQtKeySequenceWidget(QWidget *parent = 0);
/**
* Destructs the widget.
*/
virtual ~FcitxQtKeySequenceWidget();
/**
* @brief Set whether allow multiple shortcuts.
*
* @param allow
*/
void setMultiKeyShortcutsAllowed(bool allow);
bool multiKeyShortcutsAllowed() const;
/**
* @brief Set whether allow modifier less that produce text, such as just
* key A.
*
* @param allow
*/
void setModifierlessAllowed(bool allow);
// FIXME: remove this
bool isModifierlessAllowed();
bool isModifierlessAllowed() const;
/**
* @brief Set whether allow key that has modifier.
*
* @param allow
* @since 5.0.12
*/
void setModifierAllowed(bool allow);
bool isModifierAllowed() const;
/**
* @brief Set whether allow key to use key code.
*
* @param allow
* @since 5.0.12
*/
void setKeycodeAllowed(bool allow);
bool isKeycodeAllowed() const;
/**
* @brief Set whether allow modifier only key, such as only left control.
*
* @param allow allow modifier only key to be captured.
*/
void setModifierOnlyAllowed(bool allow);
// FIXME: remove this
bool isModifierOnlyAllowed();
bool isModifierOnlyAllowed() const;
void setClearButtonShown(bool show);
bool isClearButtonVisible() const;
const QList<Key> &keySequence() const;
Q_SIGNALS:
void keySequenceChanged(const QList<Key> &seq);
public Q_SLOTS:
void captureKeySequence();
void setKeySequence(const QList<Key> &seq);
void clearKeySequence();
private:
friend class FcitxQtKeySequenceWidgetPrivate;
FcitxQtKeySequenceWidgetPrivate *const d;
Q_DISABLE_COPY(FcitxQtKeySequenceWidget)
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_H_

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*/
#ifndef _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_P_H_
#define _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_P_H_
/* this is forked from kdelibs/kdeui/kkeysequencewidget_p.h */
/*
Original Copyright header
SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QAction>
#include <QHBoxLayout>
#include <QPushButton>
#include <QToolButton>
namespace fcitx {
class FcitxQtKeySequenceWidgetPrivate;
class FcitxQtKeySequenceButton : public QPushButton {
Q_OBJECT
public:
explicit FcitxQtKeySequenceButton(FcitxQtKeySequenceWidgetPrivate *d,
QWidget *parent)
: QPushButton(parent), d(d) {}
virtual ~FcitxQtKeySequenceButton();
protected:
/**
* Reimplemented for internal reasons.
*/
bool event(QEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
private:
FcitxQtKeySequenceWidgetPrivate *const d;
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_P_H_

View File

@@ -0,0 +1,773 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "qtkeytrans.h"
#include "qtkeytransdata.h"
#include <QDebug>
#include <QTextCodec>
#include <ctype.h>
#include <fcitx-utils/key.h>
#define _ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define _ARRAY_END(a) (a + _ARRAY_SIZE(a))
namespace fcitx {
void qEventToSym(int key, Qt::KeyboardModifiers mod, const QString &text,
int &outsym, unsigned int &outstate) {
int sym = 0;
fcitx::KeyStates state;
do {
if (text.length() <= 0)
break;
int uni = text[0].unicode();
int *result =
std::lower_bound(unicodeHasKey, _ARRAY_END(unicodeHasKey), uni);
if (result != _ARRAY_END(unicodeHasKey) && *result == uni) {
sym = *result + 0x1000000;
break;
}
Unicode2Key *keyMap =
std::lower_bound(unicodeKeyMap, _ARRAY_END(unicodeKeyMap), uni);
if (keyMap != _ARRAY_END(unicodeKeyMap) && keyMap->unicode == uni) {
sym = keyMap->key;
break;
}
} while (0);
do {
if (sym)
break;
QtCode2Key *result = nullptr;
if (mod & Qt::KeypadModifier) {
result = std::lower_bound(keyPadQtCodeToKey,
_ARRAY_END(keyPadQtCodeToKey), key);
if (result == _ARRAY_END(keyPadQtCodeToKey) ||
result->qtcode != key)
result = nullptr;
} else {
if (text.isEmpty() || !text[0].isPrint()) {
result = std::lower_bound(qtCodeToKeyBackup,
_ARRAY_END(qtCodeToKeyBackup), key);
if (result == _ARRAY_END(qtCodeToKeyBackup) ||
result->qtcode != key)
result = nullptr;
}
if (!result) {
result =
std::lower_bound(qtCodeToKey, _ARRAY_END(qtCodeToKey), key);
if (result == _ARRAY_END(qtCodeToKey) || result->qtcode != key)
result = nullptr;
}
if (!result) {
result = std::lower_bound(keyPadQtCodeToKey,
_ARRAY_END(keyPadQtCodeToKey), key);
if (result == _ARRAY_END(keyPadQtCodeToKey) ||
result->qtcode != key)
result = nullptr;
}
}
if (result)
sym = result->key;
} while (0);
state = fcitx::KeyState::NoState;
if (mod & Qt::CTRL)
state |= fcitx::KeyState::Ctrl;
if (mod & Qt::ALT)
state |= fcitx::KeyState::Alt;
if (mod & Qt::SHIFT)
state |= fcitx::KeyState::Shift;
if (mod & Qt::META)
state |= fcitx::KeyState::Super;
outsym = sym;
outstate = state;
}
// the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining
// some special
// multimedia keys. They are included here as not every system has them.
#define XF86FcitxKey_MonBrightnessUp 0x1008FF02
#define XF86FcitxKey_MonBrightnessDown 0x1008FF03
#define XF86FcitxKey_KbdLightOnOff 0x1008FF04
#define XF86FcitxKey_KbdBrightnessUp 0x1008FF05
#define XF86FcitxKey_KbdBrightnessDown 0x1008FF06
#define XF86FcitxKey_Standby 0x1008FF10
#define XF86FcitxKey_AudioLowerVolume 0x1008FF11
#define XF86FcitxKey_AudioMute 0x1008FF12
#define XF86FcitxKey_AudioRaiseVolume 0x1008FF13
#define XF86FcitxKey_AudioPlay 0x1008FF14
#define XF86FcitxKey_AudioStop 0x1008FF15
#define XF86FcitxKey_AudioPrev 0x1008FF16
#define XF86FcitxKey_AudioNext 0x1008FF17
#define XF86FcitxKey_HomePage 0x1008FF18
#define XF86FcitxKey_Mail 0x1008FF19
#define XF86FcitxKey_Start 0x1008FF1A
#define XF86FcitxKey_Search 0x1008FF1B
#define XF86FcitxKey_AudioRecord 0x1008FF1C
#define XF86FcitxKey_Calculator 0x1008FF1D
#define XF86FcitxKey_Memo 0x1008FF1E
#define XF86FcitxKey_ToDoList 0x1008FF1F
#define XF86FcitxKey_Calendar 0x1008FF20
#define XF86FcitxKey_PowerDown 0x1008FF21
#define XF86FcitxKey_ContrastAdjust 0x1008FF22
#define XF86FcitxKey_Back 0x1008FF26
#define XF86FcitxKey_Forward 0x1008FF27
#define XF86FcitxKey_Stop 0x1008FF28
#define XF86FcitxKey_Refresh 0x1008FF29
#define XF86FcitxKey_PowerOff 0x1008FF2A
#define XF86FcitxKey_WakeUp 0x1008FF2B
#define XF86FcitxKey_Eject 0x1008FF2C
#define XF86FcitxKey_ScreenSaver 0x1008FF2D
#define XF86FcitxKey_WWW 0x1008FF2E
#define XF86FcitxKey_Sleep 0x1008FF2F
#define XF86FcitxKey_Favorites 0x1008FF30
#define XF86FcitxKey_AudioPause 0x1008FF31
#define XF86FcitxKey_AudioMedia 0x1008FF32
#define XF86FcitxKey_MyComputer 0x1008FF33
#define XF86FcitxKey_LightBulb 0x1008FF35
#define XF86FcitxKey_Shop 0x1008FF36
#define XF86FcitxKey_History 0x1008FF37
#define XF86FcitxKey_OpenURL 0x1008FF38
#define XF86FcitxKey_AddFavorite 0x1008FF39
#define XF86FcitxKey_HotLinks 0x1008FF3A
#define XF86FcitxKey_BrightnessAdjust 0x1008FF3B
#define XF86FcitxKey_Finance 0x1008FF3C
#define XF86FcitxKey_Community 0x1008FF3D
#define XF86FcitxKey_AudioRewind 0x1008FF3E
#define XF86FcitxKey_BackForward 0x1008FF3F
#define XF86FcitxKey_Launch0 0x1008FF40
#define XF86FcitxKey_Launch1 0x1008FF41
#define XF86FcitxKey_Launch2 0x1008FF42
#define XF86FcitxKey_Launch3 0x1008FF43
#define XF86FcitxKey_Launch4 0x1008FF44
#define XF86FcitxKey_Launch5 0x1008FF45
#define XF86FcitxKey_Launch6 0x1008FF46
#define XF86FcitxKey_Launch7 0x1008FF47
#define XF86FcitxKey_Launch8 0x1008FF48
#define XF86FcitxKey_Launch9 0x1008FF49
#define XF86FcitxKey_LaunchA 0x1008FF4A
#define XF86FcitxKey_LaunchB 0x1008FF4B
#define XF86FcitxKey_LaunchC 0x1008FF4C
#define XF86FcitxKey_LaunchD 0x1008FF4D
#define XF86FcitxKey_LaunchE 0x1008FF4E
#define XF86FcitxKey_LaunchF 0x1008FF4F
#define XF86FcitxKey_ApplicationLeft 0x1008FF50
#define XF86FcitxKey_ApplicationRight 0x1008FF51
#define XF86FcitxKey_Book 0x1008FF52
#define XF86FcitxKey_CD 0x1008FF53
#define XF86FcitxKey_Calculater 0x1008FF54
#define XF86FcitxKey_Clear 0x1008FF55
#define XF86FcitxKey_ClearGrab 0x1008FE21
#define XF86FcitxKey_Close 0x1008FF56
#define XF86FcitxKey_Copy 0x1008FF57
#define XF86FcitxKey_Cut 0x1008FF58
#define XF86FcitxKey_Display 0x1008FF59
#define XF86FcitxKey_DOS 0x1008FF5A
#define XF86FcitxKey_Documents 0x1008FF5B
#define XF86FcitxKey_Excel 0x1008FF5C
#define XF86FcitxKey_Explorer 0x1008FF5D
#define XF86FcitxKey_Game 0x1008FF5E
#define XF86FcitxKey_Go 0x1008FF5F
#define XF86FcitxKey_iTouch 0x1008FF60
#define XF86FcitxKey_LogOff 0x1008FF61
#define XF86FcitxKey_Market 0x1008FF62
#define XF86FcitxKey_Meeting 0x1008FF63
#define XF86FcitxKey_MenuKB 0x1008FF65
#define XF86FcitxKey_MenuPB 0x1008FF66
#define XF86FcitxKey_MySites 0x1008FF67
#define XF86FcitxKey_News 0x1008FF69
#define XF86FcitxKey_OfficeHome 0x1008FF6A
#define XF86FcitxKey_Option 0x1008FF6C
#define XF86FcitxKey_Paste 0x1008FF6D
#define XF86FcitxKey_Phone 0x1008FF6E
#define XF86FcitxKey_Reply 0x1008FF72
#define XF86FcitxKey_Reload 0x1008FF73
#define XF86FcitxKey_RotateWindows 0x1008FF74
#define XF86FcitxKey_RotationPB 0x1008FF75
#define XF86FcitxKey_RotationKB 0x1008FF76
#define XF86FcitxKey_Save 0x1008FF77
#define XF86FcitxKey_Send 0x1008FF7B
#define XF86FcitxKey_Spell 0x1008FF7C
#define XF86FcitxKey_SplitScreen 0x1008FF7D
#define XF86FcitxKey_Support 0x1008FF7E
#define XF86FcitxKey_TaskPane 0x1008FF7F
#define XF86FcitxKey_Terminal 0x1008FF80
#define XF86FcitxKey_Tools 0x1008FF81
#define XF86FcitxKey_Travel 0x1008FF82
#define XF86FcitxKey_Video 0x1008FF87
#define XF86FcitxKey_Word 0x1008FF89
#define XF86FcitxKey_Xfer 0x1008FF8A
#define XF86FcitxKey_ZoomIn 0x1008FF8B
#define XF86FcitxKey_ZoomOut 0x1008FF8C
#define XF86FcitxKey_Away 0x1008FF8D
#define XF86FcitxKey_Messenger 0x1008FF8E
#define XF86FcitxKey_WebCam 0x1008FF8F
#define XF86FcitxKey_MailForward 0x1008FF90
#define XF86FcitxKey_Pictures 0x1008FF91
#define XF86FcitxKey_Music 0x1008FF92
#define XF86FcitxKey_Battery 0x1008FF93
#define XF86FcitxKey_Bluetooth 0x1008FF94
#define XF86FcitxKey_WLAN 0x1008FF95
#define XF86FcitxKey_UWB 0x1008FF96
#define XF86FcitxKey_AudioForward 0x1008FF97
#define XF86FcitxKey_AudioRepeat 0x1008FF98
#define XF86FcitxKey_AudioRandomPlay 0x1008FF99
#define XF86FcitxKey_Subtitle 0x1008FF9A
#define XF86FcitxKey_AudioCycleTrack 0x1008FF9B
#define XF86FcitxKey_Time 0x1008FF9F
#define XF86FcitxKey_Select 0x1008FFA0
#define XF86FcitxKey_View 0x1008FFA1
#define XF86FcitxKey_TopMenu 0x1008FFA2
#define XF86FcitxKey_Suspend 0x1008FFA7
#define XF86FcitxKey_Hibernate 0x1008FFA8
#define XF86FcitxKey_TouchpadToggle 0x1008FFA9
#define XF86FcitxKey_TouchpadOn 0x1008FFB0
#define XF86FcitxKey_TouchpadOff 0x1008FFB1
// end of XF86keysyms.h
QT_BEGIN_NAMESPACE
// keyboard mapping table
static const unsigned int KeyTbl[] = {
// misc keys
FcitxKey_Escape, Qt::Key_Escape, FcitxKey_Tab, Qt::Key_Tab,
FcitxKey_ISO_Left_Tab, Qt::Key_Backtab, FcitxKey_BackSpace,
Qt::Key_Backspace, FcitxKey_Return, Qt::Key_Return, FcitxKey_Insert,
Qt::Key_Insert, FcitxKey_Delete, Qt::Key_Delete, FcitxKey_Clear,
Qt::Key_Delete, FcitxKey_Pause, Qt::Key_Pause, FcitxKey_Print,
Qt::Key_Print, 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
// cursor movement
FcitxKey_Home, Qt::Key_Home, FcitxKey_End, Qt::Key_End, FcitxKey_Left,
Qt::Key_Left, FcitxKey_Up, Qt::Key_Up, FcitxKey_Right, Qt::Key_Right,
FcitxKey_Down, Qt::Key_Down, FcitxKey_Prior, Qt::Key_PageUp, FcitxKey_Next,
Qt::Key_PageDown,
// modifiers
FcitxKey_Shift_L, Qt::Key_Shift, FcitxKey_Shift_R, Qt::Key_Shift,
FcitxKey_Shift_Lock, Qt::Key_Shift, FcitxKey_Control_L, Qt::Key_Control,
FcitxKey_Control_R, Qt::Key_Control, FcitxKey_Meta_L, Qt::Key_Meta,
FcitxKey_Meta_R, Qt::Key_Meta, FcitxKey_Alt_L, Qt::Key_Alt, FcitxKey_Alt_R,
Qt::Key_Alt, FcitxKey_Caps_Lock, Qt::Key_CapsLock, FcitxKey_Num_Lock,
Qt::Key_NumLock, FcitxKey_Scroll_Lock, Qt::Key_ScrollLock, FcitxKey_Super_L,
Qt::Key_Super_L, FcitxKey_Super_R, Qt::Key_Super_R, FcitxKey_Menu,
Qt::Key_Menu, FcitxKey_Hyper_L, Qt::Key_Hyper_L, FcitxKey_Hyper_R,
Qt::Key_Hyper_R, FcitxKey_Help, Qt::Key_Help, 0x1000FF74,
Qt::Key_Backtab, // hardcoded HP backtab
0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
// numeric and function keypad keys
FcitxKey_KP_Space, Qt::Key_Space, FcitxKey_KP_Tab, Qt::Key_Tab,
FcitxKey_KP_Enter, Qt::Key_Enter,
// FcitxKey_KP_F1, Qt::Key_F1,
// FcitxKey_KP_F2, Qt::Key_F2,
// FcitxKey_KP_F3, Qt::Key_F3,
// FcitxKey_KP_F4, Qt::Key_F4,
FcitxKey_KP_Home, Qt::Key_Home, FcitxKey_KP_Left, Qt::Key_Left,
FcitxKey_KP_Up, Qt::Key_Up, FcitxKey_KP_Right, Qt::Key_Right,
FcitxKey_KP_Down, Qt::Key_Down, FcitxKey_KP_Prior, Qt::Key_PageUp,
FcitxKey_KP_Next, Qt::Key_PageDown, FcitxKey_KP_End, Qt::Key_End,
FcitxKey_KP_Begin, Qt::Key_Clear, FcitxKey_KP_Insert, Qt::Key_Insert,
FcitxKey_KP_Delete, Qt::Key_Delete, FcitxKey_KP_Equal, Qt::Key_Equal,
FcitxKey_KP_Multiply, Qt::Key_Asterisk, FcitxKey_KP_Add, Qt::Key_Plus,
FcitxKey_KP_Separator, Qt::Key_Comma, FcitxKey_KP_Subtract, Qt::Key_Minus,
FcitxKey_KP_Decimal, Qt::Key_Period, FcitxKey_KP_Divide, Qt::Key_Slash,
// International input method support keys
// International & multi-key character composition
FcitxKey_ISO_Level3_Shift, Qt::Key_AltGr, FcitxKey_Multi_key,
Qt::Key_Multi_key, FcitxKey_Codeinput, Qt::Key_Codeinput,
FcitxKey_SingleCandidate, Qt::Key_SingleCandidate,
FcitxKey_MultipleCandidate, Qt::Key_MultipleCandidate,
FcitxKey_PreviousCandidate, Qt::Key_PreviousCandidate,
// Misc Functions
FcitxKey_Mode_switch, Qt::Key_Mode_switch, FcitxKey_script_switch,
Qt::Key_Mode_switch,
// Japanese keyboard support
FcitxKey_Kanji, Qt::Key_Kanji, FcitxKey_Muhenkan, Qt::Key_Muhenkan,
// FcitxKey_Henkan_Mode, Qt::Key_Henkan_Mode,
FcitxKey_Henkan_Mode, Qt::Key_Henkan, FcitxKey_Henkan, Qt::Key_Henkan,
FcitxKey_Romaji, Qt::Key_Romaji, FcitxKey_Hiragana, Qt::Key_Hiragana,
FcitxKey_Katakana, Qt::Key_Katakana, FcitxKey_Hiragana_Katakana,
Qt::Key_Hiragana_Katakana, FcitxKey_Zenkaku, Qt::Key_Zenkaku,
FcitxKey_Hankaku, Qt::Key_Hankaku, FcitxKey_Zenkaku_Hankaku,
Qt::Key_Zenkaku_Hankaku, FcitxKey_Touroku, Qt::Key_Touroku, FcitxKey_Massyo,
Qt::Key_Massyo, FcitxKey_Kana_Lock, Qt::Key_Kana_Lock, FcitxKey_Kana_Shift,
Qt::Key_Kana_Shift, FcitxKey_Eisu_Shift, Qt::Key_Eisu_Shift,
FcitxKey_Eisu_toggle, Qt::Key_Eisu_toggle,
// FcitxKey_Kanji_Bangou, Qt::Key_Kanji_Bangou,
// FcitxKey_Zen_Koho, Qt::Key_Zen_Koho,
// FcitxKey_Mae_Koho, Qt::Key_Mae_Koho,
FcitxKey_Kanji_Bangou, Qt::Key_Codeinput, FcitxKey_Zen_Koho,
Qt::Key_MultipleCandidate, FcitxKey_Mae_Koho, Qt::Key_PreviousCandidate,
#ifdef FcitxKey_KOREAN
// Korean keyboard support
FcitxKey_Hangul, Qt::Key_Hangul, FcitxKey_Hangul_Start,
Qt::Key_Hangul_Start, FcitxKey_Hangul_End, Qt::Key_Hangul_End,
FcitxKey_Hangul_Hanja, Qt::Key_Hangul_Hanja, FcitxKey_Hangul_Jamo,
Qt::Key_Hangul_Jamo, FcitxKey_Hangul_Romaja, Qt::Key_Hangul_Romaja,
// FcitxKey_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
FcitxKey_Hangul_Codeinput, Qt::Key_Codeinput, FcitxKey_Hangul_Jeonja,
Qt::Key_Hangul_Jeonja, FcitxKey_Hangul_Banja, Qt::Key_Hangul_Banja,
FcitxKey_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
FcitxKey_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
// FcitxKey_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
// FcitxKey_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
// FcitxKey_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
FcitxKey_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
FcitxKey_Hangul_MultipleCandidate, Qt::Key_MultipleCandidate,
FcitxKey_Hangul_PreviousCandidate, Qt::Key_PreviousCandidate,
FcitxKey_Hangul_Special, Qt::Key_Hangul_Special,
// FcitxKey_Hangul_switch, Qt::Key_Hangul_switch,
FcitxKey_Hangul_switch, Qt::Key_Mode_switch,
#endif // FcitxKey_KOREAN
// dead keys
FcitxKey_dead_grave, Qt::Key_Dead_Grave, FcitxKey_dead_acute,
Qt::Key_Dead_Acute, FcitxKey_dead_circumflex, Qt::Key_Dead_Circumflex,
FcitxKey_dead_tilde, Qt::Key_Dead_Tilde, FcitxKey_dead_macron,
Qt::Key_Dead_Macron, FcitxKey_dead_breve, Qt::Key_Dead_Breve,
FcitxKey_dead_abovedot, Qt::Key_Dead_Abovedot, FcitxKey_dead_diaeresis,
Qt::Key_Dead_Diaeresis, FcitxKey_dead_abovering, Qt::Key_Dead_Abovering,
FcitxKey_dead_doubleacute, Qt::Key_Dead_Doubleacute, FcitxKey_dead_caron,
Qt::Key_Dead_Caron, FcitxKey_dead_cedilla, Qt::Key_Dead_Cedilla,
FcitxKey_dead_ogonek, Qt::Key_Dead_Ogonek, FcitxKey_dead_iota,
Qt::Key_Dead_Iota, FcitxKey_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
FcitxKey_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
FcitxKey_dead_belowdot, Qt::Key_Dead_Belowdot, FcitxKey_dead_hook,
Qt::Key_Dead_Hook, FcitxKey_dead_horn, Qt::Key_Dead_Horn,
// Special keys from X.org - This include multimedia keys,
// wireless/bluetooth/uwb keys, special launcher keys, etc.
XF86FcitxKey_Back, Qt::Key_Back, XF86FcitxKey_Forward, Qt::Key_Forward,
XF86FcitxKey_Stop, Qt::Key_Stop, XF86FcitxKey_Refresh, Qt::Key_Refresh,
XF86FcitxKey_Favorites, Qt::Key_Favorites, XF86FcitxKey_AudioMedia,
Qt::Key_LaunchMedia, XF86FcitxKey_OpenURL, Qt::Key_OpenUrl,
XF86FcitxKey_HomePage, Qt::Key_HomePage, XF86FcitxKey_Search,
Qt::Key_Search, XF86FcitxKey_AudioLowerVolume, Qt::Key_VolumeDown,
XF86FcitxKey_AudioMute, Qt::Key_VolumeMute, XF86FcitxKey_AudioRaiseVolume,
Qt::Key_VolumeUp, XF86FcitxKey_AudioPlay, Qt::Key_MediaPlay,
XF86FcitxKey_AudioStop, Qt::Key_MediaStop, XF86FcitxKey_AudioPrev,
Qt::Key_MediaPrevious, XF86FcitxKey_AudioNext, Qt::Key_MediaNext,
XF86FcitxKey_AudioRecord, Qt::Key_MediaRecord, XF86FcitxKey_Mail,
Qt::Key_LaunchMail, XF86FcitxKey_MyComputer,
Qt::Key_Launch0, // ### Qt 6: remap properly
XF86FcitxKey_Calculator, Qt::Key_Launch1, XF86FcitxKey_Memo, Qt::Key_Memo,
XF86FcitxKey_ToDoList, Qt::Key_ToDoList, XF86FcitxKey_Calendar,
Qt::Key_Calendar, XF86FcitxKey_PowerDown, Qt::Key_PowerDown,
XF86FcitxKey_ContrastAdjust, Qt::Key_ContrastAdjust, XF86FcitxKey_Standby,
Qt::Key_Standby, XF86FcitxKey_MonBrightnessUp, Qt::Key_MonBrightnessUp,
XF86FcitxKey_MonBrightnessDown, Qt::Key_MonBrightnessDown,
XF86FcitxKey_KbdLightOnOff, Qt::Key_KeyboardLightOnOff,
XF86FcitxKey_KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp,
XF86FcitxKey_KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown,
XF86FcitxKey_PowerOff, Qt::Key_PowerOff, XF86FcitxKey_WakeUp,
Qt::Key_WakeUp, XF86FcitxKey_Eject, Qt::Key_Eject, XF86FcitxKey_ScreenSaver,
Qt::Key_ScreenSaver, XF86FcitxKey_WWW, Qt::Key_WWW, XF86FcitxKey_Sleep,
Qt::Key_Sleep, XF86FcitxKey_LightBulb, Qt::Key_LightBulb, XF86FcitxKey_Shop,
Qt::Key_Shop, XF86FcitxKey_History, Qt::Key_History,
XF86FcitxKey_AddFavorite, Qt::Key_AddFavorite, XF86FcitxKey_HotLinks,
Qt::Key_HotLinks, XF86FcitxKey_BrightnessAdjust, Qt::Key_BrightnessAdjust,
XF86FcitxKey_Finance, Qt::Key_Finance, XF86FcitxKey_Community,
Qt::Key_Community, XF86FcitxKey_AudioRewind, Qt::Key_AudioRewind,
XF86FcitxKey_BackForward, Qt::Key_BackForward, XF86FcitxKey_ApplicationLeft,
Qt::Key_ApplicationLeft, XF86FcitxKey_ApplicationRight,
Qt::Key_ApplicationRight, XF86FcitxKey_Book, Qt::Key_Book, XF86FcitxKey_CD,
Qt::Key_CD, XF86FcitxKey_Calculater, Qt::Key_Calculator, XF86FcitxKey_Clear,
Qt::Key_Clear, XF86FcitxKey_ClearGrab, Qt::Key_ClearGrab,
XF86FcitxKey_Close, Qt::Key_Close, XF86FcitxKey_Copy, Qt::Key_Copy,
XF86FcitxKey_Cut, Qt::Key_Cut, XF86FcitxKey_Display, Qt::Key_Display,
XF86FcitxKey_DOS, Qt::Key_DOS, XF86FcitxKey_Documents, Qt::Key_Documents,
XF86FcitxKey_Excel, Qt::Key_Excel, XF86FcitxKey_Explorer, Qt::Key_Explorer,
XF86FcitxKey_Game, Qt::Key_Game, XF86FcitxKey_Go, Qt::Key_Go,
XF86FcitxKey_iTouch, Qt::Key_iTouch, XF86FcitxKey_LogOff, Qt::Key_LogOff,
XF86FcitxKey_Market, Qt::Key_Market, XF86FcitxKey_Meeting, Qt::Key_Meeting,
XF86FcitxKey_MenuKB, Qt::Key_MenuKB, XF86FcitxKey_MenuPB, Qt::Key_MenuPB,
XF86FcitxKey_MySites, Qt::Key_MySites, XF86FcitxKey_News, Qt::Key_News,
XF86FcitxKey_OfficeHome, Qt::Key_OfficeHome, XF86FcitxKey_Option,
Qt::Key_Option, XF86FcitxKey_Paste, Qt::Key_Paste, XF86FcitxKey_Phone,
Qt::Key_Phone, XF86FcitxKey_Reply, Qt::Key_Reply, XF86FcitxKey_Reload,
Qt::Key_Reload, XF86FcitxKey_RotateWindows, Qt::Key_RotateWindows,
XF86FcitxKey_RotationPB, Qt::Key_RotationPB, XF86FcitxKey_RotationKB,
Qt::Key_RotationKB, XF86FcitxKey_Save, Qt::Key_Save, XF86FcitxKey_Send,
Qt::Key_Send, XF86FcitxKey_Spell, Qt::Key_Spell, XF86FcitxKey_SplitScreen,
Qt::Key_SplitScreen, XF86FcitxKey_Support, Qt::Key_Support,
XF86FcitxKey_TaskPane, Qt::Key_TaskPane, XF86FcitxKey_Terminal,
Qt::Key_Terminal, XF86FcitxKey_Tools, Qt::Key_Tools, XF86FcitxKey_Travel,
Qt::Key_Travel, XF86FcitxKey_Video, Qt::Key_Video, XF86FcitxKey_Word,
Qt::Key_Word, XF86FcitxKey_Xfer, Qt::Key_Xfer, XF86FcitxKey_ZoomIn,
Qt::Key_ZoomIn, XF86FcitxKey_ZoomOut, Qt::Key_ZoomOut, XF86FcitxKey_Away,
Qt::Key_Away, XF86FcitxKey_Messenger, Qt::Key_Messenger,
XF86FcitxKey_WebCam, Qt::Key_WebCam, XF86FcitxKey_MailForward,
Qt::Key_MailForward, XF86FcitxKey_Pictures, Qt::Key_Pictures,
XF86FcitxKey_Music, Qt::Key_Music, XF86FcitxKey_Battery, Qt::Key_Battery,
XF86FcitxKey_Bluetooth, Qt::Key_Bluetooth, XF86FcitxKey_WLAN, Qt::Key_WLAN,
XF86FcitxKey_UWB, Qt::Key_UWB, XF86FcitxKey_AudioForward,
Qt::Key_AudioForward, XF86FcitxKey_AudioRepeat, Qt::Key_AudioRepeat,
XF86FcitxKey_AudioRandomPlay, Qt::Key_AudioRandomPlay,
XF86FcitxKey_Subtitle, Qt::Key_Subtitle, XF86FcitxKey_AudioCycleTrack,
Qt::Key_AudioCycleTrack, XF86FcitxKey_Time, Qt::Key_Time,
XF86FcitxKey_Select, Qt::Key_Select, XF86FcitxKey_View, Qt::Key_View,
XF86FcitxKey_TopMenu, Qt::Key_TopMenu, XF86FcitxKey_Bluetooth,
Qt::Key_Bluetooth, XF86FcitxKey_Suspend, Qt::Key_Suspend,
XF86FcitxKey_Hibernate, Qt::Key_Hibernate, XF86FcitxKey_Launch0,
Qt::Key_Launch2, // ### Qt 6: remap properly
XF86FcitxKey_Launch1, Qt::Key_Launch3, XF86FcitxKey_Launch2,
Qt::Key_Launch4, XF86FcitxKey_Launch3, Qt::Key_Launch5,
XF86FcitxKey_Launch4, Qt::Key_Launch6, XF86FcitxKey_Launch5,
Qt::Key_Launch7, XF86FcitxKey_Launch6, Qt::Key_Launch8,
XF86FcitxKey_Launch7, Qt::Key_Launch9, XF86FcitxKey_Launch8,
Qt::Key_LaunchA, XF86FcitxKey_Launch9, Qt::Key_LaunchB,
XF86FcitxKey_LaunchA, Qt::Key_LaunchC, XF86FcitxKey_LaunchB,
Qt::Key_LaunchD, XF86FcitxKey_LaunchC, Qt::Key_LaunchE,
XF86FcitxKey_LaunchD, Qt::Key_LaunchF, XF86FcitxKey_LaunchE,
Qt::Key_LaunchG, XF86FcitxKey_LaunchF, Qt::Key_LaunchH,
0, 0};
static const unsigned short katakanaKeysymsToUnicode[] = {
0x0000, 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1,
0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5, 0x30E7, 0x30C3,
0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD,
0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD,
0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC,
0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE,
0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9,
0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3, 0x309B, 0x309C};
static const unsigned short cyrillicKeysymsToUnicode[] = {
0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458,
0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f, 0x2116, 0x0402,
0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a,
0x040b, 0x040c, 0x0000, 0x040e, 0x040f, 0x044e, 0x0430, 0x0431, 0x0446,
0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043a, 0x043b,
0x043c, 0x043d, 0x043e, 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443,
0x0436, 0x0432, 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447,
0x044a, 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x042b,
0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a};
static const unsigned short greekKeysymsToUnicode[] = {
0x0000, 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, 0x038e,
0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, 0x0000, 0x03ac,
0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, 0x03cd, 0x03cb, 0x03b0,
0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0391, 0x0392, 0x0393,
0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c,
0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5,
0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0,
0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
static const unsigned short technicalKeysymsToUnicode[] = {
0x0000, 0x23B7, 0x250C, 0x2500, 0x2320, 0x2321, 0x2502, 0x23A1, 0x23A3,
0x23A4, 0x23A6, 0x239B, 0x239D, 0x239E, 0x23A0, 0x23A8, 0x23AC, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x2264, 0x2260, 0x2265, 0x222B, 0x2234, 0x221D, 0x221E, 0x0000,
0x0000, 0x2207, 0x0000, 0x0000, 0x223C, 0x2243, 0x0000, 0x0000, 0x0000,
0x21D4, 0x21D2, 0x2261, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x221A, 0x0000, 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222A, 0x2227,
0x2228, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, 0x0000, 0x0000,
0x0000, 0x2190, 0x2191, 0x2192, 0x2193, 0x0000};
static const unsigned short specialKeysymsToUnicode[] = {
0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x0000, 0x0000,
0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA,
0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C,
0x2502, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
static const unsigned short publishingKeysymsToUnicode[] = {
0x0000, 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, 0x200a,
0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, 0x2153, 0x2154,
0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x2105, 0x0000, 0x0000,
0x2012, 0x2329, 0x0000, 0x232a, 0x0000, 0x0000, 0x0000, 0x0000, 0x215b,
0x215c, 0x215d, 0x215e, 0x0000, 0x0000, 0x2122, 0x2613, 0x0000, 0x25c1,
0x25b7, 0x25cb, 0x25af, 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000,
0x2032, 0x2033, 0x0000, 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf,
0x25ae, 0x25e6, 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa,
0x25b2, 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000, 0x2720,
0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642, 0x2640, 0x260e,
0x2315, 0x2117, 0x2038, 0x201a, 0x201e, 0x0000};
static const unsigned short aplKeysymsToUnicode[] = {
0x0000, 0x0000, 0x0000, 0x003c, 0x0000, 0x0000, 0x003e, 0x0000, 0x2228,
0x2227, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00af, 0x0000, 0x22a5, 0x2229,
0x230a, 0x0000, 0x005f, 0x0000, 0x0000, 0x0000, 0x2218, 0x0000, 0x2395,
0x0000, 0x22a4, 0x25cb, 0x0000, 0x0000, 0x0000, 0x2308, 0x0000, 0x0000,
0x222a, 0x0000, 0x2283, 0x0000, 0x2282, 0x0000, 0x22a2, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x22a3, 0x0000, 0x0000, 0x0000};
static const unsigned short koreanKeysymsToUnicode[] = {
0x0000, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138,
0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, 0x3140, 0x3141,
0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314a,
0x314b, 0x314c, 0x314d, 0x314e, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153,
0x3154, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a, 0x315b, 0x315c,
0x315d, 0x315e, 0x315f, 0x3160, 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9,
0x11aa, 0x11ab, 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2,
0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb,
0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d, 0x3171,
0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e, 0x11eb, 0x11f0,
0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9};
static QChar keysymToUnicode(unsigned char byte3, unsigned char byte4) {
switch (byte3) {
case 0x04:
// katakana
if (byte4 > 0xa0 && byte4 < 0xe0)
return QChar(katakanaKeysymsToUnicode[byte4 - 0xa0]);
else if (byte4 == 0x7e)
return QChar(0x203e); // Overline
break;
case 0x06:
// russian, use lookup table
if (byte4 > 0xa0)
return QChar(cyrillicKeysymsToUnicode[byte4 - 0xa0]);
break;
case 0x07:
// greek
if (byte4 > 0xa0)
return QChar(greekKeysymsToUnicode[byte4 - 0xa0]);
break;
case 0x08:
// technical
if (byte4 > 0xa0)
return QChar(technicalKeysymsToUnicode[byte4 - 0xa0]);
break;
case 0x09:
// special
if (byte4 >= 0xe0)
return QChar(specialKeysymsToUnicode[byte4 - 0xe0]);
break;
case 0x0a:
// publishing
if (byte4 > 0xa0)
return QChar(publishingKeysymsToUnicode[byte4 - 0xa0]);
break;
case 0x0b:
// APL
if (byte4 > 0xa0)
return QChar(aplKeysymsToUnicode[byte4 - 0xa0]);
break;
case 0x0e:
// Korean
if (byte4 > 0xa0)
return QChar(koreanKeysymsToUnicode[byte4 - 0xa0]);
break;
default:
break;
}
return QChar(0x0);
}
int translateKeySym(unsigned int key) {
int code = -1;
int i = 0; // any other keys
while (KeyTbl[i]) {
if (key == KeyTbl[i]) {
code = (int)KeyTbl[i + 1];
break;
}
i += 2;
}
return code;
}
QString translateKeySym(int keysym, fcitx::KeyStates xmodifiers, int &code,
Qt::KeyboardModifiers &modifiers, QByteArray &chars,
int &count) {
// all keysyms smaller than 0xff00 are actually keys that can be mapped to
// unicode chars
QTextCodec *mapper = QTextCodec::codecForLocale();
QChar converted;
if (/*count == 0 &&*/ keysym < 0xff00) {
unsigned char byte3 = (unsigned char)(keysym >> 8);
int mib = -1;
switch (byte3) {
case 0: // Latin 1
case 1: // Latin 2
case 2: // latin 3
case 3: // latin4
mib = byte3 + 4;
break;
case 5: // arabic
mib = 82;
break;
case 12: // Hebrew
mib = 85;
break;
case 13: // Thai
mib = 2259;
break;
case 4: // kana
case 6: // cyrillic
case 7: // greek
case 8: // technical, no mapping here at the moment
case 9: // Special
case 10: // Publishing
case 11: // APL
case 14: // Korean, no mapping
mib = -1; // manual conversion
mapper = 0;
converted = keysymToUnicode(byte3, keysym & 0xff);
break;
case 0x20:
// currency symbols
if (keysym >= 0x20a0 && keysym <= 0x20ac) {
mib = -1; // manual conversion
mapper = 0;
converted = static_cast<unsigned int>(keysym);
}
break;
default:
break;
}
if (mib != -1) {
mapper = QTextCodec::codecForMib(mib);
if (chars.isEmpty())
chars.resize(1);
chars[0] =
static_cast<unsigned char>(keysym & 0xff); // get only the
// fourth bit for
// conversion later
count = 1;
}
} else if (keysym >= 0x1000000 && keysym <= 0x100ffff) {
converted = (ushort)(keysym - 0x1000000);
mapper = 0;
}
if (count < (int)chars.size() - 1)
chars[count] = '\0';
QString text;
if (!mapper && converted.unicode() != 0x0) {
text = converted;
} else if (!chars.isEmpty()) {
// convert chars (8bit) to text (unicode).
if (mapper)
text = mapper->toUnicode(chars.constData(), count, 0);
if (text.isEmpty()) {
// no mapper, or codec couldn't convert to unicode (this
// can happen when running in the C locale or with no LANG
// set). try converting from latin-1
text = QString::fromLatin1(chars);
}
}
if (xmodifiers & fcitx::KeyState::Alt) {
modifiers |= Qt::AltModifier;
}
if (xmodifiers & fcitx::KeyState::Shift) {
modifiers |= Qt::ShiftModifier;
}
if (xmodifiers & fcitx::KeyState::Ctrl) {
modifiers |= Qt::ControlModifier;
}
if (xmodifiers & fcitx::KeyState::Super) {
modifiers |= Qt::MetaModifier;
}
// Commentary in X11/keysymdef says that X codes match ASCII, so it
// is safe to use the locale functions to process X codes in ISO8859-1.
//
// This is mainly for compatibility - applications should not use the
// Qt keycodes between 128 and 255, but should rather use the
// QKeyEvent::text().
//
if (keysym < 128 || (keysym < 256 && (!mapper || mapper->mibEnum() == 4))) {
// upper-case key, if known
code = isprint((int)keysym) ? toupper((int)keysym) : 0;
} else if (keysym >= FcitxKey_F1 && keysym <= FcitxKey_F35) {
// function keys
code = Qt::Key_F1 + ((int)keysym - FcitxKey_F1);
} else if (keysym >= FcitxKey_KP_Space && keysym <= FcitxKey_KP_9) {
if (keysym >= FcitxKey_KP_0) {
// numeric keypad keys
code = Qt::Key_0 + ((int)keysym - FcitxKey_KP_0);
} else {
code = translateKeySym(keysym);
}
modifiers |= Qt::KeypadModifier;
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f &&
text.unicode()->unicode() != 0x7f &&
!(keysym >= FcitxKey_dead_grave &&
keysym <= FcitxKey_dead_horn)) {
code = text.unicode()->toUpper().unicode();
} else {
// any other keys
code = translateKeySym(keysym);
if (code == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) {
// map shift+tab to shift+backtab, QShortcutMap knows about it
// and will handle it.
code = Qt::Key_Backtab;
text = QString();
}
}
return text;
}
bool symToKeyQt(int sym, unsigned int state, int &qtcode,
Qt::KeyboardModifiers &mod) {
QByteArray chars;
int count = 0;
translateKeySym(sym, fcitx::KeyStates(state), qtcode, mod, chars, count);
return qtcode >= 0;
}
bool keyQtToSym(int qtcode, Qt::KeyboardModifiers mod, int &sym,
unsigned int &state) {
return keyQtToSym(qtcode, mod, QString(), sym, state);
}
bool keyQtToSym(int qtcode, Qt::KeyboardModifiers mod, const QString &text,
int &sym, unsigned int &state) {
qEventToSym(qtcode, mod, text, sym, state);
return sym >= 0;
}
} // namespace fcitx

View File

@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_QTKEYTRANS_H_
#define _WIDGETSADDONS_QTKEYTRANS_H_
#include "fcitx5qt5widgetsaddons_export.h"
#include <QString>
#include <qnamespace.h>
namespace fcitx {
FCITX5QT5WIDGETSADDONS_EXPORT bool keyQtToSym(int qtcode,
Qt::KeyboardModifiers mod,
int &sym, unsigned int &state);
FCITX5QT5WIDGETSADDONS_EXPORT bool keyQtToSym(int qtcode,
Qt::KeyboardModifiers mod,
const QString &text, int &sym,
unsigned int &state);
FCITX5QT5WIDGETSADDONS_EXPORT bool symToKeyQt(int sym, unsigned int state,
int &qtcode,
Qt::KeyboardModifiers &mod);
} // namespace fcitx
#endif // _WIDGETSADDONS_QTKEYTRANS_H_

File diff suppressed because it is too large Load Diff