diff --git a/README.md b/README.md index 66dff352..01e59958 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,19 @@ be running. If it doesn't already after logging in, you can use: key-mapper-service ``` +## Macros + +It is possible to write timed macros into the center column: +- `r(3, k('a').w(10))`: aaa +- `r(2, k('a').k('-').k('b')`: a-a-b +- `w(1000).m('SHIFT_L', r(2, k('a'))).w(10, 20).k('b')`: AAb + +Documentation: +- `r` repeats +- `w` waits in ms (randomly with 2 parameters) +- `k` writes a keystroke +- `m` modifies + ## Git Installation ```bash diff --git a/keymapper/dev/macros.py b/keymapper/dev/macros.py new file mode 100644 index 00000000..603f44a9 --- /dev/null +++ b/keymapper/dev/macros.py @@ -0,0 +1,127 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# key-mapper - GUI for device specific keyboard mappings +# Copyright (C) 2020 sezanzeb +# +# This file is part of key-mapper. +# +# key-mapper is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# key-mapper is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with key-mapper. If not, see . + + +"""Executes more complex patterns of keystrokes. + +To keep it short on the UI, the available functions are one-letter long. + +The global functions actually perform the stuff and always return macro +instances that can then be further chained. + +the outermost macro (in the examples below the one created by 'r', +'r' and 'w') will be started, which triggers a chain reaction to execute +all of the configured stuff. + +Examples +-------- +r(3, k('a').w(10)): 'a' <10ms> 'a' <10ms> 'a' +r(2, k('a').k('-').k('b'): 'a' '-' 'a' '-' 'b' +w(1000).m('SHIFT_L', r(2, k('a'))).w(10).k('b'): <1s> 'A' 'A' <10ms> 'b' +""" + + +import time +import random + + +# TODO parse securely + + +def m(*args): + return Macro().m(*args) + + +def r(*args): + return Macro().r(*args) + + +def k(*args): + return Macro().k(*args) + + +def w(*args): + return Macro().w(*args) + + +class Macro: + """Supports chaining and preparing actions.""" + def __init__(self): + self.tasks = [] + + def run(self): + """Run the macro""" + for task in self.tasks: + task() + + def m(self, modifier, macro): + """Do stuff while a modifier is activated. + + Parameters + ---------- + modifier : str + macro : Macro + """ + # TODO press modifier down + self.tasks.append(macro.run) + # TODO release modifier + return self + + def r(self, repeats, macro): + """Repeat actions. + + Parameters + ---------- + repeats : int + macro : Macro + """ + for _ in range(repeats): + self.tasks.append(macro.run) + return self + + def k(self, character, value=None): + """Write the character. + + Parameters + ---------- + """ + # TODO write character + self.tasks.append(lambda: print(character)) + return self + + def w(self, min, max=None): + """Wait a random time in milliseconds""" + # TODO random + self.tasks.append(lambda: time.sleep(min / 1000)) + return self + + +# TODO make these into tests + +print() +r(3, k('a').w(200)).run() + +print() +r(2, k('a').k('-')).k('b').run() + +print() +w(400).m('SHIFT_L', r(2, k('a'))).w(10).k('b').run() + +print()