Skip to content

Commit 8e3d1c8

Browse files
committed
scripting: allow creation of custom variables
1 parent 54ee11c commit 8e3d1c8

17 files changed

Lines changed: 477 additions & 40 deletions

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ set(libinputactions_SRCS
8484
libinputactions/interfaces/WindowProvider.cpp
8585
libinputactions/scripting/modules/core/Config.cpp
8686
libinputactions/scripting/modules/core/CoreModule.cpp
87+
libinputactions/scripting/modules/core/StoredVariableWrapper.cpp
88+
libinputactions/scripting/modules/core/VariableRegistryWrapper.cpp
89+
libinputactions/scripting/modules/core/VariableWrapper.cpp
8790
libinputactions/scripting/modules/fs/File.cpp
8891
libinputactions/scripting/modules/main/MainModule.cpp
8992
libinputactions/scripting/modules/main/Script.cpp

src/libinputactions/InputActionsMain.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,12 @@ void InputActionsMain::setMissingImplementations()
9898
setMissingImplementation(g_configLoader);
9999
setMissingImplementation(g_globalConfig);
100100
setMissingImplementation(g_inputBackend);
101-
setMissingImplementation(g_scriptingEngine);
102101
setMissingImplementation(g_strokeRecorder);
103102
setMissingImplementation(g_variableRegistry);
103+
104+
if (!g_scriptingEngine) {
105+
g_scriptingEngine = std::make_shared<ScriptingEngine>(*g_variableRegistry.get());
106+
}
104107
}
105108

106109
void InputActionsMain::registerGlobalVariables(VariableRegistry *variableRegistry, std::shared_ptr<PointerPositionGetter> pointerPositionGetter,

src/libinputactions/config/ConfigLoader.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
*/
1818

1919
#include "ConfigLoader.h"
20+
#include "ConfigIssue.h"
2021
#include "ConfigIssueManager.h"
2122
#include "GlobalConfig.h"
23+
#include "InputActionsMain.h"
2224
#include "Node.h"
23-
#include "config/ConfigIssue.h"
24-
#include "interfaces/ConfigProvider.h"
2525
#include "parsers/containers.h"
2626
#include "parsers/core.h"
2727
#include "parsers/utils.h"
@@ -35,11 +35,13 @@
3535
#include <libinputactions/handlers/TouchscreenTriggerHandler.h>
3636
#include <libinputactions/input/backends/LibevdevComplementaryInputBackend.h>
3737
#include <libinputactions/input/devices/InputDeviceRule.h>
38+
#include <libinputactions/interfaces/ConfigProvider.h>
3839
#include <libinputactions/interfaces/NotificationManager.h>
3940
#include <libinputactions/scripting/ScriptingEngine.h>
4041
#include <libinputactions/scripting/modules/core/Config.h>
4142
#include <libinputactions/scripting/modules/core/CoreModule.h>
4243
#include <libinputactions/scripting/modules/main/Script.h>
44+
#include <libinputactions/variables/VariableRegistry.h>
4345

4446
namespace InputActions
4547
{
@@ -79,18 +81,22 @@ bool ConfigLoader::load(const ConfigLoadSettings &settings)
7981
};
8082

8183
auto currentEngine = g_scriptingEngine;
84+
auto currentVariableRegistry = g_variableRegistry;
8285
try {
8386
qCDebug(INPUTACTIONS, "Reloading config");
8487
const auto rawConfig = settings.config.value_or(g_configProvider->currentConfig());
8588

8689
g_configIssueManager = std::make_shared<ConfigIssueManager>(rawConfig);
87-
g_scriptingEngine = std::make_shared<ScriptingEngine>();
90+
g_variableRegistry = std::make_shared<VariableRegistry>();
91+
g_inputActions->registerGlobalVariables(g_variableRegistry.get());
92+
g_scriptingEngine = std::make_shared<ScriptingEngine>(*g_variableRegistry.get());
8893
auto config = createConfig(rawConfig);
8994
destroyEngine(currentEngine);
9095
activateConfig(std::move(config), true);
9196
} catch (const ConfigException &e) {
9297
destroyEngine(g_scriptingEngine);
9398
g_scriptingEngine = currentEngine;
99+
g_variableRegistry = currentVariableRegistry;
94100
g_configIssueManager->addIssue(e);
95101
}
96102

@@ -158,6 +164,10 @@ ConfigData ConfigLoader::createConfig(const QString &raw)
158164
}
159165
}
160166

