Skip to content

Commit 828ab7e

Browse files
committed
add stuff for text expansion
1 parent bd7298b commit 828ab7e

14 files changed

Lines changed: 376 additions & 4 deletions

File tree

src/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ set(libinputactions_SRCS
88
libinputactions/actions/CustomAction.cpp
99
libinputactions/actions/InputAction.cpp
1010
libinputactions/actions/PlasmaGlobalShortcutAction.cpp
11+
libinputactions/actions/ReplaceTextAction.cpp
1112
libinputactions/actions/SleepAction.cpp
1213
libinputactions/actions/TriggerAction.cpp
1314
libinputactions/config/parsers/base.cpp
@@ -27,6 +28,7 @@ set(libinputactions_SRCS
2728
libinputactions/config/GlobalConfig.cpp
2829
libinputactions/config/Node.cpp
2930
libinputactions/config/TextPosition.cpp
31+
libinputactions/conditions/CanReplaceTextCondition.cpp
3032
libinputactions/conditions/Condition.cpp
3133
libinputactions/conditions/ConditionGroup.cpp
3234
libinputactions/conditions/CustomCondition.cpp
@@ -75,7 +77,7 @@ set(libinputactions_SRCS
7577
libinputactions/interfaces/PointerPositionSetter.h
7678
libinputactions/interfaces/ProcessRunner.cpp
7779
libinputactions/interfaces/SessionLock.h
78-
libinputactions/interfaces/TextInput.h
80+
libinputactions/interfaces/TextInput.cpp
7981
libinputactions/interfaces/Window.h
8082
libinputactions/interfaces/WindowProvider.cpp
8183
libinputactions/triggers/core/DirectionalMotionTriggerCore.cpp

src/libinputactions/InputActionsMain.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void InputActionsMain::registerGlobalVariables(VariableManager *variableManager,
114114
value = g_cursorShapeProvider->cursorShape();
115115
});
116116
variableManager->registerLocalVariable(BuiltinVariables::DeviceName);
117-
for (auto i = 1; i <= s_fingerVariableCount; i++) {
117+
for (auto i = 1; i <= FINGER_VARIABLE_COUNT; i++) {
118118
variableManager->registerLocalVariable<QPointF>(QString("finger_%1_initial_position_percentage").arg(i));
119119
variableManager->registerLocalVariable<QPointF>(QString("finger_%1_position_percentage").arg(i));
120120
variableManager->registerLocalVariable<qreal>(QString("finger_%1_pressure").arg(i));
@@ -123,6 +123,9 @@ void InputActionsMain::registerGlobalVariables(VariableManager *variableManager,
123123
variableManager->registerRemoteVariable<Qt::KeyboardModifiers>(BuiltinVariables::KeyboardModifiers, [](auto &value) {
124124
value = g_inputBackend->keyboardModifiers();
125125
});
126+
for (auto i = 0; i < REGEX_MATCH_VARIABLE_COUNT; i++) {
127+
variableManager->registerLocalVariable<QString>(QString("match_%1").arg(i));
128+
}
126129
variableManager->registerLocalVariable(BuiltinVariables::LastTriggerId);
127130
variableManager->registerLocalVariable(BuiltinVariables::LastTriggerTimestamp, true);
128131
variableManager->registerRemoteVariable<QPointF>("pointer_position_screen_percentage", [pointerPositionGetter](auto &value) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Input Actions - Input handler that executes user-defined actions
3+
Copyright (C) 2024-2026 Marcin Woźniak
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "ReplaceTextAction.h"
20+
#include <libinputactions/helpers/QThread.h>
21+
#include <libinputactions/interfaces/TextInput.h>
22+
23+
namespace InputActions
24+
{
25+
26+
ReplaceTextAction::ReplaceTextAction(std::vector<TextSubstitutionRule> rules)
27+
: m_rules(std::move(rules))
28+
{
29+
}
30+
31+
void ReplaceTextAction::executeImpl(const ActionExecutionArguments &args)
32+
{
33+
const auto rule = std::ranges::find_if(m_rules, [](const auto &rule) {
34+
return g_textInput->canReplace(rule.regex());
35+
});
36+
if (rule == m_rules.end()) {
37+
return;
38+
}
39+
40+
g_textInput->replace(rule->regex(), rule->newText());
41+
}
42+
43+
bool ReplaceTextAction::async() const
44+
{
45+
return std::ranges::any_of(m_rules, [](const auto &rule) {
46+
return g_textInput->canReplace(rule.regex()) && rule.newText().expensive();
47+
});
48+
}
49+
50+
TextSubstitutionRule::TextSubstitutionRule(QRegularExpression regex, Value<QString> newText)
51+
: m_regex(std::move(regex))
52+
, m_newText(std::move(newText))
53+
{
54+
}
55+
56+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
Input Actions - Input handler that executes user-defined actions
3+
Copyright (C) 2024-2026 Marcin Woźniak
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#pragma once
20+
21+
#include "Action.h"
22+
#include <QString>
23+
#include <libinputactions/Value.h>
24+
#include <qregularexpression.h>
25+
26+
namespace InputActions
27+
{
28+
29+
class TextSubstitutionRule
30+
{
31+
public:
32+
TextSubstitutionRule() = default;
33+
TextSubstitutionRule(QRegularExpression regex, Value<QString> newText);
34+
35+
const QRegularExpression &regex() const { return m_regex; }
36+
const Value<QString> &newText() const { return m_newText; }
37+
38+
private:
39+
QRegularExpression m_regex;
40+
Value<QString> m_newText;
41+
};
42+
43+
class ReplaceTextAction : public Action
44+
{
45+
public:
46+
ReplaceTextAction(std::vector<TextSubstitutionRule> rules);
47+
48+
const std::vector<TextSubstitutionRule> &rules() const { return m_rules; }
49+
50+
bool async() const override;
51+
52+
protected:
53+
void executeImpl(const ActionExecutionArguments &args) override;
54+
55+
private:
56+
std::vector<TextSubstitutionRule> m_rules;
57+
};
58+
59+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
Input Actions - Input handler that executes user-defined actions
3+
Copyright (C) 2024-2026 Marcin Woźniak
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "CanReplaceTextCondition.h"
20+
#include <libinputactions/actions/ReplaceTextAction.h>
21+
#include <libinputactions/interfaces/TextInput.h>
22+
23+
namespace InputActions
24+
{
25+
26+
CanReplaceTextCondition::CanReplaceTextCondition(std::vector<TextSubstitutionRule> rules)
27+
: m_rules(std::move(rules))
28+
{
29+
}
30+
31+
CanReplaceTextCondition::~CanReplaceTextCondition() = default;
32+
33+
bool CanReplaceTextCondition::evaluateImpl(const ConditionEvaluationArguments &arguments)
34+
{
35+
return std::ranges::any_of(m_rules, [](const auto &rule) {
36+
return g_textInput->canReplace(rule.regex());
37+
});
38+
}
39+
40+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Input Actions - Input handler that executes user-defined actions
3+
Copyright (C) 2024-2026 Marcin Woźniak
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#pragma once
20+
21+
#include "Condition.h"
22+
23+
namespace InputActions
24+
{
25+
26+
class TextSubstitutionRule;
27+
28+
class CanReplaceTextCondition : public Condition
29+
{
30+
public:
31+
CanReplaceTextCondition(std::vector<TextSubstitutionRule> rules);
32+
~CanReplaceTextCondition() override;
33+
34+
const std::vector<TextSubstitutionRule> &rules() const { return m_rules; }
35+
36+
protected:
37+
bool evaluateImpl(const ConditionEvaluationArguments &arguments) override;
38+
39+
private:
40+
std::vector<TextSubstitutionRule> m_rules;
41+
};
42+
43+
}

src/libinputactions/config/parsers/core.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
#include <libinputactions/actions/CommandAction.h>
3232
#include <libinputactions/actions/InputAction.h>
3333
#include <libinputactions/actions/PlasmaGlobalShortcutAction.h>
34+
#include <libinputactions/actions/ReplaceTextAction.h>
3435
#include <libinputactions/actions/SleepAction.h>
3536
#include <libinputactions/actions/TriggerAction.h>
37+
#include <libinputactions/conditions/CanReplaceTextCondition.h>
3638
#include <libinputactions/conditions/ConditionGroup.h>
3739
#include <libinputactions/conditions/VariableCondition.h>
3840
#include <libinputactions/config/ConfigIssue.h>
@@ -154,6 +156,8 @@ void NodeParser<std::unique_ptr<Action>>::parse(const Node *node, std::unique_pt
154156
} else if (const auto *plasmaShortcutNode = node->at("plasma_shortcut")) {
155157
const auto shortcut = parseSeparatedString2<QString>(plasmaShortcutNode, ',');
156158
result = std::make_unique<PlasmaGlobalShortcutAction>(shortcut.first, shortcut.second);
159+
} else if (const auto *replaceTextNode = node->at("replace_text")) {
160+
result = std::make_unique<ReplaceTextAction>(replaceTextNode->as<std::vector<TextSubstitutionRule>>(true));
157161
} else if (const auto *sleepActionNode = node->at("sleep")) {
158162
result = std::make_unique<SleepAction>(sleepActionNode->as<std::chrono::milliseconds>());
159163
} else if (const auto *oneNode = node->at("one")) {
@@ -218,6 +222,10 @@ std::shared_ptr<Condition> parseCondition(const Node *node, const VariableManage
218222
return group;
219223
}
220224

225+
if (const auto *canReplaceTextNode = node->at("can_replace_text")) {
226+
return std::make_shared<CanReplaceTextCondition>(canReplaceTextNode->as<std::vector<TextSubstitutionRule>>(true));
227+
}
228+
221229
if (isLegacy(node)) {
222230
g_configIssueManager->addIssue(DeprecatedFeatureConfigIssue(node, DeprecatedFeature::LegacyConditions));
223231

@@ -576,6 +584,14 @@ struct NodeParser<Range<T>>
576584
};
577585
template struct NodeParser<Range<qreal>>;
578586

587+
template<>
588+
void NodeParser<TextSubstitutionRule>::parse(const Node *node, TextSubstitutionRule &result)
589+
{
590+
const auto regex = node->at("regex", true)->as<QRegularExpression>();
591+
const auto newText = node->at("replace", true)->as<QString>();
592+
result = {regex, newText};
593+
}
594+
579595
template<>
580596
void NodeParser<std::unique_ptr<TriggerAction>>::parse(const Node *node, std::unique_ptr<TriggerAction> &result)
581597
{

src/libinputactions/handlers/MultiTouchMotionTriggerHandler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void MultiTouchMotionTriggerHandler::updateVariables(const InputDevice *sender)
105105
bool hasThumb{};
106106

107107
const auto touchPoints = sender ? sender->physicalState().validTouchPoints() : std::vector<const TouchPoint *>();
108-
for (size_t i = 0; i < s_fingerVariableCount; i++) {
108+
for (size_t i = 0; i < FINGER_VARIABLE_COUNT; i++) {
109109
const auto fingerVariableNumber = i + 1;
110110
auto initialPosition = g_variableManager->getVariable<QPointF>(QString("finger_%1_initial_position_percentage").arg(fingerVariableNumber));
111111
auto position = g_variableManager->getVariable<QPointF>(QString("finger_%1_position_percentage").arg(fingerVariableNumber));
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
Input Actions - Input handler that executes user-defined actions
3+
Copyright (C) 2024-2026 Marcin Woźniak
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "TextInput.h"
20+
#include <libinputactions/helpers/QThread.h>
21+
#include <libinputactions/variables/VariableManager.h>
22+
23+
namespace InputActions
24+
{
25+
26+
bool TextInput::canReplace(const QRegularExpression &regex)
27+
{
28+
const auto text = surroundingText();
29+
if (!text) {
30+
return false;
31+
}
32+
33+
const auto match = regex.match(text.value());
34+
if (!match.hasMatch()) {
35+
return false;
36+
}
37+
38+
const auto cursorPos = surroundingTextCursorPosition();
39+
return !cursorPos || cursorPos == match.capturedEnd();
40+
}
41+
42+
void TextInput::replace(const QRegularExpression &regex, const Value<QString> &after)
43+
{
44+
if (!canReplace(regex)) {
45+
return;
46+
}
47+
48+
const auto match = regex.match(surroundingText().value());
49+
for (auto i = 0; i < REGEX_MATCH_VARIABLE_COUNT; i++) {
50+
auto *variable = g_variableManager->getVariable(QString("match_%1").arg(i));
51+
if (i > match.lastCapturedIndex()) {
52+
variable->set({});
53+
continue;
54+
}
55+
56+
variable->set(match.capturedTexts()[i]);
57+
}
58+
59+
const auto value = after.get();
60+
if (!value) {
61+
return;
62+
}
63+
64+
deleteSurroundingText(match.capturedLength(), 0);
65+
QThreadHelpers::runOnThread(QThreadHelpers::mainThread(), [this, value = value.value()]() {
66+
writeText(value);
67+
});
68+
}
69+
70+
}

0 commit comments

Comments
 (0)