Macropad automatic layer switching

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
dearmash
 
Posts: 66
Joined: Mon Nov 28, 2011 4:20 pm

Macropad automatic layer switching

Post by dearmash »

I'm an absolute fan of https://learn.adafruit.com/macropad-hot ... oject-code and use it all day / every day. Thanks so much for this!

Besides some quality of life changes in code.py 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 app.name == target:
      macropad._encoder.position = -i
      break
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.tools.list_ports
import serial
import sys
import Quartz


ser = None
prev_output = None

while True:
    try:
        screen_locked = "CGSSessionScreenIsLocked" in Quartz.CGSessionCopyCurrentDictionary().keys()
        if screen_locked:
            if ser:
                ser.close()
                ser = None
            sleep(5)
            continue

        if not ser:
            MACROPAD_SERIAL="<YOUR_SERIAL_HERE>"

            a=serial.tools.list_ports.comports()
            s=None
            for w in a:
                if w.serial_number == MACROPAD_SERIAL:
                    s=w
                    break

            if not s:
                print("Macropad not found")
                sleep(10)
                continue

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

        sleep(1)

        r = applescript.run(
"""
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
            ser.write(output.encode())
            ser.write(b'\r')
            ser.readlines()

            print(output)

    except serial.serialutil.SerialException as e:
        ser = None
        print("Serial exception, waiting", e)
        sleep(10)
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
                break
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.

Locked
Please be positive and constructive with your questions and comments.

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