mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
hapticsplugin: Port to feedbackd
This is an initial port to feedbackd for the haptics plugin. This implementation is a simple port to have the motor enabled for a certain duration. We will eventually want to use feedbackd events to trigger these instead. Related MR for qtfeedback: https://invent.kde.org/jbbgameich/ktactilefeedback/-/merge_requests/2 https://invent.kde.org/teams/plasma-mobile/issues/-/issues/10
This commit is contained in:
parent
73b5595139
commit
72284989f8
8 changed files with 184 additions and 44 deletions
|
|
@ -45,7 +45,7 @@ Dependencies:
|
|||
* Milou (for search)
|
||||
* Kirigami
|
||||
* Kirigami Addons
|
||||
* hfd-service (optional: for vibrations)
|
||||
* feedbackd (optional: for vibrations)
|
||||
|
||||
To start the shell in a window, run:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
# SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
qt_add_dbus_interfaces(DBUS_SRCS dbus/com.lomiri.hfd.xml)
|
||||
set_source_files_properties(dbus/org.sigxcpu.Feedback.Haptic.xml PROPERTIES INCLUDE vibrationevent.h)
|
||||
qt_add_dbus_interfaces(dbusinterface_SRCS
|
||||
dbus/org.sigxcpu.Feedback.Haptic.xml)
|
||||
|
||||
ecm_add_qml_module(hapticsplugin URI org.kde.plasma.private.mobileshell.hapticsplugin GENERATE_PLUGIN_SOURCE)
|
||||
target_sources(hapticsplugin PRIVATE
|
||||
vibrationevent.h
|
||||
vibrationmanager.cpp
|
||||
${DBUS_SRCS}
|
||||
${dbusinterface_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(hapticsplugin PRIVATE
|
||||
|
|
@ -14,6 +17,7 @@ target_link_libraries(hapticsplugin PRIVATE
|
|||
Qt::DBus
|
||||
KF6::CoreAddons
|
||||
KF6::I18n
|
||||
QCoro::DBus
|
||||
)
|
||||
|
||||
ecm_finalize_qml_module(hapticsplugin)
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2020 Marius Gripsgard <marius@ubports.com>
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<node name="/com/lomiri/hfd">
|
||||
<interface name="com.lomiri.hfd.Vibrator">
|
||||
<method name="vibrate"/>
|
||||
<method name="vibrate">
|
||||
<arg name="durationMs" type="i" direction="in" />
|
||||
</method>
|
||||
<method name="rumble">
|
||||
<arg name="durationMs" type="i" direction="in" />
|
||||
<arg name="repeat" type="i" direction="in" />
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="com.lomiri.hfd.Leds">
|
||||
<method name="setState">
|
||||
<arg name="state" type="i" direction="in" />
|
||||
</method>
|
||||
<method name="setColor">
|
||||
<arg name="color" type="u" direction="in" />
|
||||
</method>
|
||||
<method name="setOnMs">
|
||||
<arg name="onMs" type="i" direction="in" />
|
||||
</method>
|
||||
<method name="setOffMs">
|
||||
<arg name="offMs" type="i" direction="in" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Guido Günther <agx@sigxcpu.org>
|
||||
- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<node>
|
||||
<!-- org.sigxcpu.Feedback.Haptic
|
||||
@short_description: Interface to make a device vibrate
|
||||
|
||||
This D-Bus interface is used to make a device's haptic motor
|
||||
vibrate. This is can be useful e.g. for games.
|
||||
|
||||
To provider user feedback the event based interface should be
|
||||
preferred.
|
||||
-->
|
||||
<interface name="org.sigxcpu.Feedback.Haptic">
|
||||
<!--
|
||||
Vibrate:
|
||||
@app_id: The application id usually in "reverse DNS" format
|
||||
@pattern: The vibration pattern.
|
||||
@success: Whether vibration was triggered
|
||||
|
||||
Triggers the given vibration pattern on the haptic device. The
|
||||
pattern is a sequence of relative amplitude and duration pairs.
|
||||
The amplitude must be between 0.0 and 1.0, durations are in
|
||||
milliseconds.
|
||||
-->
|
||||
<method name="Vibrate">
|
||||
<arg direction="in" name="app_id" type="s"/>
|
||||
<arg direction="in" name="pattern" type="a(du)"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="VibrationEventList" />
|
||||
<arg direction="out" name="success" type="b"/>
|
||||
</method>
|
||||
|
||||
</interface>
|
||||
|
||||
</node>
|
||||
80
components/hapticsplugin/dbus/org.sigxcpu.Feedback.xml
Normal file
80
components/hapticsplugin/dbus/org.sigxcpu.Feedback.xml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Guido Günther <agx@sigxcpu.org>
|
||||
- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
<node>
|
||||
<!-- org.sigxcpu.Feedback
|
||||
@short_description: haptic/audio/visual feedback interface
|
||||
|
||||
This D-Bus interface is used to get the current feedback theme
|
||||
and to give feedback on events.
|
||||
-->
|
||||
<interface name="org.sigxcpu.Feedback">
|
||||
<!--
|
||||
Profile: The currently used profile.
|
||||
|
||||
The currently used feedback profile name. Applications should
|
||||
usually not change this value.
|
||||
-->
|
||||
<property name="Profile" type="s" access="readwrite" />
|
||||
|
||||
<!--
|
||||
TriggerFeedback:
|
||||
@app_id: The application id usually in "reverse DNS" format
|
||||
@event: The event name from the Event naming spec
|
||||
@hints: Additional hints. Currently known hints
|
||||
- profile: Override the profile used for this event with the given profile name
|
||||
- important: Override the current global feedback level.
|
||||
Together with the 'profile' hint this allows to trigger feedback for events
|
||||
that would otherwise be disabled. A typical use case is an alarm clock. Note
|
||||
that the feedback daemon (depending on it's configuration) might ignore this flag.
|
||||
- sound-file: A custom sound file to play. This file will be used instead of any
|
||||
sound event specified in the "full" profile. The sound will only be played if
|
||||
appropriate for the feedback level of the event.
|
||||
@timeout: When the feedbacks for this event should end latest in seconds. The special
|
||||
values '-1' (just run each feedback once) and '0' (endless loop) are also supported.
|
||||
@id: Event id for future reference
|
||||
|
||||
Give user feedback for an event by triggering feedbacks
|
||||
defined in the daemon. The method call returns an event id
|
||||
that can be used later on to e.g. cancel the triggered
|
||||
feedbacks early.
|
||||
|
||||
Depending on the event, theme and profile several forms of
|
||||
feedback will be triggered such as an audio ring tone and a
|
||||
haptic motor.
|
||||
-->
|
||||
<method name="TriggerFeedback">
|
||||
<arg direction="in" name="app_id" type="s"/>
|
||||
<arg direction="in" name="event" type="s"/>
|
||||
<arg direction="in" name="hints" type="a{sv}"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap" />
|
||||
<arg direction="in" name="timeout" type="i"/>
|
||||
<arg direction="out" name="id" type="u"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
EndFeedback:
|
||||
@id: The id of the event
|
||||
|
||||
End all feedbacks triggered by the event with the given id.
|
||||
-->
|
||||
<method name="EndFeedback">
|
||||
<arg direction="in" name="id" type="u"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
FeedbackEnded:
|
||||
@id: The id of the event
|
||||
@reason: The reason why feedback was ended (currently unused).
|
||||
|
||||
Emitted when all feedbacks for an event have ended.
|
||||
-->
|
||||
<signal name="FeedbackEnded">
|
||||
<arg name="id" type="u"/>
|
||||
<arg name="reason" type="u"/>
|
||||
</signal>
|
||||
</interface>
|
||||
|
||||
</node>
|
||||
37
components/hapticsplugin/vibrationevent.h
Normal file
37
components/hapticsplugin/vibrationevent.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QList>
|
||||
|
||||
class VibrationEvent
|
||||
{
|
||||
public:
|
||||
double amplitude;
|
||||
quint32 duration;
|
||||
};
|
||||
|
||||
using VibrationEventList = QList<VibrationEvent>;
|
||||
|
||||
Q_DECLARE_METATYPE(VibrationEvent)
|
||||
Q_DECLARE_METATYPE(VibrationEventList)
|
||||
|
||||
inline QDBusArgument &operator<<(QDBusArgument &argument, const VibrationEvent &e)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << e.amplitude;
|
||||
argument << e.duration;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
inline const QDBusArgument &operator>>(const QDBusArgument &argument, VibrationEvent &e)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> e.amplitude;
|
||||
argument >> e.duration;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
||||
// SPDX-FileCopyrightText: 2023-2025 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "vibrationmanager.h"
|
||||
|
|
@ -6,14 +6,24 @@
|
|||
VibrationManager::VibrationManager(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
qDBusRegisterMetaType<VibrationEvent>();
|
||||
qDBusRegisterMetaType<VibrationEventList>();
|
||||
}
|
||||
|
||||
void VibrationManager::vibrate(int durationMs)
|
||||
QCoro::Task<void> VibrationManager::vibrate(int durationMs)
|
||||
{
|
||||
// Only create interface when needed.
|
||||
if (!m_interface) {
|
||||
const auto objectPath = QStringLiteral("/com/lomiri/hfd");
|
||||
m_interface = new com::lomiri::hfd::Vibrator("com.lomiri.hfd", objectPath, QDBusConnection::systemBus(), this);
|
||||
const auto objectPath = QStringLiteral("/org/sigxcpu/Feedback");
|
||||
m_interface = new OrgSigxcpuFeedbackHapticInterface("org.sigxcpu.Feedback", objectPath, QDBusConnection::sessionBus(), this);
|
||||
}
|
||||
|
||||
const QString appId = QStringLiteral("org.kde.plasmashell");
|
||||
const VibrationEvent event{1.0, static_cast<quint32>(durationMs)};
|
||||
const VibrationEventList pattern = {event};
|
||||
QDBusPendingReply<bool> reply = co_await m_interface->Vibrate(appId, pattern);
|
||||
|
||||
if (!reply.isValid() || !reply.value()) {
|
||||
qWarning() << "feedbackd vibration failed";
|
||||
}
|
||||
m_interface->vibrate(durationMs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
#include "hfdinterface.h"
|
||||
#include "hapticinterface.h"
|
||||
#include "vibrationevent.h"
|
||||
|
||||
#include <QCoroDBusPendingReply>
|
||||
|
||||
class VibrationManager : public QObject
|
||||
{
|
||||
|
|
@ -17,8 +21,8 @@ class VibrationManager : public QObject
|
|||
public:
|
||||
VibrationManager(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void vibrate(int durationMs);
|
||||
Q_INVOKABLE QCoro::Task<void> vibrate(int durationMs);
|
||||
|
||||
private:
|
||||
com::lomiri::hfd::Vibrator *m_interface{nullptr};
|
||||
OrgSigxcpuFeedbackHapticInterface *m_interface{nullptr};
|
||||
};
|
||||
Loading…
Reference in a new issue