feat: keyboard layout indicator adjust

when fcitx is running, keyboard indicator show fcitx current lang code,
disbale system keyboard switch switch shotcut and hide system keyboard
layout in dde-control-center.
resume those after fcitx stopped.

Log: keyboard layout indicator adjust
Influence: plugins/keyboard-layout
Task: https://pms.uniontech.com/task-view-115107.html
Change-Id: Id717a681b4c0d21154602c7494900fc47f3a3a98
This commit is contained in:
Tsic 2022-06-07 13:04:10 +08:00 committed by wubw
parent 1cff0b8600
commit 623dc8c764
7 changed files with 395 additions and 5 deletions

View File

@ -20,6 +20,7 @@
*/
#ifndef UTILS
#define UTILS
#include <QPixmap>
#include <QImageReader>
#include <QApplication>

View File

@ -16,8 +16,18 @@ find_package(DFrameworkdbus REQUIRED)
pkg_check_modules(DFrameworkDBus REQUIRED dframeworkdbus)
pkg_check_modules(QGSettings REQUIRED gsettings-qt)
set_source_files_properties(
org.fcitx.Fcitx.xml
PROPERTIES INCLUDE fcitxinputmethoditem.h
CLASSNAME FcitxInputMethodProxy
)
qt5_add_dbus_interfaces(DBUS_INTERFACES
org.fcitx.Fcitx.xml
)
add_definitions("${QT_DEFINITIONS} -DQT_PLUGIN")
add_library(${PLUGIN_NAME} SHARED ${SRCS})
add_library(${PLUGIN_NAME} SHARED ${SRCS} ${DBUS_INTERFACES})
set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../)
target_include_directories(${PLUGIN_NAME} PUBLIC ${DtkWidget_INCLUDE_DIRS}
${DFrameworkDBus_INCLUDE_DIRS}

View File

@ -19,23 +19,40 @@
#include "utils.h"
#include "dbusadaptors.h"
#include "fcitxinputmethoditem.h"
#include <DDBusSender>
#include <DSysInfo>
#include <QDebug>
#include <QtDBus/QDBusConnection>
// switch kdb layout key in gsettings
const QString KDB_LAYOUT_KEYBINDING_KEY = "switchNextKbdLayout";
// dcc keyboard layout key in gsettings
const QString KDB_LAYOUT_DCC_NAME = "keyboardLayout";
// because not allowd to use libfcitx-qt, use org.fcitx.Fcitx to
// get fcitx status and data
const QString FCITX_ADDRESSS = "org.fcitx.Fcitx";
DBusAdaptors::DBusAdaptors(QObject *parent)
: QDBusAbstractAdaptor(parent),
m_keyboard(new Keyboard("com.deepin.daemon.InputDevices",
"/com/deepin/daemon/InputDevice/Keyboard",
QDBusConnection::sessionBus(), this)),
m_menu(new QMenu()),
m_gsettings(Utils::ModuleSettingsPtr("keyboard", QByteArray(), this))
m_menu(new QMenu()),
m_gsettings(Utils::ModuleSettingsPtr("keyboard", QByteArray(), this)),
m_keybingEnabled(Utils::SettingsPtr("com.deepin.dde.keybinding.system.enable", QByteArray(), this)),
m_dccSettings(Utils::SettingsPtr("com.deepin.dde.control-center", QByteArray(), this)),
m_fcitxRunning(false),
m_inputmethod(nullptr)
{
m_keyboard->setSync(false);
connect(m_keyboard, &Keyboard::CurrentLayoutChanged, this, &DBusAdaptors::onCurrentLayoutChanged);
connect(m_keyboard, &Keyboard::UserLayoutListChanged, this, &DBusAdaptors::onUserLayoutListChanged);
connect(m_menu, &QMenu::triggered, this, &DBusAdaptors::handleActionTriggered);
// init data
@ -45,6 +62,12 @@ DBusAdaptors::DBusAdaptors(QObject *parent)
if (m_gsettings)
connect(m_gsettings, &QGSettings::changed, this, &DBusAdaptors::onGSettingsChanged);
// deepin show fcitx lang code,while fcitx is running
if (Dtk::Core::DSysInfo::isCommunityEdition()) {
initFcitxWatcher();
}
}
DBusAdaptors::~DBusAdaptors()
@ -93,7 +116,7 @@ void DBusAdaptors::onClicked(int button, int x, int y)
Q_UNUSED(button);
if (m_menu && m_userLayoutList.size() >= 2) {
if (m_menu && m_userLayoutList.size() >= 2 && !m_fcitxRunning) {
m_menu->exec(QPoint(x, y));
}
}
@ -215,3 +238,143 @@ QString DBusAdaptors::duplicateCheck(const QString &kb)
return kblayout + (list.count() > 1 ? QString::number(list.indexOf(kb) + 1) : "");
}
void DBusAdaptors::onFcitxConnected(const QString &service)
{
Q_UNUSED(service)
if (m_fcitxRunning)
return;
// fcitx from closed to running
m_fcitxRunning = true;
setKeyboardLayoutGsettings();
if (m_inputmethod) {
delete m_inputmethod;
m_inputmethod = nullptr;
}
// fcitx from off to on will create this, free it on fcitx closing.
m_inputmethod = new FcitxInputMethodProxy(
FCITX_ADDRESSS,
"/inputmethod",
QDBusConnection::sessionBus(),
this);
if (QDBusConnection::sessionBus().connect(FCITX_ADDRESSS, "/inputmethod",
"org.freedesktop.DBus.Properties", "PropertiesChanged", this,
SLOT(onPropertyChanged(QString, QVariantMap, QStringList)))) {
} else {
qWarning() << "fcitx's PropertiesChanged signal connection was not successful";
}
Q_EMIT(fcitxStatusChanged(m_fcitxRunning));
}
void DBusAdaptors::onFcitxDisconnected(const QString &service)
{
Q_UNUSED(service)
if (!m_fcitxRunning)
return;
// fcitx from running to close
m_fcitxRunning = false;
setKeyboardLayoutGsettings();
QDBusConnection::sessionBus().disconnect(FCITX_ADDRESSS, "/inputmethod",
"org.freedesktop.DBus.Properties", "PropertiesChanged", this,
SLOT(onPropertyChanged(QString, QVariantMap, QStringList)));
// fcitx is closing, free it.
if (m_inputmethod) {
delete m_inputmethod;
m_inputmethod = nullptr;
}
Q_EMIT(fcitxStatusChanged(m_fcitxRunning));
}
void DBusAdaptors::onPropertyChanged(QString name, QVariantMap map, QStringList list)
{
// fcitx uniquename start with fcitx-keyboard- which contains keyboard layout.
QString fcitxUniqueName("fcitx-keyboard-");
qDebug() << QString("properties of interface %1 changed").arg(name);
if (list.isEmpty() || "CurrentIM" != list[0])
return;
if (m_inputmethod == nullptr)
return;
QString currentIM = m_inputmethod ->GetCurrentIM();
if (currentIM.startsWith(fcitxUniqueName)) {
// fcitx uniquename contains keyboard layout, keyboard is after fcitx-keyboard-
// such as fcitx-keyboard-ara-uga, keyboard layout is ara;uga
// fcitx-keyboard-us keyboard is us;
// fcitx-keyboard-am-phonetic-alt keyboard layout is am;phonetic-alt
QString layout = currentIM.right(currentIM.size() - fcitxUniqueName.size());
int splitLoc = layout.indexOf('-');
if (splitLoc > 0) {
layout = layout.replace(splitLoc, 1, ';');
} else {
layout.append(';');
}
m_keyboard->setCurrentLayout(layout);
qDebug() << (m_keyboard->currentLayout() == layout);
} else {
// sunpinyin sogounpinyin uniquename not contains keyboard-layout. using lang code only for display.
FcitxQtInputMethodItemList lists = m_inputmethod -> iMList();
for (FcitxQtInputMethodItem item : lists) {
if (currentIM == item.uniqueName()) {
// zh_CN display as cn
if (0 == QString::compare("zh_CN", item.langCode())) {
item.setLangCode("cn");
}
QString layout = item.langCode();
layout.append(';');
m_keyboard->setCurrentLayout(layout);
qDebug() << (m_keyboard->currentLayout() == layout);
}
}
}
}
void DBusAdaptors::setKeyboardLayoutGsettings()
{
// while fcitx is running, disable keyboard switch shortcut, enable it after fcitx stopped
if (m_keybingEnabled && m_keybingEnabled->keys().contains(KDB_LAYOUT_KEYBINDING_KEY)) {
m_keybingEnabled->set(KDB_LAYOUT_KEYBINDING_KEY, QVariant(!m_fcitxRunning));
}
// hide keyboard layout setttings in dde-control-center, resume it after fcitx stopped
if (m_dccSettings && m_dccSettings->keys().contains(KDB_LAYOUT_DCC_NAME)) {
m_dccSettings->set(KDB_LAYOUT_DCC_NAME, QVariant(!m_fcitxRunning));
}
}
bool DBusAdaptors::isFcitxRunning() const
{
return m_fcitxRunning;
}
void DBusAdaptors::initFcitxWatcher()
{
qDebug() << "init fcitx status watcher";
FcitxQtInputMethodItem::registerMetaType();
// init dbusSewrviceWatcher to see fcitx status
m_fcitxWatcher = new QDBusServiceWatcher(this);
m_fcitxWatcher->setConnection(QDBusConnection::sessionBus());
m_fcitxWatcher->addWatchedService(FCITX_ADDRESSS);
// send fcitx on or off signal, when fcitx is starting or closing.
connect(m_fcitxWatcher, SIGNAL(serviceRegistered(QString)), this, SLOT(onFcitxConnected(QString)));
connect(m_fcitxWatcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(onFcitxDisconnected(QString)));
// get fcitx current status
QDBusReply<bool> registered = m_fcitxWatcher ->connection().interface()->isServiceRegistered(FCITX_ADDRESSS);
if (registered.isValid() && registered.value()) {
// fcitx is alerdy running,
onFcitxConnected(QString());
}
setKeyboardLayoutGsettings();
}

