Macropad automatic layer switching

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Post Reply
User avatar
Posts: 51
Joined: Mon Nov 28, 2011 4:20 pm

Macropad automatic layer switching

Post by dearmash »

I'm an absolute fan of ... oject-code and use it all day / every day. Thanks so much for this!

Besides some quality of life changes in for how lists are handled, one of my favorite tweaks was adding layer switching. In the dict definition, I added:

Code: Select all

if 'layer' in item:
  target = item['layer']
  for i, app in enumerate(apps):
    if == target:
      macropad._encoder.position = -i
So if you have [{'layer':'Off'}] in your macro it will search for the 'app' that has the same title, and set the encoder position to a value that will effectively automatically switch to that 'layer'.

The main reason I use this is I have an "off" layer, with shortcuts to other layers I frequently use. All other layers link to "off" on rotary press. Rotary press in the "off" layer is the shortcut to lock my screen. So a reasonably quick double tap on the rotary encoder will lock my computer.

The recent major improvement I came up with is a python script running on my mac in the background. It requires a few pip dependencies for pyserial, applescript, and pyobjc if I recall correctly.

Code: Select all

#!/usr/bin/env python3

import applescript
from time import sleep
import serial
import sys
import Quartz

ser = None
prev_output = None

while True:
        screen_locked = "CGSSessionScreenIsLocked" in Quartz.CGSessionCopyCurrentDictionary().keys()
        if screen_locked:
            if ser:
                ser = None

        if not ser:

            for w in a:
                if w.serial_number == MACROPAD_SERIAL:

            if not s:
                print("Macropad not found")

            ser = serial.Serial(s.device, baudrate=9600, timeout=0.01)


        r =
set appInfo to info for (path to frontmost application)
set frontAppName to displayed name of (info for (path to frontmost application))
tell application "System Events"
    set frontApp to application process 1 whose frontmost is true
    return {frontAppName, name of window 1 of frontApp}
end tell


        output = r.out

        if not output:
            output = "Empty!"

        if prev_output != output:
            prev_output = output


    except serial.serialutil.SerialException as e:
        ser = None
        print("Serial exception, waiting", e)
This will send the title of my foreground window to the macropad only when it changes. It backs off a bit when the screen locks, or if there is an error in the serial connection.

Then in the macropad, I have

Code: Select all

    if supervisor.runtime.serial_bytes_available:
        inText = input().strip()
        for i, app in enumerate(apps):
            if app.window_title and app.window_title in inText:
                macropad._encoder.position = -i
which is a take on the above layer switching approach, but instead it looks to see if an 'app' "window_title" field is a substring of the received window title. If it is, it automatically switches to that layer. I've been toying with the idea of switching to regex / lists, to make it easier to have one app layer target multiple window titles. For now though, it's good enough.

This has mostly been for work productivity and whatnot. I have no idea how this would work for games, or other macropad use cases.

Post Reply
Please be positive and constructive with your questions and comments.

Return to “AdaBox! Show us what you made!”