Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(libinputactions_SRCS
libinputactions/config/parsers/qt.cpp
libinputactions/config/parsers/separated-string.h
libinputactions/config/parsers/std.cpp
libinputactions/config/parsers/triggers.cpp
libinputactions/config/parsers/utils.h
libinputactions/config/ConfigIssue.cpp
libinputactions/config/ConfigIssueManager.cpp
Expand Down Expand Up @@ -76,15 +77,41 @@ set(libinputactions_SRCS
libinputactions/interfaces/SessionLock.h
libinputactions/interfaces/Window.h
libinputactions/interfaces/WindowProvider.cpp
libinputactions/triggers/DirectionalMotionTrigger.cpp
libinputactions/triggers/HoverTrigger.cpp
libinputactions/triggers/KeyboardShortcutTrigger.cpp
libinputactions/triggers/MotionTrigger.cpp
libinputactions/triggers/PressTrigger.cpp
libinputactions/triggers/StrokeTrigger.cpp
libinputactions/triggers/SwipeTrigger.cpp
libinputactions/triggers/core/DirectionalMotionTriggerCore.cpp
libinputactions/triggers/core/MotionTriggerCore.cpp
libinputactions/triggers/core/StrokeTriggerCore.cpp
libinputactions/triggers/core/SwipeTriggerCore.cpp
libinputactions/triggers/core/TimeTriggerCore.cpp
libinputactions/triggers/core/TriggerCore.cpp
libinputactions/triggers/keyboard/KeyboardShortcutTrigger.cpp
libinputactions/triggers/keyboard/KeyboardTrigger.cpp
libinputactions/triggers/mouse/MouseCircleTrigger.cpp
libinputactions/triggers/mouse/MouseMotionTrigger.cpp
libinputactions/triggers/mouse/MousePressTrigger.cpp
libinputactions/triggers/mouse/MouseStrokeTrigger.cpp
libinputactions/triggers/mouse/MouseSwipeTrigger.cpp
libinputactions/triggers/mouse/MouseTrigger.cpp
libinputactions/triggers/mouse/MouseWheelTrigger.cpp
libinputactions/triggers/pointer/PointerHoverTrigger.cpp
libinputactions/triggers/pointer/PointerTrigger.cpp
libinputactions/triggers/touchpad/TouchpadCircleTrigger.cpp
libinputactions/triggers/touchpad/TouchpadClickTrigger.cpp
libinputactions/triggers/touchpad/TouchpadHoldTrigger.cpp
libinputactions/triggers/touchpad/TouchpadPinchTrigger.cpp
libinputactions/triggers/touchpad/TouchpadRotateTrigger.cpp
libinputactions/triggers/touchpad/TouchpadStrokeTrigger.cpp
libinputactions/triggers/touchpad/TouchpadSwipeTrigger.cpp
libinputactions/triggers/touchpad/TouchpadTapTrigger.cpp
libinputactions/triggers/touchpad/TouchpadTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenCircleTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenHoldTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenPinchTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenRotateTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenStrokeTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenSwipeTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenTapTrigger.cpp
libinputactions/triggers/touchscreen/TouchscreenTrigger.cpp
libinputactions/triggers/Trigger.cpp
libinputactions/triggers/WheelTrigger.cpp
libinputactions/variables/LocalVariable.cpp
libinputactions/variables/RemoteVariable.cpp
libinputactions/variables/VariableManager.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/libinputactions/actions/TriggerAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "TriggerAction.h"
#include "ActionExecutor.h"
#include <libinputactions/input/Delta.h>
#include <libinputactions/triggers/MotionTrigger.h>
#include <libinputactions/triggers/core/MotionTriggerCore.h>

Q_LOGGING_CATEGORY(INPUTACTIONS_ACTION, "inputactions.action", QtWarningMsg)

Expand Down
4 changes: 2 additions & 2 deletions src/libinputactions/config/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@ std::map<const Node *, const Node *> Node::mapItemsRawKeys() const
return result;
}

std::vector<const Node *> Node::sequenceItems() const
std::vector<const Node *> Node::sequenceItems(bool allowImplicitConversionToSequence) const
{
if (!isSequence()) {
if (m_allowImplicitConversionToSequence) {
if (m_allowImplicitConversionToSequence || allowImplicitConversionToSequence) {
return {this};
}
throw InvalidNodeTypeConfigException(this, NodeType::Sequence);
Expand Down
2 changes: 1 addition & 1 deletion src/libinputactions/config/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class Node : public std::enable_shared_from_this<Node>
* @return Items of this sequence node.
* @throws InvalidNodeTypeConfigException The node is not a sequence.
*/
std::vector<const Node *> sequenceItems() const;
std::vector<const Node *> sequenceItems(bool allowImplicitConversionToSequence = false) const;

/**
* @return String keys and node values of this map node. Returned nodes are not marked as used.
Expand Down
205 changes: 22 additions & 183 deletions src/libinputactions/config/parsers/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "flags.h"
#include "globals.h"
#include "separated-string.h"
#include "triggers.h"
#include "utils.h"
#include <QPointF>
#include <QRegularExpression>
Expand Down Expand Up @@ -48,12 +49,12 @@
#include <libinputactions/input/backends/InputBackend.h>
#include <libinputactions/input/devices/InputDeviceRule.h>
#include <libinputactions/interfaces/CursorShapeProvider.h>
#include <libinputactions/triggers/HoverTrigger.h>
#include <libinputactions/triggers/KeyboardShortcutTrigger.h>
#include <libinputactions/triggers/PressTrigger.h>
#include <libinputactions/triggers/StrokeTrigger.h>
#include <libinputactions/triggers/SwipeTrigger.h>
#include <libinputactions/triggers/WheelTrigger.h>
#include <libinputactions/triggers/core/StrokeTriggerCore.h>
#include <libinputactions/triggers/keyboard/KeyboardShortcutTrigger.h>
#include <libinputactions/triggers/mouse/MouseTrigger.h>
#include <libinputactions/triggers/pointer/PointerTrigger.h>
#include <libinputactions/triggers/touchpad/TouchpadTrigger.h>
#include <libinputactions/triggers/touchscreen/TouchscreenTrigger.h>
#include <libinputactions/variables/Variable.h>
#include <libinputactions/variables/VariableManager.h>

Expand Down Expand Up @@ -575,180 +576,6 @@ struct NodeParser<Range<T>>
};
template struct NodeParser<Range<qreal>>;

template<>
void NodeParser<std::unique_ptr<Trigger>>::parse(const Node *node, std::unique_ptr<Trigger> &result)
{
const auto *typeNode = node->at("type", true);
auto type = typeNode->as<QString>();

if (type == "circle") {
result = std::make_unique<DirectionalMotionTrigger>(TriggerType::Circle,
static_cast<TriggerDirection>(node->at("direction", true)->as<RotateDirection>()));
} else if (type == "click") {
result = std::make_unique<Trigger>(TriggerType::Click);
} else if (type == "hold" || type == "press") {
auto pressTrigger = std::make_unique<PressTrigger>();
loadSetter(pressTrigger.get(), &PressTrigger::setInstant, node->at("instant"));
result = std::move(pressTrigger);
} else if (type == "hover") {
result = std::make_unique<HoverTrigger>();
} else if (type == "pinch") {
result = std::make_unique<DirectionalMotionTrigger>(TriggerType::Pinch,
static_cast<TriggerDirection>(node->at("direction", true)->as<PinchDirection>()));
} else if (type == "rotate") {
result = std::make_unique<DirectionalMotionTrigger>(TriggerType::Rotate,
static_cast<TriggerDirection>(node->at("direction", true)->as<RotateDirection>()));
} else if (type == "shortcut") {
result = std::make_unique<KeyboardShortcutTrigger>(node->at("shortcut", true)->as<KeyboardShortcut>());
} else if (type == "stroke") {
result = std::make_unique<StrokeTrigger>(node->at("strokes", true)->as<std::vector<Stroke>>(true));
} else if (type == "swipe") {
if (const auto *directionNode = node->at("direction")) {
result = std::make_unique<SwipeTrigger>(directionNode->as<SwipeTriggerDirection>());
} else {
const auto *angleNode = node->at("angle", true);
const auto angles = parseSeparatedString2<qreal>(angleNode, '-');
if (angles.first > 360 || angles.second > 360) {
throw InvalidValueConfigException(angleNode, "The angle may not be greater than 360.");
}

auto swipeTrigger = std::make_unique<SwipeTrigger>(angles.first, angles.second);
loadSetter(swipeTrigger.get(), &SwipeTrigger::setBidirectional, node->at("bidirectional"));
result = std::move(swipeTrigger);
}

} else if (type == "tap") {
result = std::make_unique<Trigger>(TriggerType::Tap);
} else if (type == "wheel") {
result = std::make_unique<WheelTrigger>(static_cast<TriggerDirection>(node->at("direction", true)->as<SwipeDirection>()));
} else {
throw InvalidValueConfigException(typeNode, QString("Invalid trigger type '%1'.").arg(type));
}

loadSetter(result, &Trigger::setBlockEvents, node->at("block_events"));
loadSetter(result, &Trigger::setClearModifiers, node->at("clear_modifiers"));
loadSetter(result, &Trigger::setEndCondition, node->at("end_conditions"));
loadSetter(result, &Trigger::setId, node->at("id"));
loadSetter(result, &Trigger::setMouseButtonsExactOrder, node->at("mouse_buttons_exact_order"));
loadSetter(result, &Trigger::setResumeTimeout, node->at("resume_timeout"));
loadSetter(result, &Trigger::setSetLastTrigger, node->at("set_last_trigger"));
loadSetter(result, &Trigger::setThreshold, node->at("threshold"));
if (const auto *mouseButtonsNode = node->at("mouse_buttons")) {
mouseButtonsNode->as<std::set<MouseButton>>(); // Ensure no duplicates, Trigger::setMouseButtons accepts a vector
loadSetter(result, &Trigger::setMouseButtons, mouseButtonsNode);
}
if (auto *motionTrigger = dynamic_cast<MotionTrigger *>(result.get())) {
loadSetter(motionTrigger, &MotionTrigger::setLockPointer, node->at("lock_pointer"));
loadSetter(motionTrigger, &MotionTrigger::setSpeed, node->at("speed"));
}

auto conditionGroup = std::make_shared<ConditionGroup>();
if (const auto *fingersNode = node->at("fingers")) {
auto range = fingersNode->as<Range<qreal>>();
if (!range.max()) {
conditionGroup->append(std::make_shared<VariableCondition>(BuiltinVariables::Fingers,
Value<qreal>(range.min().value()),
ComparisonOperator::EqualTo));
} else {
conditionGroup->append(std::make_shared<VariableCondition>(BuiltinVariables::Fingers,
std::vector<Value<std::any>>{
Value<qreal>(range.min().value()), Value<qreal>(range.max().value())},
ComparisonOperator::Between));
}
}
if (const auto *modifiersNode = node->at("keyboard_modifiers")) {
g_configIssueManager->addIssue(DeprecatedFeatureConfigIssue(modifiersNode, DeprecatedFeature::TriggerKeyboardModifiers));

std::optional<Qt::KeyboardModifiers> modifiers;
if (modifiersNode->isSequence()) {
modifiers = modifiersNode->as<Qt::KeyboardModifiers>();
} else {
const auto modifierMatchingMode = modifiersNode->as<QString>();
if (modifierMatchingMode == "none") {
modifiers = Qt::KeyboardModifier::NoModifier;
} else if (modifierMatchingMode != "any") {
throw InvalidValueConfigException(modifiersNode, "Invalid keyboard modifier.");
}
}

if (modifiers) {
conditionGroup->append(std::make_shared<VariableCondition>(BuiltinVariables::KeyboardModifiers,
Value<Qt::KeyboardModifiers>(modifiers.value()),
ComparisonOperator::EqualTo));
}
}
if (const auto *conditionsNode = node->at("conditions")) {
conditionGroup->append(conditionsNode->as<std::shared_ptr<Condition>>());
}

if (conditionGroup->conditions().size() == 1) {
result->setActivationCondition(conditionGroup->conditions()[0]);
} else if (conditionGroup->conditions().size()) {
result->setActivationCondition(conditionGroup);
}

bool accelerated{};
loadMember(accelerated, node->at("accelerated"));

if (const auto *actionsNode = node->at("actions")) {
for (const auto *actionNode : actionsNode->sequenceItems()) {
auto action = actionNode->as<std::unique_ptr<TriggerAction>>();
if (dynamic_cast<StrokeTrigger *>(result.get()) && action->on() != On::End && action->conflicting()) {
throw InvalidValueContextConfigException(actionNode, "Stroke triggers only support 'on: end' conflicting actions.");
}

action->setAccelerated(accelerated);
result->addAction(std::move(action));
}
}
}

// Trigger list, handles triggers groups as well
template<>
void NodeParser<std::vector<std::unique_ptr<Trigger>>>::parse(const Node *node, std::vector<std::unique_ptr<Trigger>> &result)
{
for (const auto *triggerNode : node->sequenceItems()) {
if (const auto *subTriggersNode = triggerNode->at("gestures")) {
// Trigger group
for (const auto *subTriggerNode : subTriggersNode->sequenceItems()) {
const auto mergedNode = std::make_shared<Node>(*subTriggerNode);

std::shared_ptr<Condition> groupCondition;
for (const auto &[key, value] : triggerNode->mapItemsRawKeys()) {
const auto keyStr = key->as<QString>();
if (keyStr == "conditions") {
groupCondition = triggerNode->at("conditions")->as<std::shared_ptr<Condition>>();
} else if (keyStr != "gestures") {
mergedNode->addMapItem(key->shared_from_this(), value->shared_from_this());
}
}
for (auto &trigger : mergedNode->as<std::vector<std::unique_ptr<Trigger>>>(true)) {
if (groupCondition) {
if (const auto triggerCondition = trigger->activationCondition()) {
if (const auto triggerConditionGroup = std::dynamic_pointer_cast<ConditionGroup>(triggerCondition);
triggerConditionGroup && triggerConditionGroup->mode() == ConditionGroupMode::All) {
triggerConditionGroup->prepend(groupCondition);
} else {
auto conditionGroup = std::make_shared<ConditionGroup>();
conditionGroup->append(groupCondition);
conditionGroup->append(trigger->activationCondition());
trigger->setActivationCondition(conditionGroup);
}
} else {
trigger->setActivationCondition(groupCondition);
}
}

result.push_back(std::move(trigger));
}
}
continue;
}

result.push_back(triggerNode->as<std::unique_ptr<Trigger>>());
}
}

template<>
void NodeParser<std::unique_ptr<TriggerAction>>::parse(const Node *node, std::unique_ptr<TriggerAction> &result)
{
Expand Down Expand Up @@ -815,9 +642,6 @@ struct NodeParser<Value<T>>

inline void parseTriggerHandler(const Node *node, TriggerHandler *handler)
{
for (auto &trigger : node->at("gestures", true)->as<std::vector<std::unique_ptr<Trigger>>>()) {
handler->addTrigger(std::move(trigger));
}
loadSetter(handler, &TriggerHandler::setTimedTriggerUpdateDelta, node->at("__time_delta"));
}

Expand Down Expand Up @@ -854,6 +678,9 @@ inline void parseMultiTouchMotionTriggerHandler(const Node *node, MultiTouchMoti
std::unique_ptr<TouchpadTriggerHandler> parseTouchpadTriggerHandler(const Node *node, InputDevice *device)
{
auto handler = std::make_unique<TouchpadTriggerHandler>(device);
for (auto &trigger : parseTriggerList<TouchpadTrigger>(node->at("gestures", true))) {
handler->addTrigger(std::move(trigger));
}
parseMultiTouchMotionTriggerHandler(node, handler.get());
loadSetter(static_cast<MotionTriggerHandler *>(handler.get()), &MotionTriggerHandler::setSwipeDeltaMultiplier, node->at("delta_multiplier"));
return handler;
Expand All @@ -862,6 +689,9 @@ std::unique_ptr<TouchpadTriggerHandler> parseTouchpadTriggerHandler(const Node *
std::unique_ptr<TouchscreenTriggerHandler> parseTouchscreenTriggerHandler(const Node *node, InputDevice *device)
{
auto handler = std::make_unique<TouchscreenTriggerHandler>(device);
for (auto &trigger : parseTriggerList<TouchscreenTrigger>(node->at("gestures", true))) {
handler->addTrigger(std::move(trigger));
}
parseMultiTouchMotionTriggerHandler(node, handler.get());
return handler;
}
Expand All @@ -870,20 +700,29 @@ template<>
void NodeParser<std::unique_ptr<KeyboardTriggerHandler>>::parse(const Node *node, std::unique_ptr<KeyboardTriggerHandler> &result)
{
result = std::make_unique<KeyboardTriggerHandler>();
for (auto &trigger : parseTriggerList<KeyboardTrigger>(node->at("gestures", true))) {
result->addTrigger(std::move(trigger));
}
parseTriggerHandler(node, result.get());
}

template<>
void NodeParser<std::unique_ptr<MouseTriggerHandler>>::parse(const Node *node, std::unique_ptr<MouseTriggerHandler> &result)
{
result = std::make_unique<MouseTriggerHandler>();
for (auto &trigger : parseTriggerList<MouseTrigger>(node->at("gestures", true))) {
result->addTrigger(std::move(trigger));
}
parseMotionTriggerHandler(node, node->mapAt("speed"), result.get());
}

template<>
void NodeParser<std::unique_ptr<PointerTriggerHandler>>::parse(const Node *node, std::unique_ptr<PointerTriggerHandler> &result)
{
result = std::make_unique<PointerTriggerHandler>();
for (auto &trigger : parseTriggerList<PointerTrigger>(node->at("gestures", true))) {
result->addTrigger(std::move(trigger));
}
parseTriggerHandler(node, result.get());
}

Expand Down
Loading