View File

@ -20,8 +20,11 @@
#ifndef DBUSADAPTORS_H
#define DBUSADAPTORS_H
#include "fcitxinterface.h"
#include <QMenu>
#include <QtDBus/QtDBus>
#include <com_deepin_daemon_inputdevice_keyboard.h>
using Keyboard = com::deepin::daemon::inputdevice::Keyboard;
@ -46,8 +49,10 @@ public:
public:
Q_PROPERTY(QString layout READ layout WRITE setLayout NOTIFY layoutChanged)
Q_PROPERTY(bool fcitxRunning READ isFcitxRunning NOTIFY fcitxStatusChanged)
QString layout() const;
void setLayout(const QString &str);
bool isFcitxRunning() const;
Keyboard *getCurrentKeyboard();
@ -56,6 +61,7 @@ public slots:
signals:
void layoutChanged(QString text);
void fcitxStatusChanged(bool running);
private slots:
void onCurrentLayoutChanged(const QString & value);
@ -67,12 +73,22 @@ private slots:
private slots:
void onGSettingsChanged(const QString &key);
void onFcitxConnected(const QString &service);
void onFcitxDisconnected(const QString &service);
void onPropertyChanged(QString name, QVariantMap map, QStringList list);
private:
QString duplicateCheck(const QString &kb);
void setKeyboardLayoutGsettings();
void initFcitxWatcher();
private:
Keyboard *m_keyboard;
bool m_fcitxRunning;
FcitxInputMethodProxy *m_inputmethod;
QDBusServiceWatcher *m_fcitxWatcher;
QGSettings *m_keybingEnabled;
QGSettings *m_dccSettings;
QMenu *m_menu;
QAction *m_addLayoutAction;