167+
if (auto *coreModule = g_scriptingEngine->coreModule()) {
168+
coreModule->variableRegistry()->disableRegistration();
169+
}
170+
161171
loadMember(config.autoReload, root->at("autoreload"));
162172
loadMember(config.allowExternalVariableAccess, root->at("external_variable_access"));
163173
if (const auto *notificationsNode = root->mapAt("notifications")) {
@@ -195,7 +205,7 @@ void ConfigLoader::activateConfig(ConfigData config, bool initialize)
195205
g_actionExecutor->clearQueue();
196206
g_actionExecutor->waitForDone();
197207

198-
const auto *coreModule = g_scriptingEngine->coreModule();
208+
auto *coreModule = g_scriptingEngine->coreModule();
199209
if (coreModule) {
200210
Q_EMIT coreModule->config()->aboutToBeActivated();
201211
}

src/libinputactions/globals.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,17 @@ Q_ENUM_NS(TriggerType)
133133
Q_DECLARE_FLAGS(TriggerTypes, TriggerType)
134134
Q_DECLARE_OPERATORS_FOR_FLAGS(TriggerTypes)
135135

136+
enum class VariableType
137+
{
138+
Boolean,
139+
CursorShape,
140+
KeyboardModifiers,
141+
Number,
142+
Point,
143+
String,
144+
};
145+
Q_ENUM_NS(VariableType)
146+
136147
static inline TriggerType operator~(TriggerType value)
137148
{
138149
return TriggerType(~static_cast<uint32_t>(value));

src/libinputactions/scripting/ScriptingEngine.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ namespace InputActions
3737
static const std::chrono::milliseconds WATCHDOG_TIMER_TIMEOUT{2000};
3838
static const std::chrono::milliseconds WATCHDOG_TIMER_RESET_INTERVAL{1000};
3939

40-
ScriptingEngine::ScriptingEngine() = default;
40+
ScriptingEngine::ScriptingEngine(VariableRegistry &variableRegistry)
41+
: m_variableRegistry(variableRegistry)
42+
{
43+
}
4144

4245
ScriptingEngine::~ScriptingEngine()
4346
{
@@ -69,10 +72,11 @@ void ScriptingEngine::initialize()
6972
}
7073
)");
7174

72-
m_coreModule = std::make_unique<CoreModule>();
75+
m_coreModule = std::make_unique<CoreModule>(*this, m_variableRegistry);
7376
QJSEngine::setObjectOwnership(m_coreModule.get(), QJSEngine::CppOwnership);
7477
auto coreModule = m_engine->newQObject(m_coreModule.get());
7578
coreModule.setProperty("KeyboardModifier", newEnum<KeyboardModifier>());
79+
coreModule.setProperty("VariableType", newEnum<VariableType>());
7680
registerBuiltinModule("inputactions/core", coreModule);
7781

7882
auto desktopModule = m_engine->newObject();

src/libinputactions/scripting/ScriptingEngine.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@
2424
#include <QObject>
2525
#include <memory>
2626

27+
Q_DECLARE_LOGGING_CATEGORY(INPUTACTIONS_SCRIPTING)
28+
2729
namespace InputActions
2830
{
2931

3032
class CoreModule;
3133
class Promise;
34+
class VariableRegistry;
3235

3336
/**
3437
* Lazily initializated.
@@ -40,7 +43,7 @@ class ScriptingEngine : public QObject
4043
Q_OBJECT
4144

4245
public:
43-
ScriptingEngine();
46+
ScriptingEngine(VariableRegistry &variableRegistry);
4447
~ScriptingEngine() override;
4548

4649
/**
@@ -98,8 +101,9 @@ private slots:
98101
}
99102
QJSValue newEnum(const QMetaEnum &metaEnum);
100103

101-
std::optional<QJSEngine> m_engine;
104+
VariableRegistry &m_variableRegistry;
102105

106+
std::optional<QJSEngine> m_engine;
103107
std::unique_ptr<CoreModule> m_coreModule;
104108
std::map<QString, QJSValue> m_builtinModules;
105109

src/libinputactions/scripting/modules/core/CoreModule.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,36 @@
1818

1919
#include "CoreModule.h"
2020
#include "Config.h"
21+
#include "VariableRegistryWrapper.h"
2122
#include <QJSEngine>
2223
#include <libinputactions/input/backends/InputBackend.h>
2324
#include <libinputactions/scripting/ScriptingEngine.h>
24-
#include <libinputactions/variables/VariableRegistry.h>
2525

2626
namespace InputActions
2727
{
2828

29-
CoreModule::CoreModule()
30-
: m_config(std::make_unique<Config>())
29+
CoreModule::CoreModule(ScriptingEngine &engine, VariableRegistry &variableRegistry)
30+
: m_variableRegistry(variableRegistry, engine)
3131
{
32-
QJSEngine::setObjectOwnership(m_config.get(), QJSEngine::CppOwnership);
32+
QJSEngine::setObjectOwnership(&m_config, QJSEngine::CppOwnership);
33+
QJSEngine::setObjectOwnership(&m_variableRegistry, QJSEngine::CppOwnership);
3334
}
3435

3536
CoreModule::~CoreModule() = default;
3637

37-
Config *CoreModule::config() const
38+
Config *CoreModule::config()
3839
{
39-
return m_config.get();
40+
return &m_config;
4041
}
4142

4243
InputBackend *CoreModule::input() const
4344
{
4445
return g_inputBackend.get();
4546
}
4647

47-
VariableRegistry *CoreModule::variableRegistry() const
48+
VariableRegistryWrapper *CoreModule::variableRegistry()
4849
{
49-
return g_variableRegistry.get();
50+
return &m_variableRegistry;
5051
}
5152

5253
}

src/libinputactions/scripting/modules/core/CoreModule.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,35 @@
1818

1919
#pragma once
2020

21+
#include "Config.h"
22+
#include "VariableRegistryWrapper.h"
2123
#include <QObject>
2224

2325
namespace InputActions
2426
{
2527

26-
class Config;
2728
class InputBackend;
2829
class ScriptingEngine;
29-
class VariableRegistry;
3030

3131
class CoreModule : public QObject
3232
{
3333
Q_OBJECT
3434

3535
Q_PROPERTY(Config *config READ config)
3636
Q_PROPERTY(InputBackend *input READ input)
37-
Q_PROPERTY(VariableRegistry *variableRegistry READ variableRegistry)
37+
Q_PROPERTY(VariableRegistryWrapper *variableRegistry READ variableRegistry)
3838

3939
public:
40-
CoreModule();
40+
CoreModule(ScriptingEngine &engine, VariableRegistry &variableRegistry);
4141
~CoreModule() override;
4242

43-
Config *config() const;
43+
Config *config();
4444
InputBackend *input() const;
45-
VariableRegistry *variableRegistry() const;
45+
VariableRegistryWrapper *variableRegistry();
4646

4747
private:
48-
ScriptingEngine *m_engine;
49-
std::unique_ptr<Config> m_config;
48+
Config m_config;
49+
VariableRegistryWrapper m_variableRegistry;
5050
};
5151

5252
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 "StoredVariableWrapper.h"
20+
#include "VariableRegistryWrapper.h"
21+
#include <libinputactions/scripting/ScriptingEngine.h>
22+
#include <libinputactions/variables/StoredVariable.h>
23+
24+
namespace InputActions
25+
{
26+
27+
StoredVariableWrapper::StoredVariableWrapper(StoredVariable &variable, ScriptingEngine &engine)
28+
: VariableWrapper(variable, engine)
29+
, m_variable(variable)
30+
, m_engine(engine)
31+
{
32+
}
33+
34+
void StoredVariableWrapper::setValue(const QJSValue &value) const
35+
{
36+
const auto variant = VariableRegistryWrapper::jsValueToVariant(value, type());
37+
if (!variant) {
38+
m_engine.ensureEngine().throwError(QString("New value does not match the variable's type."));
39+
return;
40+
}
41+
42+
m_variable.setValue(variant.value());
43+
}
44+
45+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 "VariableWrapper.h"
22+
#include <QJSValue>
23+
#include <QObject>
24+
25+
namespace InputActions
26+
{
27+
28+
class ScriptingEngine;
29+
class StoredVariable;
30+
31+
class StoredVariableWrapper : public VariableWrapper
32+
{
33+
Q_OBJECT
34+
Q_PROPERTY(QJSValue value READ value WRITE setValue OVERRIDE)
35+
36+
public:
37+
StoredVariableWrapper(StoredVariable &variable, ScriptingEngine &engine);
38+
39+
void setValue(const QJSValue &value) const;
40+
41+
private:
42+
StoredVariable &m_variable;
43+
44+
ScriptingEngine &m_engine;
45+
};
46+
47+
}

0 commit comments

Comments
 (0)