this post was submitted on 21 Jun 2023
2 points (100.0% liked)

Linux

48082 readers
770 users here now

From Wikipedia, the free encyclopedia

Linux is a family of open source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991 by Linus Torvalds. Linux is typically packaged in a Linux distribution (or distro for short).

Distributions include the Linux kernel and supporting system software and libraries, many of which are provided by the GNU Project. Many Linux distributions use the word "Linux" in their name, but the Free Software Foundation uses the name GNU/Linux to emphasize the importance of GNU software, causing some controversy.

Rules

Related Communities

Community icon by Alpár-Etele Méder, licensed under CC BY 3.0

founded 5 years ago
MODERATORS
 

One of my biggest gripes while using Piper has always been the lack of automatic profile switching on profile switch. I wanted to implement a band-aid to try and solve this issue, but have been having too many issues to sink more time into this:

Method 1:

  • Using a while loop that triggers every couple seconds that gets the active window id and fetches its name for a function that checks it against various regexs.
  • Problem? Well, it is rather laggy. I find my mouse stuttering every once in a while, even when using an if statement to only run code when the IDs don't match.

Method 2:

  • Using xdotool search . behave %@ focus ... to add event listeners to windows.
  • This method was WAY better in terms of performance, but doesn't apply it to windows created after script launch, which is an issue since the script would launch at session startup.

It's about time I came to the collective hive-mind for ideas, or even a complete solution that someone may have.

Here is my neofetch for system info, since I know that can impact your answers.

OS: EndeavourOS Linux x86_64 
Kernel: 6.3.8-arch1-1 
Uptime: 1 hour, 5 mins 
Packages: 1400 (pacman), 8 (flatpak) 
Shell: zsh 5.9 
Resolution: 1080x1920, 1920x1080, 1920x1080 
DE: Xfce 4.18 
WM: Xfwm4 
WM Theme: Matcha-dark-sea 
Theme: Flat-Remix-GTK-MORALES-Dark [GTK2], Arc-Darker [GTK3] 
Icons: Flat-Remix-Red-Dark [GTK2], Qogir [GTK3] 
Terminal: xfce4-terminal 
Terminal Font: Fira Code 10 
CPU: AMD Ryzen 9 5950X (32) @ 3.400GHz 
GPU: NVIDIA GeForce RTX 3080 Lite Hash Rate 
Memory: 6675MiB / 32006MiB 
top 3 comments
sorted by: hot top controversial new old
[–] [email protected] 2 points 1 year ago (1 children)

I don't have a ready-to-run solution for you, but I see you already dug quite into that rabbit hole. Google-fu turned up this and this - maybe those are good starting points to have.

[–] [email protected] 2 points 1 year ago* (last edited 1 year ago)

The results have made me realize that the bash way of doing this is just not worth attempting, and a Python script is much more simple. At the end of the day, I ended up using this GIST with a custom handler function:

https://gist.github.com/dperelman/c1d3c966d397ff884abb8b3baf7990db

class MouseProfile(Enum):
    DEFAULT = 0
    BLOONS = 1
    GAMING_COMMON = 2
    CALL_OF_DUTY = 3
    REALM_GRINDER = 4

def handle_change(new_state: dict):
    """
    Using `libratbag`, switch the profile of the mouse based on the active window title.
    """
    # Get the title of the active window
    title: str = new_state['title']
    profile: MouseProfile = MouseProfile.DEFAULT
    match title:
        case "BloonsTD6":
            profile = MouseProfile.BLOONS
        case "Realm Grinder":
            profile = MouseProfile.REALM_GRINDER
        case _:
            if title:
              if search(r"^Call of Duty.*", title):
                  profile = MouseProfile.CALL_OF_DUTY
              elif search(r"^Deep Rock Galactic.*", title):
                  profile = MouseProfile.GAMING_COMMON
    # Send the ratbag command to switch the profile
    run(["ratbagctl", "Logitech", "profile", "active", "set", str(profile.value)], stdout=PIPE, stderr=PIPE)
[–] [email protected] 1 points 1 year ago

I have been tinkering with my script some more and figured I would post an update:

  • As I have been experimenting with the script, I have noticed some weird window dragging issues. I have learned that, if you switch a profile, your mouse is temporarily interrupted, even when switching to the same profile. So, I have added a variable that stores the profile to ensure that you only switch when actually needed.

GIST with source code used: https://gist.github.com/dperelman/c1d3c966d397ff884abb8b3baf7990db

from enum import Enum
from re import search
from subprocess import run, PIPE

# Code from the GIST
... 

class MouseProfile(Enum):
    DEFAULT = 0
    BLOONS = 1
    GAMING_COMMON = 2
    CALL_OF_DUTY = 3
    REALM_GRINDER = 4

current_profile: MouseProfile = MouseProfile.DEFAULT

def handle_change(new_state: dict):
    """
    Using `libratbag`, switch the profile of the mouse
    based on the active window title.
    """
    global current_profile

    # Get the title of the active window
    title: str = new_state['title']
    profile: MouseProfile = MouseProfile.DEFAULT
    match title:
        case "BloonsTD6":
            profile = MouseProfile.BLOONS
        case "Realm Grinder":
            profile = MouseProfile.REALM_GRINDER
        case _:
            if title:
                if search(r"^Call of Duty.*", title):
                    profile = MouseProfile.CALL_OF_DUTY
                elif search(r"^Deep Rock Galactic.*", title):
                    profile = MouseProfile.GAMING_COMMON
    # Send the ratbag command to switch the profile
    if profile != current_profile:
        run([
            "ratbagctl", "Logitech", "profile", "active", "set", str(profile.value)
        ], stdout=PIPE, stderr=PIPE)
        current_profile = profile


if __name__ == '__main__':
    # Get the current mouse profile and set it as the current profile
    result = run(
        ["ratbagctl", "Logitech", "profile", "active", "get"],
        stdout=PIPE, stderr=PIPE
    )
    current_profile = MouseProfile(int(result.stdout)) if result.returncode == 0 else MouseProfile.DEFAULT

    # Listen for _NET_ACTIVE_WINDOW changes
    root.change_attributes(event_mask=X.PropertyChangeMask)

    # Prime last_seen with whatever window was active when we started this
    get_window_name(get_active_window()[0])
    handle_change(last_seen)

    while True:
        handle_xevent(display.next_event())
load more comments
view more: next ›