View File

@ -0,0 +1,79 @@
#include "fcitxinputmethoditem.h"
#include <QDBusArgument>
#include <QDBusMetaType>
bool FcitxQtInputMethodItem::enabled() const
{
return m_enabled;
}
const QString& FcitxQtInputMethodItem::langCode() const
{
return m_langCode;
}
const QString& FcitxQtInputMethodItem::name() const
{
return m_name;
}
const QString& FcitxQtInputMethodItem::uniqueName() const
{
return m_uniqueName;
}
void FcitxQtInputMethodItem::setEnabled(bool enable)
{
m_enabled = enable;
}
void FcitxQtInputMethodItem::setLangCode(const QString& lang)
{
m_langCode = lang;
}
void FcitxQtInputMethodItem::setName(const QString& name)
{
m_name = name;
}
void FcitxQtInputMethodItem::setUniqueName(const QString& name)
{
m_uniqueName = name;
}
void FcitxQtInputMethodItem::registerMetaType()
{
qRegisterMetaType<FcitxQtInputMethodItem>("FcitxQtInputMethodItem");
qDBusRegisterMetaType<FcitxQtInputMethodItem>();
qRegisterMetaType<FcitxQtInputMethodItemList>("FcitxQtInputMethodItemList");
qDBusRegisterMetaType<FcitxQtInputMethodItemList>();
}
QDBusArgument& operator<<(QDBusArgument& argument, const FcitxQtInputMethodItem& im)
{
argument.beginStructure();
argument << im.name();
argument << im.uniqueName();
argument << im.langCode();
argument << im.enabled();
argument.endStructure();
return argument;
}
const QDBusArgument& operator>>(const QDBusArgument& argument, FcitxQtInputMethodItem& im)
{
QString name;
QString uniqueName;
QString langCode;
bool enabled;
argument.beginStructure();
argument >> name >> uniqueName >> langCode >> enabled;
argument.endStructure();
im.setName(name);
im.setUniqueName(uniqueName);
im.setLangCode(langCode);
im.setEnabled(enabled);
return argument;
}

