diff --git a/Macropad_Hotkeys/code.py b/Macropad_Hotkeys/code.py index 0da71f000..f3ece1b49 100755 --- a/Macropad_Hotkeys/code.py +++ b/Macropad_Hotkeys/code.py @@ -1,9 +1,8 @@ """ -A fairly straightforward macro/hotkey program for Adafruit MACROPAD. -Macro key setups are stored in the /macros folder (configurable below), -load up just the ones you're likely to use. Plug into computer's USB port, -use dial to select an application macro set, press MACROPAD keys to send -key sequences. +A macro/hotkey program for Adafruit MACROPAD. Macro setups are stored in the +/macros folder (configurable below), load up just the ones you're likely to +use. Plug into computer's USB port, use dial to select an application macro +set, press MACROPAD keys to send key sequences and other USB protocols. """ # pylint: disable=import-error, unused-import, too-few-public-methods @@ -44,6 +43,9 @@ class App: macropad.pixels[i] = 0 group[i].text = '' macropad.keyboard.release_all() + macropad.consumer_control.release() + macropad.mouse.release_all() + macropad.stop_tone() macropad.pixels.show() macropad.display.refresh() @@ -129,15 +131,13 @@ while True: sequence = apps[app_index].macros[key_number][2] if pressed: - # the sequence is arbitrary-length - # each item in the sequence is either - # an integer (e.g., Keycode.KEYPAD_MINUS), - # a floating point value (e.g., 0.20) - # or a string. - # Positive Integers ==> key pressed - # Negative Integers ==> key released - # Float ==> sleep in seconds - # String ==> each key in string pressed & released + # 'sequence' is an arbitrary-length list, each item is one of: + # Positive integer (e.g. Keycode.KEYPAD_MINUS): key pressed + # Negative integer: (absolute value) key released + # Float (e.g. 0.25): delay in seconds + # String (e.g. "Foo"): corresponding keys pressed & released + # List []: one or more Consumer Control codes (can also do float delay) + # Dict {}: mouse buttons/motion (might extend in future) if key_number < 12: # No pixel for encoder button macropad.pixels[key_number] = 0xFFFFFF macropad.pixels.show() @@ -149,13 +149,49 @@ while True: macropad.keyboard.release(-item) elif isinstance(item, float): time.sleep(item) - else: + elif isinstance(item, str): macropad.keyboard_layout.write(item) + elif isinstance(item, list): + for code in item: + if isinstance(code, int): + macropad.consumer_control.release() + macropad.consumer_control.press(code) + if isinstance(code, float): + time.sleep(code) + elif isinstance(item, dict): + if 'buttons' in item: + if item['buttons'] >= 0: + macropad.mouse.press(item['buttons']) + else: + macropad.mouse.release(-item['buttons']) + macropad.mouse.move(item['x'] if 'x' in item else 0, + item['y'] if 'y' in item else 0, + item['wheel'] if 'wheel' in item else 0) + if 'tone' in item: + if item['tone'] > 0: + macropad.stop_tone() + macropad.start_tone(item['tone']) + else: + macropad.stop_tone() + elif 'play' in item: + macropad.play_file(item['play']) else: - # Release any still-pressed keys + # Release any still-pressed keys, consumer codes, mouse buttons + # Keys and mouse buttons are individually released this way (rather + # than release_all()) because pad supports multi-key rollover, e.g. + # could have a meta key or right-mouse held down by one macro and + # press/release keys/buttons with others. Navigate popups, etc. for item in sequence: - if isinstance(item, int) and item >= 0: - macropad.keyboard.release(item) + if isinstance(item, int): + if item >= 0: + macropad.keyboard.release(item) + elif isinstance(item, dict): + if 'buttons' in item: + if item['buttons'] >= 0: + macropad.mouse.release(item['buttons']) + elif 'tone' in item: + macropad.stop_tone() + macropad.consumer_control.release() if key_number < 12: # No pixel for encoder button macropad.pixels[key_number] = apps[app_index].macros[key_number][0] macropad.pixels.show() diff --git a/Macropad_Hotkeys/macros/linux-firefox.py b/Macropad_Hotkeys/macros/linux-firefox.py index 36aa871b3..1cc6e857e 100644 --- a/Macropad_Hotkeys/macros/linux-firefox.py +++ b/Macropad_Hotkeys/macros/linux-firefox.py @@ -2,9 +2,9 @@ from adafruit_hid.keycode import Keycode # REQUIRED if using Keycode.* values -app = { # REQUIRED dict, must be named 'app' +app = { # REQUIRED dict, must be named 'app' 'name' : 'Linux Firefox', # Application name - 'macros' : [ # List of button macros... + 'macros' : [ # List of button macros... # COLOR LABEL KEY SEQUENCE # 1st row ---------- (0x004000, '< Back', [Keycode.CONTROL, '[']), @@ -20,10 +20,10 @@ app = { # REQUIRED dict, must be named 'app' (0x000040, 'Private', [Keycode.CONTROL, Keycode.SHIFT, 'p']), # 4th row ---------- (0x101010, 'Ada', [Keycode.CONTROL, 't', -Keycode.CONTROL, - 'www.adafruit.com\n']), # adafruit.com in a new tab - (0x000040, 'Dev Mode', [Keycode.F12]), # dev mode + 'www.adafruit.com\n']), # adafruit.com in a new tab + (0x000040, 'Dev Mode', [Keycode.F12]), # dev mode (0x101010, 'Digi', [Keycode.CONTROL, 't', -Keycode.CONTROL, - 'digikey.com\n']), # digikey in a new tab + 'digikey.com\n']), # digikey in a new tab # Encoder button --- (0x000000, '', [Keycode.CONTROL, 'w']) # Close window/tab ] diff --git a/Macropad_Hotkeys/macros/mac-evernote.py b/Macropad_Hotkeys/macros/mac-evernote.py index 2d64ace99..2ae820f02 100644 --- a/Macropad_Hotkeys/macros/mac-evernote.py +++ b/Macropad_Hotkeys/macros/mac-evernote.py @@ -20,8 +20,8 @@ app = { # REQUIRED dict, must be named 'app' (0x004000, 'Nums', [Keycode.SHIFT, Keycode.COMMAND, 'o']), (0x004000, 'Check', [Keycode.SHIFT, Keycode.COMMAND, 't']), # 4th row ---------- - (0x004000, 'Date', [Keycode.SHIFT, Keycode.COMMAND, 'D' ]), - (0x004000, 'Time', [Keycode.OPTION, Keycode.SHIFT, Keycode.COMMAND, 'D' ]), + (0x004000, 'Date', [Keycode.SHIFT, Keycode.COMMAND, 'D']), + (0x004000, 'Time', [Keycode.OPTION, Keycode.SHIFT, Keycode.COMMAND, 'D']), (0x004000, 'Divider', [Keycode.SHIFT, Keycode.COMMAND, 'H']), # Encoder button --- (0x000000, '', [Keycode.COMMAND, 'w']) # Close window/tab diff --git a/Macropad_Hotkeys/macros/media.py b/Macropad_Hotkeys/macros/media.py new file mode 100755 index 000000000..2026be3fe --- /dev/null +++ b/Macropad_Hotkeys/macros/media.py @@ -0,0 +1,40 @@ +# MACROPAD Hotkeys example: Consumer Control codes (media keys) + +# The syntax for Consumer Control macros is a little peculiar, in order to +# maintain backward compatibility with the original keycode-only macro files. +# The third item for each macro is a list in brackets, and each value within +# is normally an integer (Keycode), float (delay) or string (typed literally). +# Consumer Control codes are distinguished by enclosing them in a list within +# the list, which is why you'll see double brackets [[ ]] below. +# Like Keycodes, Consumer Control codes can be positive (press) or negative +# (release), and float values can be inserted for pauses. + +# To reference Consumer Control codes, import ConsumerControlCode like so... +from adafruit_hid.consumer_control_code import ConsumerControlCode +# You can still import Keycode as well if a macro file mixes types! +# See other macro files for typical Keycode examples. + +app = { # REQUIRED dict, must be named 'app' + 'name' : 'Media', # Application name + 'macros' : [ # List of button macros... + # COLOR LABEL KEY SEQUENCE + # 1st row ---------- + (0x000000, '', []), + (0x000020, 'Vol+', [[ConsumerControlCode.VOLUME_INCREMENT]]), + (0x202020, 'Bright+', [[ConsumerControlCode.BRIGHTNESS_INCREMENT]]), + # 2nd row ---------- + (0x000000, '', []), + (0x000020, 'Vol-', [[ConsumerControlCode.VOLUME_DECREMENT]]), + (0x202020, 'Bright-', [[ConsumerControlCode.BRIGHTNESS_DECREMENT]]), + # 3rd row ---------- + (0x000000, '', []), + (0x200000, 'Mute', [[ConsumerControlCode.MUTE]]), + (0x000000, '', []), + # 4th row ---------- + (0x202000, '<<', [[ConsumerControlCode.SCAN_PREVIOUS_TRACK]]), + (0x002000, 'Play/Pause', [[ConsumerControlCode.PLAY_PAUSE]]), + (0x202000, '>>', [[ConsumerControlCode.SCAN_NEXT_TRACK]]), + # Encoder button --- + (0x000000, '', []) + ] +} diff --git a/Macropad_Hotkeys/macros/minecraft-messages.py b/Macropad_Hotkeys/macros/minecraft-messages.py index a2b05f0c7..67e295940 100644 --- a/Macropad_Hotkeys/macros/minecraft-messages.py +++ b/Macropad_Hotkeys/macros/minecraft-messages.py @@ -8,16 +8,16 @@ from adafruit_hid.keycode import Keycode # REQUIRED if using Keycode.* values # NOTE: There appears to be some delay when bringing up the command screen. -DELAY_AFTER_SLASH = 0.80 # required so minecraft has time to bring up command screen +DELAY_AFTER_SLASH = 0.80 # required so minecraft has time to bring up command screen DELAY_BEFORE_RETURN = 0.10 # NOTE: On PC, characters are sometimes lost due to lag. No simple fix for # lost keystrokes is known. However, the commands do work most of the time. -app = { # REQUIRED dict, must be named 'app' - 'name' : 'Minecraft (/msg)', # Application name - 'macros' : [ # List of button macros... +app = { # REQUIRED dict, must be named 'app' + 'name' : 'Minecraft (/msg)', # Application name + 'macros' : [ # List of button macros... # COLOR LABEL KEY SEQUENCE # 1st row ---------- (0x000020, 'list', [ @@ -33,13 +33,13 @@ app = { # REQUIRED dict, must be named 'app' 'list', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), # 2nd row ---------- - (0x000000, '', []), - (0x000000, '', []), - (0x000000, '', []), + (0x000000, '', []), + (0x000000, '', []), + (0x000000, '', []), # 3rd row ---------- - (0x000000, '', []), - (0x000000, '', []), - (0x000000, '', []), + (0x000000, '', []), + (0x000000, '', []), + (0x000000, '', []), # 4th row ---------- (0x101010, 'bed', [ '/', DELAY_AFTER_SLASH, diff --git a/Macropad_Hotkeys/macros/minecraft-pe-effects.py b/Macropad_Hotkeys/macros/minecraft-pe-effects.py index 46fd72b62..8dfa5c6e0 100644 --- a/Macropad_Hotkeys/macros/minecraft-pe-effects.py +++ b/Macropad_Hotkeys/macros/minecraft-pe-effects.py @@ -8,32 +8,32 @@ from adafruit_hid.keycode import Keycode # REQUIRED if using Keycode.* values # See https://minecraft.fandom.com/wiki/Effect -DELAY_AFTER_SLASH = 0.80 # required so minecraft has time to bring up command screen +DELAY_AFTER_SLASH = 0.80 # required so minecraft has time to bring up command screen DELAY_BEFORE_RETURN = 0.10 # give minecraft time to show all the keys pressed... -app = { # REQUIRED dict, must be named 'app' - 'name' : 'Minecraft PE (effect)', # Application name +app = { # REQUIRED dict, must be named 'app' + 'name' : 'Minecraft PE (effect)', # Application name # # /effect # [seconds: int] [amplifier: int] [hideParticles: Boolean] # - 'macros' : [ # List of button macros... + 'macros' : [ # List of button macros... # COLOR LABEL KEY SEQUENCE # 1st row ---------- - (0x002000, 'speed', [ + (0x002000, 'speed', [ '/', DELAY_AFTER_SLASH, 'effect @s speed 999999999 1 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), - (0x002000, 'str', [ + (0x002000, 'str', [ '/', DELAY_AFTER_SLASH, 'effect @s strength 999999999 1 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), - (0x002000, 'haste', [ + (0x002000, 'haste', [ '/', DELAY_AFTER_SLASH, 'effect @s haste 999999999 1 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), # 2nd row ---------- - (0x002000, 'jump', [ + (0x002000, 'jump', [ '/', DELAY_AFTER_SLASH, 'effect @s jump_boost 999999999 1 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), @@ -41,7 +41,7 @@ app = { # REQUIRED dict, must be named 'app' '/', DELAY_AFTER_SLASH, 'effect @s water_breathing 999999999 0 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), - (0x202020, 'darkv', [ + (0x202020, 'darkv', [ '/', DELAY_AFTER_SLASH, 'effect @s night_vision 999999999 0 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), @@ -50,7 +50,7 @@ app = { # REQUIRED dict, must be named 'app' '/', DELAY_AFTER_SLASH, 'effect @s health_boost 999999999 4 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), - (0x300000, 'regen', [ + (0x300000, 'regen', [ '/', DELAY_AFTER_SLASH, 'effect @s regeneration 999999999 4 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), @@ -63,7 +63,7 @@ app = { # REQUIRED dict, must be named 'app' '/', DELAY_AFTER_SLASH, 'effect @s resistance 999999999 3 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), - (0x101010, 'invis', [ + (0x101010, 'invis', [ '/', DELAY_AFTER_SLASH, 'effect @s invisibility 999999999 0 true', DELAY_BEFORE_RETURN, Keycode.RETURN, -Keycode.RETURN]), diff --git a/Macropad_Hotkeys/macros/minecraft-pe-equip.py b/Macropad_Hotkeys/macros/minecraft-pe-equip.py index 4f3c0f511..0a64723eb 100644 --- a/Macropad_Hotkeys/macros/minecraft-pe-equip.py +++ b/Macropad_Hotkeys/macros/minecraft-pe-equip.py @@ -3,11 +3,9 @@ # Note: Must enable "full keyboad gameplay" to equip armor automatically. # This is found under "settings", then "keyboard and mouse". -# NOTE: There is a line length limit (? ~100 char ?). Exceeding that limit appears -# to result in silent failure. Therefore, the key sequences are split -# across multiple lines. - - +# NOTE: There is a line length limit (? ~100 char ?). Exceeding that limit +# appears to result in silent failure. Therefore, the key sequences are +# split across multiple lines. from adafruit_hid.keycode import Keycode # REQUIRED if using Keycode.* values @@ -21,7 +19,7 @@ from adafruit_hid.keycode import Keycode # REQUIRED if using Keycode.* values # macro files before attempting to adjust settings in this one. DELAY_AFTER_COMMAND = 0.75 -DELAY_AFTER_SLASH = 0.80 # required so minecraft has time to bring up command screen +DELAY_AFTER_SLASH = 0.80 # required so minecraft has time to bring up command screen DELAY_BEFORE_RETURN = 0.10 # give minecraft time to show all the keys pressed... diff --git a/Macropad_Hotkeys/macros/mouse.py b/Macropad_Hotkeys/macros/mouse.py new file mode 100755 index 000000000..1452fe3b3 --- /dev/null +++ b/Macropad_Hotkeys/macros/mouse.py @@ -0,0 +1,41 @@ +# MACROPAD Hotkeys example: Mouse control + +# The syntax for Mouse macros is highly peculiar, in order to maintain +# backward compatibility with the original keycode-only macro files. +# The third item for each macro is a list in brackets, and each value within +# is normally an integer (Keycode), float (delay) or string (typed literally). +# Consumer Control codes were added as list-within-list, and then mouse +# further complicates this by adding dicts-within-list. Each mouse-related +# dict can have any mix of keys 'buttons' w/integer mask of button values +# (positive to press, negative to release), 'x' w/horizontal motion, +# 'y' w/vertical and 'wheel' with scrollwheel motion. + +# To reference Mouse constants, import Mouse like so... +from adafruit_hid.mouse import Mouse +# You can still import Keycode and/or ConsumerControl as well if a macro file +# mixes types! See other macro files for typical Keycode examples. + +app = { # REQUIRED dict, must be named 'app' + 'name' : 'Mouse', # Application name + 'macros' : [ # List of button macros... + # COLOR LABEL KEY SEQUENCE + # 1st row ---------- + (0x200000, 'L', [{'buttons':Mouse.LEFT_BUTTON}]), + (0x202000, 'M', [{'buttons':Mouse.MIDDLE_BUTTON}]), + (0x002000, 'R', [{'buttons':Mouse.RIGHT_BUTTON}]), + # 2nd row ---------- + (0x000000, '', []), + (0x202020, 'Up', [{'y':-10}]), + (0x000000, '', []), + # 3rd row ---------- + (0x202020, 'Left', [{'x':-10}]), + (0x000000, '', []), + (0x202020, 'Right', [{'x':10}]), + # 4th row ---------- + (0x000000, '', []), + (0x202020, 'Down', [{'y':10}]), + (0x000000, '', []), + # Encoder button --- + (0x000000, '', []) + ] +} diff --git a/Macropad_Hotkeys/macros/numpad.py b/Macropad_Hotkeys/macros/numpad.py index ccdbd977a..65d26da34 100644 --- a/Macropad_Hotkeys/macros/numpad.py +++ b/Macropad_Hotkeys/macros/numpad.py @@ -2,9 +2,9 @@ from adafruit_hid.keycode import Keycode # REQUIRED if using Keycode.* values -app = { # REQUIRED dict, must be named 'app' +app = { # REQUIRED dict, must be named 'app' 'name' : 'Numpad', # Application name - 'macros' : [ # List of button macros... + 'macros' : [ # List of button macros... # COLOR LABEL KEY SEQUENCE # 1st row ---------- (0x202000, '7', ['7']), diff --git a/Macropad_Hotkeys/macros/tones.py b/Macropad_Hotkeys/macros/tones.py new file mode 100755 index 000000000..10778cc2e --- /dev/null +++ b/Macropad_Hotkeys/macros/tones.py @@ -0,0 +1,39 @@ +# MACROPAD Hotkeys example: Tones + +# The syntax for Tones in macros is highly peculiar, in order to maintain +# backward compatibility with the original keycode-only macro files. +# The third item for each macro is a list in brackets, and each value within +# is normally an integer (Keycode), float (delay) or string (typed literally). +# Consumer Control codes were added as list-within-list, and then mouse and +# tone further complicate this by adding dicts-within-list. Each tone-related +# item is the key 'tone' with either an integer frequency value, or 0 to stop +# the tone mid-macro (tone is also stopped when key is released). +# Helpful: https://en.wikipedia.org/wiki/Piano_key_frequencies + +# This example ONLY shows tones (and delays), but really they can be mixed +# with other elements (keys, codes, mouse) to provide auditory feedback. + +app = { # REQUIRED dict, must be named 'app' + 'name' : 'Tones', # Application name + 'macros' : [ # List of button macros... + # COLOR LABEL KEY SEQUENCE + # 1st row ---------- + (0x200000, 'C3', [{'tone':131}]), + (0x202000, 'C4', [{'tone':262}]), + (0x002000, 'C5', [{'tone':523}]), + # 2nd row ---------- + (0x000020, 'Rising', [{'tone':131}, 0.2, {'tone':262}, 0.2, {'tone':523}]), + (0x000000, '', []), + (0x000020, 'Falling', [{'tone':523}, 0.2, {'tone':262}, 0.2, {'tone':131}]), + # 3rd row ---------- + (0x000000, '', []), + (0x000000, '', []), + (0x000000, '', []), + # 4th row ---------- + (0x000000, '', []), + (0x000000, '', []), + (0x000000, '', []), + # Encoder button --- + (0x000000, '', []) + ] +}