├── LICENSE ├── README.md └── TheWiggler ├── QtUtils.h ├── TheWiggler.pro ├── TheWiggler.pro.user ├── main.cpp ├── main.qml ├── qml.qrc ├── releases ├── TheWiggler-0.1.0-Linux.tar.gz ├── TheWiggler-0.1.0-OSX.zip └── TheWiggler-0.1.0-Win64.zip ├── wigglecore.cpp ├── wigglecore.h ├── wigglecoreworker.cpp ├── wigglecoreworker.h ├── wiggledata.h ├── wiggleinput.cpp └── wiggleinput.h /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TheWiggler 2 | 3 | This is a small Qt / QML / C++ application that moves your mouse to prevent screensavers and auto locking. It is moderately configurable via a QML UI but typically you can run it with the default settings. 4 | 5 | Currently, it builds on **Windows**, **macOS** and **Ubuntu** and releases for each can be found on the **releases** page. 6 | 7 | # Build instructions 8 | 9 | Qt is the main dependency and can be downloaded for free from https://www.qt.io. 10 | 11 | - For Windows users you will also need Visual Studio 2017 installed if you are using the latest Qt release (5.14.2). 12 | - For macOS users you will need XCode which the Qt installer should prompt you to install if it is missing. 13 | - For Linux users users you will need an X11 environment and on Ubuntu specifically the following additional packages installed: **build-essential** and either **libgl-dev** or **libgl-mesa-dev** depending on your Ubuntu version. If you intend to deploy the application Ubuntu 16.04 is recommended as currently this is the version of Ubuntu the deployment tool works on. 14 | 15 | Once the dependencies are installed you should be able to open the project in Qt Creator and build / run it. 16 | 17 | Currently, the build has only been tested on Windows 10, macOS High Sierra 10.13 and Ubuntu 16.04 + 20.04. 18 | 19 | # Deployment instructions 20 | 21 | Once you have built a release version of the application you may wish to deploy so it can be run on other machines by collecting all the shared library dependencies. 22 | 23 | # Windows deployment 24 | 25 | For Windows deployment you can use the `windeployqt.exe` which is found in the Qt install directory. For example: 26 | 27 | ``` 28 | C:/Qt/5.14.0/msvc2016_64/bin/windeployqt.exe 29 | ``` 30 | 31 | Simply run this tool using the following parameters: 32 | 33 | ``` 34 | ./windeployqt.exe {path-to-build-folder}\TheWiggler.exe --qmldir {path-to-repo-root}\TheWiggler 35 | ``` 36 | 37 | This will copy all the dependencies required to run `TheWiggler.exe` on any machine into the folder containing `TheWiggler.exe`. 38 | 39 | # macOS deployment 40 | 41 | For OSX deployment you can use the `macdeployqt` tool found in the Qt install directory. For example: 42 | 43 | ``` 44 | $HOME/Qt/5.14.2/clang_64/bin/macdeployqt 45 | ``` 46 | 47 | Simply run this tool using the following parameters: 48 | 49 | ``` 50 | ./macdeployqt {path-to-build-folder}\TheWiggler.app -qmldir={path-to-repo-root}\TheWiggler 51 | ``` 52 | 53 | This will pack your `.app` file with all the required Qt framework dependencies required to run the app on any machine. 54 | 55 | # Ubuntu deployment 56 | 57 | For Ubuntu deployment you can use the unoffical linuxdeployqt tool available from `https://github.com/probonopd/linuxdeployqt`. 58 | 59 | For compatibility reasons this tool is maintained such that it only works on the current oldest Ubuntu LTS release (currently 16.04), thus you should use Ubuntu 16.04 for both building and deployment if deployment is your goal. 60 | 61 | - Obtain and download the linuxdeployqt app image from the linuxdeployqt github release page 62 | - Export your Qt binary folder so the Qt build tools are available from the command line. For example: 63 | ``` 64 | export PATH=~/Qt/5.14.2/gcc_64/:$PATH 65 | ``` 66 | - Run the linuxdeployqt tool using the following parameters: 67 | ``` 68 | ./linuxdeployqt {path-to-build-folder}\TheWiggler -qmldir={absolute-path-to-repo-root}\TheWiggler 69 | ``` 70 | **Note:** For some reason the current version of linuxdeployqt does not appear to work if the qmldir path specified is not an absolute path. 71 | 72 | This will copy all the dependencies required to run `TheWiggler` on any machine into the folder containing `TheWiggler`. 73 | 74 | # Known issues 75 | 76 | - On Ubuntu VM guests under Virtual Box you must disable `Input->Mouse Integration` otherwise the mouse cannot be programmatically moved. 77 | -------------------------------------------------------------------------------- /TheWiggler/QtUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef QTUTILS_H 2 | #define QTUTILS_H 3 | 4 | #include 5 | 6 | // These macros define the following: 7 | // 1. member variable 8 | // 2. read function for the member variable 9 | // 3. write function for the member variable 10 | // 4. QT property macro to define the property so QT understands it 11 | // Notes: 12 | // - For the qmlName ensure the variable starts with a capital letter 13 | // - These macros do NOT define the onChange signals 14 | // - The CREF variant makes the setter take a const reference type 15 | #define READ_WRITE_QML_PROPERTY(type, qmlName, defaultValue) \ 16 | public: \ 17 | Q_PROPERTY(type qmlName MEMBER m_##qmlName READ get##qmlName WRITE set##qmlName) \ 18 | void set##qmlName(type v) { m_##qmlName = v; } \ 19 | type get##qmlName() const { return m_##qmlName; } \ 20 | private: \ 21 | type m_##qmlName = defaultValue; 22 | 23 | #define READ_WRITE_QML_PROPERTY_CREF(type, qmlName, defaultValue) \ 24 | public: \ 25 | Q_PROPERTY(type qmlName MEMBER m_##qmlName READ get##qmlName WRITE set##qmlName) \ 26 | void set##qmlName(const type& v) { m_##qmlName = v; } \ 27 | type get##qmlName() const { return m_##qmlName; } \ 28 | private: \ 29 | type m_##qmlName = defaultValue; 30 | 31 | #endif // QTUTILS_H 32 | -------------------------------------------------------------------------------- /TheWiggler/TheWiggler.pro: -------------------------------------------------------------------------------- 1 | QT += quick 2 | 3 | CONFIG += c++14 4 | 5 | # The following define makes your compiler emit warnings if you use 6 | # any Qt feature that has been marked deprecated (the exact warnings 7 | # depend on your compiler). Refer to the documentation for the 8 | # deprecated API to know how to port your code away from it. 9 | DEFINES += QT_DEPRECATED_WARNINGS 10 | 11 | # You can also make your code fail to compile if it uses deprecated APIs. 12 | # In order to do so, uncomment the following line. 13 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 14 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 15 | 16 | SOURCES += \ 17 | main.cpp \ 18 | wigglecore.cpp \ 19 | wigglecoreworker.cpp \ 20 | wiggleinput.cpp 21 | 22 | RESOURCES += qml.qrc 23 | 24 | win32 { 25 | LIBS += -luser32 26 | } 27 | 28 | linux-g++ | linux-g++-64 | linux-g++-32 { 29 | LIBS += -lX11 30 | } 31 | 32 | # Additional import path used to resolve QML modules in Qt Creator's code model 33 | QML_IMPORT_PATH = 34 | 35 | # Additional import path used to resolve QML modules just for Qt Quick Designer 36 | QML_DESIGNER_IMPORT_PATH = 37 | 38 | # Default rules for deployment. 39 | qnx: target.path = /tmp/$${TARGET}/bin 40 | else: unix:!android: target.path = /opt/$${TARGET}/bin 41 | !isEmpty(target.path): INSTALLS += target 42 | 43 | HEADERS += \ 44 | QtUtils.h \ 45 | wigglecore.h \ 46 | wigglecoreworker.h \ 47 | wiggledata.h \ 48 | wiggleinput.h 49 | -------------------------------------------------------------------------------- /TheWiggler/TheWiggler.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {d416a51c-35b1-4d74-9319-fb677327cb93} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | qt2 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | -fno-delayed-template-parsing 60 | 61 | true 62 | 63 | 64 | 65 | ProjectExplorer.Project.Target.0 66 | 67 | Desktop Qt 5.14.0 MSVC2017 64bit 68 | Desktop Qt 5.14.0 MSVC2017 64bit 69 | qt.qt5.5140.win64_msvc2017_64_kit 70 | 0 71 | 0 72 | 0 73 | 74 | C:/Users/aaron/Documents/Dev/Repos/TheWiggler/build-TheWiggler-Desktop_Qt_5_14_0_MSVC2017_64bit-Debug 75 | 76 | 77 | true 78 | QtProjectManager.QMakeBuildStep 79 | true 80 | 81 | false 82 | false 83 | false 84 | 85 | 86 | true 87 | Qt4ProjectManager.MakeStep 88 | 89 | false 90 | 91 | 92 | false 93 | 94 | 2 95 | Build 96 | Build 97 | ProjectExplorer.BuildSteps.Build 98 | 99 | 100 | 101 | true 102 | Qt4ProjectManager.MakeStep 103 | 104 | true 105 | clean 106 | 107 | false 108 | 109 | 1 110 | Clean 111 | Clean 112 | ProjectExplorer.BuildSteps.Clean 113 | 114 | 2 115 | false 116 | 117 | Debug 118 | Qt4ProjectManager.Qt4BuildConfiguration 119 | 2 120 | 121 | 122 | C:/Users/aaron/Documents/Dev/Repos/TheWiggler/build-TheWiggler-Desktop_Qt_5_14_0_MSVC2017_64bit-Release 123 | 124 | 125 | true 126 | QtProjectManager.QMakeBuildStep 127 | false 128 | 129 | false 130 | false 131 | true 132 | 133 | 134 | true 135 | Qt4ProjectManager.MakeStep 136 | 137 | false 138 | 139 | 140 | false 141 | 142 | 2 143 | Build 144 | Build 145 | ProjectExplorer.BuildSteps.Build 146 | 147 | 148 | 149 | true 150 | Qt4ProjectManager.MakeStep 151 | 152 | true 153 | clean 154 | 155 | false 156 | 157 | 1 158 | Clean 159 | Clean 160 | ProjectExplorer.BuildSteps.Clean 161 | 162 | 2 163 | false 164 | 165 | Release 166 | Qt4ProjectManager.Qt4BuildConfiguration 167 | 0 168 | 169 | 170 | C:/Users/aaron/Documents/Dev/Repos/TheWiggler/build-TheWiggler-Desktop_Qt_5_14_0_MSVC2017_64bit-Profile 171 | 172 | 173 | true 174 | QtProjectManager.QMakeBuildStep 175 | true 176 | 177 | false 178 | true 179 | true 180 | 181 | 182 | true 183 | Qt4ProjectManager.MakeStep 184 | 185 | false 186 | 187 | 188 | false 189 | 190 | 2 191 | Build 192 | Build 193 | ProjectExplorer.BuildSteps.Build 194 | 195 | 196 | 197 | true 198 | Qt4ProjectManager.MakeStep 199 | 200 | true 201 | clean 202 | 203 | false 204 | 205 | 1 206 | Clean 207 | Clean 208 | ProjectExplorer.BuildSteps.Clean 209 | 210 | 2 211 | false 212 | 213 | Profile 214 | Qt4ProjectManager.Qt4BuildConfiguration 215 | 0 216 | 217 | 3 218 | 219 | 220 | 0 221 | Deploy 222 | Deploy 223 | ProjectExplorer.BuildSteps.Deploy 224 | 225 | 1 226 | ProjectExplorer.DefaultDeployConfiguration 227 | 228 | 1 229 | 230 | 231 | dwarf 232 | 233 | cpu-cycles 234 | 235 | 236 | 250 237 | 238 | -e 239 | cpu-cycles 240 | --call-graph 241 | dwarf,4096 242 | -F 243 | 250 244 | 245 | -F 246 | true 247 | 4096 248 | false 249 | false 250 | 1000 251 | 252 | true 253 | 254 | false 255 | false 256 | false 257 | false 258 | true 259 | 0.01 260 | 10 261 | true 262 | kcachegrind 263 | 1 264 | 25 265 | 266 | 1 267 | true 268 | false 269 | true 270 | valgrind 271 | 272 | 0 273 | 1 274 | 2 275 | 3 276 | 4 277 | 5 278 | 6 279 | 7 280 | 8 281 | 9 282 | 10 283 | 11 284 | 12 285 | 13 286 | 14 287 | 288 | 2 289 | 290 | Qt4ProjectManager.Qt4RunConfiguration:C:/Users/aaron/Documents/Dev/Repos/TheWiggler/TheWiggler/TheWiggler.pro 291 | C:/Users/aaron/Documents/Dev/Repos/TheWiggler/TheWiggler/TheWiggler.pro 292 | 293 | false 294 | 295 | false 296 | true 297 | true 298 | false 299 | false 300 | true 301 | 302 | C:/Users/aaron/Documents/Dev/Repos/TheWiggler/build-TheWiggler-Desktop_Qt_5_14_0_MSVC2017_64bit-Debug 303 | 304 | 1 305 | 306 | 307 | 308 | ProjectExplorer.Project.TargetCount 309 | 1 310 | 311 | 312 | ProjectExplorer.Project.Updater.FileVersion 313 | 22 314 | 315 | 316 | Version 317 | 22 318 | 319 | 320 | -------------------------------------------------------------------------------- /TheWiggler/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 13 | 14 | QGuiApplication app(argc, argv); 15 | QQmlApplicationEngine engine; 16 | 17 | qApp->setApplicationName("The Wiggler"); 18 | qApp->setApplicationVersion("0.1.0"); 19 | qApp->setOrganizationName("aatwo"); 20 | 21 | qRegisterMetaType("int64_t"); 22 | qRegisterMetaType("WiggleData"); 23 | 24 | auto wiggleCore = std::make_unique(); 25 | engine.rootContext()->setContextProperty("wiggleCore", wiggleCore.get()); 26 | 27 | auto wiggleDataFactory = std::make_unique(); 28 | engine.rootContext()->setContextProperty("wiggleDataFactory", wiggleDataFactory.get()); 29 | 30 | const QUrl url(QStringLiteral("qrc:/main.qml")); 31 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, 32 | &app, [url](QObject *obj, const QUrl &objUrl) { 33 | if (!obj && url == objUrl) 34 | QCoreApplication::exit(-1); 35 | }, Qt::QueuedConnection); 36 | engine.load(url); 37 | 38 | return app.exec(); 39 | } 40 | -------------------------------------------------------------------------------- /TheWiggler/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.14 2 | import QtQuick.Window 2.14 3 | import QtQuick.Controls 2.5 4 | 5 | Window { 6 | visible: true 7 | width: 640 8 | height: 480 9 | title: qsTr("The Wiggler") 10 | Component.onCompleted: init() 11 | 12 | property bool wigglerCoreIsRunning: false 13 | property int buttonAreaHeight: 40 14 | 15 | function init() 16 | { 17 | loadCurrentWiggleData() 18 | } 19 | 20 | function loadCurrentWiggleData() 21 | { 22 | const wiggleData = wiggleCore.getWiggleData() 23 | loadWiggleData(wiggleData) 24 | } 25 | 26 | function loadWiggleData(wiggleData) 27 | { 28 | wigglerCoreIsRunning = wiggleData.IsRunning 29 | wigglerIntervalEdit.value = wiggleData.WiggleIntervalMs 30 | wigglerDurationEdit.value = wiggleData.WiggleDurationMs 31 | horizontalMoveDistanceEdit.value = wiggleData.HorizontalMoveDistancePixels 32 | verticalMoveDistanceEdit.value = wiggleData.VerticalMoveDistancePixels 33 | alternateHorizontalDirectionEdit.checked = wiggleData.FlipHorizontalDirection 34 | alternateVerticalDirectionEdit.checked = wiggleData.FlipVerticalDirection 35 | moveHorizontallyEdit.checked = wiggleData.MoveHorizontal 36 | moveVerticallyEdit.checked = wiggleData.MoveVertical 37 | } 38 | 39 | function getWiggleDataFromUI() 40 | { 41 | let wiggleData = wiggleDataFactory.make() 42 | 43 | wiggleData.WiggleIntervalMs = wigglerIntervalEdit.value 44 | wiggleData.WiggleDurationMs = wigglerDurationEdit.value 45 | wiggleData.IsRunning = true 46 | wiggleData.HorizontalMoveDistancePixels = horizontalMoveDistanceEdit.value 47 | wiggleData.VerticalMoveDistancePixels = verticalMoveDistanceEdit.value 48 | wiggleData.FlipHorizontalDirection = alternateHorizontalDirectionEdit.checked 49 | wiggleData.FlipVerticalDirection = alternateVerticalDirectionEdit.checked 50 | wiggleData.MoveHorizontal = moveHorizontallyEdit.checked 51 | wiggleData.MoveVertical = moveVerticallyEdit.checked 52 | 53 | return wiggleData 54 | } 55 | 56 | ScrollView { 57 | x: 0 58 | y: 0 59 | width: parent.width 60 | height: parent.height - buttonAreaHeight 61 | 62 | Column { 63 | 64 | enabled: !wigglerCoreIsRunning 65 | padding: 20 66 | spacing: 20 67 | 68 | GroupBox { 69 | title: "General" 70 | Column { 71 | spacing: 20 72 | Row { 73 | spacing: 20 74 | Label { 75 | text: "Wiggle interval" 76 | } 77 | SpinBox { 78 | id: wigglerIntervalEdit 79 | from: 0 80 | to: 1000 * 60 * 60 // One hour 81 | editable: true 82 | } 83 | Label { 84 | text: "ms" 85 | } 86 | } 87 | 88 | Row { 89 | spacing: 20 90 | Label { 91 | text: "Wiggle duration" 92 | } 93 | SpinBox { 94 | id: wigglerDurationEdit 95 | from: 0 96 | to: 1000 * 60 * 60 // One hour 97 | editable: true 98 | } 99 | Label { 100 | text: "ms" 101 | } 102 | } 103 | } 104 | } 105 | 106 | GroupBox { 107 | title: "Horizontal movement" 108 | Column { 109 | spacing: 20 110 | Row { 111 | spacing: 20 112 | Label { 113 | text: "Move horizontally" 114 | } 115 | CheckBox { 116 | id: moveHorizontallyEdit 117 | } 118 | } 119 | Row { 120 | spacing: 20 121 | enabled: moveHorizontallyEdit.checked 122 | Label { 123 | text: "Horizontal move distance" 124 | } 125 | SpinBox { 126 | id: horizontalMoveDistanceEdit 127 | from: 0 128 | to: 30000 129 | editable: true 130 | } 131 | Label { 132 | text: "pixels" 133 | } 134 | } 135 | 136 | Row { 137 | spacing: 20 138 | enabled: moveHorizontallyEdit.checked 139 | Label { 140 | text: "Alternate horizontal direction" 141 | } 142 | CheckBox { 143 | id: alternateHorizontalDirectionEdit 144 | } 145 | Label { 146 | text: "pixels" 147 | } 148 | } 149 | } 150 | } 151 | 152 | GroupBox { 153 | title: "Vertical params" 154 | Column { 155 | spacing: 20 156 | Row { 157 | spacing: 20 158 | Label { 159 | text: "Move vertically" 160 | } 161 | CheckBox { 162 | id: moveVerticallyEdit 163 | } 164 | } 165 | Row { 166 | spacing: 20 167 | enabled: moveVerticallyEdit.checked 168 | Label { 169 | text: "Vertical move distance" 170 | } 171 | SpinBox { 172 | id: verticalMoveDistanceEdit 173 | from: 0 174 | to: 30000 175 | editable: true 176 | } 177 | Label { 178 | text: "pixels" 179 | } 180 | } 181 | 182 | Row { 183 | spacing: 20 184 | enabled: moveVerticallyEdit.checked 185 | Label { 186 | text: "Alternate vertical direction" 187 | } 188 | CheckBox { 189 | id: alternateVerticalDirectionEdit 190 | } 191 | Label { 192 | text: "pixels" 193 | } 194 | } 195 | } 196 | } 197 | } 198 | } 199 | 200 | Button { 201 | text: "Stop" 202 | enabled: wigglerCoreIsRunning 203 | onClicked: { 204 | wigglerCoreIsRunning = false 205 | wiggleCore.stop() 206 | } 207 | x: 0 208 | y: parent.height - buttonAreaHeight 209 | width: parent.width * 0.5 210 | height: buttonAreaHeight 211 | } 212 | Button { 213 | text: "Start" 214 | enabled: !wigglerCoreIsRunning 215 | onClicked: { 216 | wigglerCoreIsRunning = true 217 | const wiggleData = getWiggleDataFromUI() 218 | wiggleCore.setWiggleData(wiggleData) 219 | } 220 | x: parent.width * 0.5 221 | y: parent.height - buttonAreaHeight 222 | width: parent.width * 0.5 223 | height: buttonAreaHeight 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /TheWiggler/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /TheWiggler/releases/TheWiggler-0.1.0-Linux.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatwo/TheWiggler/226a66c470e6c79fa48c7e68187c7d2fc4a5ceaf/TheWiggler/releases/TheWiggler-0.1.0-Linux.tar.gz -------------------------------------------------------------------------------- /TheWiggler/releases/TheWiggler-0.1.0-OSX.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatwo/TheWiggler/226a66c470e6c79fa48c7e68187c7d2fc4a5ceaf/TheWiggler/releases/TheWiggler-0.1.0-OSX.zip -------------------------------------------------------------------------------- /TheWiggler/releases/TheWiggler-0.1.0-Win64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatwo/TheWiggler/226a66c470e6c79fa48c7e68187c7d2fc4a5ceaf/TheWiggler/releases/TheWiggler-0.1.0-Win64.zip -------------------------------------------------------------------------------- /TheWiggler/wigglecore.cpp: -------------------------------------------------------------------------------- 1 | #include "wigglecore.h" 2 | 3 | #include 4 | #include 5 | 6 | WiggleCore::WiggleCore(QObject* parent) 7 | : QObject(parent) 8 | { 9 | wiggleWorker = new WiggleCoreWorker(); 10 | wiggleWorker->moveToThread(&wiggleWorkerThread); 11 | wiggleWorkerThread.start(); 12 | } 13 | 14 | WiggleCore::~WiggleCore() 15 | { 16 | if(wiggleWorkerThread.isRunning()) 17 | { 18 | wiggleWorkerThread.quit(); 19 | wiggleWorkerThread.wait(); 20 | } 21 | } 22 | 23 | void WiggleCore::setWiggleData(const WiggleData& wiggleData) 24 | { 25 | this->wiggleData = wiggleData; 26 | updateWiggleWorker(); 27 | } 28 | 29 | WiggleData WiggleCore::getWiggleData() const 30 | { 31 | return wiggleData; 32 | } 33 | 34 | void WiggleCore::start() 35 | { 36 | wiggleData.setIsRunning(true); 37 | updateWiggleWorker(); 38 | } 39 | 40 | void WiggleCore::stop() 41 | { 42 | wiggleData.setIsRunning(false); 43 | updateWiggleWorker(); 44 | } 45 | 46 | void WiggleCore::updateWiggleWorker() 47 | { 48 | QMetaObject::invokeMethod(wiggleWorker.data(), "setWiggleData", Q_ARG(WiggleData, this->wiggleData)); 49 | } 50 | -------------------------------------------------------------------------------- /TheWiggler/wigglecore.h: -------------------------------------------------------------------------------- 1 | #ifndef WIGGLECORE_H 2 | #define WIGGLECORE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | class WiggleCore : public QObject 13 | { 14 | Q_OBJECT 15 | public: 16 | 17 | explicit WiggleCore(QObject* parent = nullptr); 18 | ~WiggleCore(); 19 | 20 | Q_INVOKABLE void setWiggleData(const WiggleData& wiggleData); 21 | Q_INVOKABLE WiggleData getWiggleData() const; 22 | 23 | Q_INVOKABLE void start(); 24 | Q_INVOKABLE void stop(); 25 | 26 | private: 27 | 28 | void updateWiggleWorker(); 29 | 30 | WiggleData wiggleData; 31 | QPointer wiggleWorker; 32 | QThread wiggleWorkerThread; 33 | 34 | }; 35 | 36 | #endif // WIGGLECORE_H 37 | -------------------------------------------------------------------------------- /TheWiggler/wigglecoreworker.cpp: -------------------------------------------------------------------------------- 1 | #include "wigglecoreworker.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | WiggleCoreWorker::WiggleCoreWorker(QObject *parent) : QObject(parent) 12 | { 13 | intervalTimer = new QTimer(this); 14 | intervalTimer->setSingleShot(true); 15 | connect(intervalTimer, &QTimer::timeout, this, &WiggleCoreWorker::intervalExpired); 16 | 17 | mouseMoveUpdateTimer = new QTimer(this); 18 | mouseMoveUpdateTimer->setSingleShot(false); 19 | mouseMoveUpdateTimer->setInterval(mouseMoveUpdateIntervalMs); 20 | connect(mouseMoveUpdateTimer, &QTimer::timeout, this, &WiggleCoreWorker::mouseMoveUpdate); 21 | 22 | handleWiggleDataChanged(); 23 | } 24 | 25 | void WiggleCoreWorker::setWiggleData(const WiggleData& data) 26 | { 27 | this->data = data; 28 | handleWiggleDataChanged(); 29 | 30 | intervalTimer->stop(); 31 | mouseMoveUpdateTimer->stop(); 32 | 33 | if(data.getIsRunning()) 34 | intervalTimer->start(); 35 | } 36 | 37 | void WiggleCoreWorker::handleWiggleDataChanged() 38 | { 39 | intervalTimer->setInterval(data.getWiggleIntervalMs()); 40 | } 41 | 42 | void WiggleCoreWorker::computeRelativeMouseMovementValues(qint64 timestamp, float& x_OUT, float& y_OUT) 43 | { 44 | qint64 elapsedDurationMs = timestamp - mouseMoveStartTimestamp; 45 | double completionPercentage = static_cast(elapsedDurationMs) / static_cast(data.getWiggleDurationMs()); 46 | bool finished = (elapsedDurationMs >= data.getWiggleDurationMs()); 47 | 48 | x_OUT = 0; 49 | y_OUT = 0; 50 | 51 | if(data.getMoveHorizontal()) 52 | { 53 | if(finished) 54 | x_OUT = (data.getHorizontalMoveDistancePixels() - horizontalPixelsMoved) * horizontalMovementModifier; 55 | else 56 | { 57 | long requiredHorizontalMovedPixelCount = static_cast(ceil(completionPercentage * data.getHorizontalMoveDistancePixels())); 58 | x_OUT = (requiredHorizontalMovedPixelCount - horizontalPixelsMoved) * horizontalMovementModifier; 59 | } 60 | } 61 | 62 | if(data.getMoveVertical()) 63 | { 64 | if(finished) 65 | y_OUT = (data.getVerticalMoveDistancePixels() - verticalPixelsMoved) * verticalMovementModifier; 66 | else 67 | { 68 | long requiredVerticalMovedPixelCount = static_cast(ceil(completionPercentage * data.getVerticalMoveDistancePixels())); 69 | y_OUT = (requiredVerticalMovedPixelCount - verticalPixelsMoved) * verticalMovementModifier; 70 | } 71 | } 72 | } 73 | 74 | void WiggleCoreWorker::intervalExpired() 75 | { 76 | qDebug() << "interval expired"; 77 | 78 | horizontalPixelsMoved = 0; 79 | verticalPixelsMoved = 0; 80 | mouseMoveStartTimestamp = QDateTime::currentMSecsSinceEpoch(); 81 | mouseMoveUpdateTimer->start(); 82 | } 83 | 84 | void WiggleCoreWorker::mouseMoveUpdate() 85 | { 86 | qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); 87 | qint64 elapsedDurationMs = currentTimestamp - mouseMoveStartTimestamp; 88 | bool finished = (elapsedDurationMs >= data.getWiggleDurationMs()); 89 | float x, y; 90 | computeRelativeMouseMovementValues(currentTimestamp, x, y); 91 | 92 | qDebug() << "to move: x: " << x << ", y: " << y; 93 | WiggleInput::moveMouseRelative(x, y); 94 | 95 | horizontalPixelsMoved += abs(x); 96 | verticalPixelsMoved += abs(y); 97 | 98 | if(finished) 99 | { 100 | qDebug() << "duration expired"; 101 | qDebug() << "OVERALL PIXELS MOVED: x: " << horizontalPixelsMoved << ", y: " << verticalPixelsMoved; 102 | 103 | if(data.getFlipHorizontalDirection()) 104 | horizontalMovementModifier *= -1; 105 | 106 | if(data.getFlipVerticalDirection()) 107 | verticalMovementModifier *= -1; 108 | 109 | mouseMoveUpdateTimer->stop(); 110 | intervalTimer->start(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /TheWiggler/wigglecoreworker.h: -------------------------------------------------------------------------------- 1 | #ifndef WIGGLECOREWORKER_H 2 | #define WIGGLECOREWORKER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class WiggleCoreWorker : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit WiggleCoreWorker(QObject *parent = nullptr); 14 | 15 | public slots: 16 | 17 | void setWiggleData(const WiggleData& data); 18 | 19 | private: 20 | 21 | void handleWiggleDataChanged(); 22 | void computeRelativeMouseMovementValues(qint64 elapsedDurationMs, float& x_OUT, float& y_OUT); 23 | 24 | void intervalExpired(); 25 | void mouseMoveUpdate(); 26 | void moveMouseRelative(long x, long y); 27 | void moveMouseAbsolute(long x, long y); 28 | 29 | WiggleData data; 30 | QTimer* intervalTimer = nullptr; 31 | QTimer* mouseMoveUpdateTimer = nullptr; 32 | const int mouseMoveUpdateIntervalMs = 17; // around 60 fps 33 | int64_t mouseMoveStartTimestamp = 0; 34 | 35 | long horizontalMovementModifier = 1; 36 | long horizontalPixelsMoved = 0; 37 | 38 | long verticalMovementModifier = 1; 39 | long verticalPixelsMoved = 0; 40 | }; 41 | 42 | #endif // WIGGLECOREWORKER_H 43 | -------------------------------------------------------------------------------- /TheWiggler/wiggledata.h: -------------------------------------------------------------------------------- 1 | #ifndef WIGGLEDATA_H 2 | #define WIGGLEDATA_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct WiggleData 10 | { 11 | Q_GADGET 12 | public: 13 | 14 | READ_WRITE_QML_PROPERTY(int64_t, WiggleIntervalMs, 5000) 15 | READ_WRITE_QML_PROPERTY(int64_t, WiggleDurationMs, 1000) 16 | READ_WRITE_QML_PROPERTY(bool, MoveHorizontal, true) 17 | READ_WRITE_QML_PROPERTY(bool, MoveVertical, true) 18 | READ_WRITE_QML_PROPERTY(int64_t, HorizontalMoveDistancePixels, 500) 19 | READ_WRITE_QML_PROPERTY(int64_t, VerticalMoveDistancePixels, 500) 20 | READ_WRITE_QML_PROPERTY(bool, FlipHorizontalDirection, true) 21 | READ_WRITE_QML_PROPERTY(bool, FlipVerticalDirection, true) 22 | READ_WRITE_QML_PROPERTY(bool, IsRunning, false) 23 | 24 | }; 25 | 26 | // This class is used to create instances of C++ classes in QML (you cannot currently do this purely in JS) 27 | class WiggleDataFactory : public QObject 28 | { 29 | Q_OBJECT 30 | public: 31 | explicit WiggleDataFactory(QObject* parent = nullptr) : QObject(parent) {} 32 | 33 | Q_INVOKABLE WiggleData make(){ return wiggleData; } 34 | 35 | private: 36 | 37 | WiggleData wiggleData; 38 | 39 | }; 40 | 41 | #endif // WIGGLEDATA_H 42 | -------------------------------------------------------------------------------- /TheWiggler/wiggleinput.cpp: -------------------------------------------------------------------------------- 1 | #include "wiggleinput.h" 2 | 3 | #include 4 | #include 5 | 6 | #ifdef Q_OS_WIN 7 | #include 8 | #endif 9 | 10 | #ifdef Q_OS_OSX 11 | #include 12 | #endif 13 | 14 | #ifdef Q_OS_LINUX 15 | #include 16 | #endif 17 | 18 | void WiggleInput::moveMouseRelative(long x, long y) 19 | { 20 | #ifdef Q_OS_WIN 21 | moveMouseRelative_Win(x, y); 22 | #endif 23 | #ifdef Q_OS_OSX 24 | moveMouseRelative_OSX(x, y); 25 | #endif 26 | #ifdef Q_OS_LINUX 27 | moveMouseRelative_Lin(x, y); 28 | #endif 29 | } 30 | 31 | void WiggleInput::moveMouseAbsolute(long x, long y) 32 | { 33 | #ifdef Q_OS_WIN 34 | moveMouseAbsolute_Win(x, y); 35 | #endif 36 | #ifdef Q_OS_OSX 37 | moveMouseAbsolute_OSX(x, y); 38 | #endif 39 | #ifdef Q_OS_LINUX 40 | moveMouseAbsolute_Lin(x, y); 41 | #endif 42 | } 43 | 44 | #ifdef Q_OS_WIN 45 | void WiggleInput::moveMouseRelative_Win(long x, long y) 46 | { 47 | INPUT Input = { 0 }; 48 | Input.type = INPUT_MOUSE; 49 | 50 | Input.mi.dx = (LONG)x; 51 | Input.mi.dy = (LONG)y; 52 | Input.mi.dwFlags = MOUSEEVENTF_MOVE; 53 | 54 | SendInput(1, &Input, sizeof(INPUT)); 55 | } 56 | 57 | void WiggleInput::moveMouseAbsolute_Win(long x, long y) 58 | { 59 | INPUT Input = { 0 }; 60 | Input.type = INPUT_MOUSE; 61 | 62 | Input.mi.dx = (LONG)x; 63 | Input.mi.dy = (LONG)y; 64 | Input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; 65 | 66 | SendInput(1, &Input, sizeof(INPUT)); 67 | } 68 | #endif 69 | 70 | #ifdef Q_OS_OSX 71 | void WiggleInput::moveMouseRelative_OSX(long x, long y) 72 | { 73 | CGPoint currentMousePos; 74 | { 75 | CGEventRef event = CGEventCreate(nullptr); 76 | currentMousePos = CGEventGetLocation(event); 77 | } 78 | 79 | CGPoint pos; 80 | pos.x = currentMousePos.x + x; 81 | pos.y = currentMousePos.y + y; 82 | 83 | CGEventRef moveEvent = CGEventCreateMouseEvent(nullptr, kCGEventMouseMoved, pos, kCGMouseButtonLeft); 84 | CGEventPost(kCGHIDEventTap, moveEvent); 85 | CFRelease(moveEvent); 86 | } 87 | 88 | void WiggleInput::moveMouseAbsolute_OSX(long x, long y) 89 | { 90 | CGPoint pos; 91 | pos.x = x; 92 | pos.y = y; 93 | 94 | CGEventRef moveEvent = CGEventCreateMouseEvent(nullptr, kCGEventMouseMoved, pos, kCGMouseButtonLeft); 95 | CGEventPost(kCGHIDEventTap, moveEvent); 96 | CFRelease(moveEvent); 97 | } 98 | #endif 99 | 100 | #ifdef Q_OS_LINUX 101 | void WiggleInput::moveMouseRelative_Lin(long x, long y) 102 | { 103 | Display* display = XOpenDisplay(0); 104 | Window rootWindow = XRootWindow(display, 0); 105 | 106 | int currentX = 0; 107 | int currentY = 0; 108 | { 109 | Window root, child; 110 | int rootX, rootY; 111 | unsigned int mask; 112 | 113 | XQueryPointer(display, rootWindow, &root, &child, &rootX, &rootY, ¤tX, ¤tY, &mask); 114 | } 115 | 116 | XWarpPointer(display, None, rootWindow, 0, 0, 0, 0, currentX + x, currentY + y); 117 | XFlush(display); 118 | } 119 | 120 | void WiggleInput::moveMouseAbsolute_Lin(long x, long y) 121 | { 122 | Display* display = XOpenDisplay(0); 123 | Window rootWindow = XRootWindow(display, 0); 124 | 125 | XWarpPointer(display, None, rootWindow, 0, 0, 0, 0, x, y); 126 | XFlush(display); 127 | } 128 | #endif 129 | -------------------------------------------------------------------------------- /TheWiggler/wiggleinput.h: -------------------------------------------------------------------------------- 1 | #ifndef WIGGLEINPUT_H 2 | #define WIGGLEINPUT_H 3 | 4 | #include 5 | 6 | class WiggleInput 7 | { 8 | public: 9 | 10 | static void moveMouseRelative(long x, long y); 11 | static void moveMouseAbsolute(long x, long y); 12 | 13 | private: 14 | 15 | #ifdef Q_OS_WIN 16 | static void moveMouseRelative_Win(long x, long y); 17 | static void moveMouseAbsolute_Win(long x, long y); 18 | #endif 19 | 20 | #ifdef Q_OS_OSX 21 | static void moveMouseRelative_OSX(long x, long y); 22 | static void moveMouseAbsolute_OSX(long x, long y); 23 | #endif 24 | 25 | #ifdef Q_OS_LINUX 26 | static void moveMouseRelative_Lin(long x, long y); 27 | static void moveMouseAbsolute_Lin(long x, long y); 28 | #endif 29 | }; 30 | 31 | #endif // WIGGLEINPUT_H 32 | --------------------------------------------------------------------------------