View File

@ -0,0 +1,43 @@
#ifndef FCITX_QT_INPUT_METHOD_ITEM_H
#define FCITX_QT_INPUT_METHOD_ITEM_H
// Qt
#include <QtCore/QString>
#include <QtCore/QMetaType>
#include <QtDBus/QDBusArgument>
class FcitxQtInputMethodItem
{
public:
const QString& name() const;
const QString& uniqueName() const;
const QString& langCode() const;
bool enabled() const;
void setName(const QString& name);
void setUniqueName(const QString& name);
void setLangCode(const QString& name);
void setEnabled(bool name);
static void registerMetaType();
inline bool operator < (const FcitxQtInputMethodItem& im) const {
return (m_enabled && !im.m_enabled);
}
private:
QString m_name;
QString m_uniqueName;
QString m_langCode;
bool m_enabled;
};
typedef QList<FcitxQtInputMethodItem> FcitxQtInputMethodItemList;
QDBusArgument& operator<<(QDBusArgument& argument, const FcitxQtInputMethodItem& im);
const QDBusArgument& operator>>(const QDBusArgument& argument, FcitxQtInputMethodItem& im);
Q_DECLARE_METATYPE(FcitxQtInputMethodItem)
Q_DECLARE_METATYPE(FcitxQtInputMethodItemList)
#endif

View File

@ -0,0 +1,78 @@
<!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.InputMethod">
<method name="CreateIC">
<arg name="icid" direction="out" type="i"/>
<arg name="keyval1" direction="out" type="u"/>
<arg name="state1" direction="out" type="u"/>
<arg name="keyval2" direction="out" type="u"/>
<arg name="state2" direction="out" type="u"/>
</method>
<method name="CreateICv2">
<arg name="appname" direction="in" type="s"/>
<arg name="icid" direction="out" type="i"/>
<arg name="enable" direction="out" type="b"/>
<arg name="keyval1" direction="out" type="u"/>
<arg name="state1" direction="out" type="u"/>
<arg name="keyval2" direction="out" type="u"/>
<arg name="state2" direction="out" type="u"/>
</method>
<method name="CreateICv3">
<arg name="appname" direction="in" type="s"/>
<arg name="pid" direction="in" type="i"/>
<arg name="icid" direction="out" type="i"/>
<arg name="enable" direction="out" type="b"/>
<arg name="keyval1" direction="out" type="u"/>
<arg name="state1" direction="out" type="u"/>
<arg name="keyval2" direction="out" type="u"/>
<arg name="state2" direction="out" type="u"/>
</method>
<method name="Exit"></method>
<method name="GetCurrentIM">
<arg name="im" direction="out" type="s"/>
</method>
<method name="GetIMByIndex">
<arg name="index" direction="in" type="i"/>
<arg name="im" direction="out" type="s"/>
</method>
<method name="SetCurrentIM">
<arg name="im" direction="in" type="s"/>
</method>
<method name="ReloadConfig"></method>
<method name="ReloadAddonConfig">
<arg name="addon" direction="in" type="s"/>
</method>
<method name="Restart"></method>
<method name="Configure"></method>
<method name="ConfigureAddon">
<arg name="addon" direction="in" type="s"/>
</method>
<method name="ConfigureIM">
<arg name="im" direction="in" type="s"/>
</method>
<method name="GetCurrentUI">
<arg name="addon" direction="out" type="s"/>
</method>
<method name="GetIMAddon">
<arg name="im" direction="in" type="s"/>
<arg name="addon" direction="out" type="s"/>
</method>
<method name="ActivateIM"></method>
<method name="InactivateIM"></method>
<method name="ToggleIM"></method>
<method name="SwitchIM"></method>
<method name="ResetIMList"></method>
<method name="GetCurrentState">
<arg name="state" direction="out" type="i"/>
</method>
<signal name="ReloadConfigUI"></signal>
<property access="readwrite" type="a(sssb)" name="IMList">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="FcitxQtInputMethodItemList"/>
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property access="readwrite" type="s" name="CurrentIM">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
</interface>
</node>