1

Is it possible to edit the keyboard shortcuts so it can be a combination of a modifier key and a mouse button? Keyboard Shortcuts I would like to change Move left a space to Shift+Mouse 5 and Move right a space to Shift+Mouse 4.

I would like to do it natively without having to install third-party applications like Karabiner if possible. enter image description here

3
  • What clicks/keys do mouse 4 & 5 provide right now? You can always enter those from the keyboard, then the mouse will send them correctly afterwards, even though the shortcut won't directly accept a mouse-click as input.
    – Tetsujin
    Commented Aug 20, 2016 at 13:06
  • They produce Mouse Button 4 and Mouse Button 5 clicks. See new screenshot.
    – jshbrntt
    Commented Aug 20, 2016 at 20:44
  • Ah... right - then it's 3rd party time, I'm afraid.
    – Tetsujin
    Commented Aug 21, 2016 at 6:28

1 Answer 1

1

You have (a few years ago) addressed a general issue with MacOS' AppleScript that's been haunting me forever…
So I started a web search –kind of feasibility study– naturally stumbled upon python and hunted for code samples to make AS aware of mouse events. Here is what I attempted to construct:

A:    A simple AppleScript (> "AS") to start (and end) the "watchout":

on idle {}
    set repCount to 4
    repeat while repCount>0
        set thescript to "python '/Users/someUser/someFolder/Mouse±Key.py'"
        set xYz to do shell script thescript
        set repCount to RepCount - 1
        delay 0.1
    end repeat
    display dialog "Now: " & (repCount as string) & " runs left…"
end idle

… which will run "Mouse±Key.py" in a loop, limited by "repCount" to 5 runs.

Next I started to look into python and find ways to detect mouse+key events. It turned out that a module "pynput" would have to be installed to your (my) python installation:

python -m pip install pynput    

was recommended for this, so I had to install pip first. Well …

The actual *.py script is not very long, due to my criminal neglect of error handling and others.
(As I mentioned: This is a FEASABILITY study! )

Here comes the script – BUT: as I'm no software engineer I won't be able to explain (with authority) why any one special expression is formulated or positioned the way it is. (trial-and-erroooors…)

from pynput import mouse, keyboard
from pynput.keyboard import Key, Listener
import os

def on_press(key):
    global keyDown
    if key == Key.shift:
        keyDown = "57.shift"
    else:
        keyDown = "none"

def on_click(x, y, button, pressed):
    global keyDown
    if button.value[1] == 3 and keyDown == "57.shift":
        cmd = """
        osascript -e 'tell application "System Events" \n key code 123 using {control down}\n delay 0.5\n end tell' 
        """
        os.system(cmd)
    elif button.value[1] == 4 and keyDown == "57.shift":
        cmd = """
        osascript -e 'tell application "System Events" \n key code 124 using {control down}\n delay 0.5\n end tell' 
        """
        os.system(cmd)

    if not pressed:
        listener_key.stop()
        listener_mouse.stop()

listener_key = keyboard.Listener(on_press=on_press)
listener_key.start()
listener_mouse = mouse.Listener(on_click=on_click)
listener_mouse.start()
keyDown = "none "
key = "X"

if keyDown == "57.shift":
    listener_key.stop()

listener_key.join()
listener_mouse.join()

Okay, what I –as layman– can say:

 First 3 lines import pynput modules (not sure, why keyboard and mouse separately) & os.

 Next, 2 crucial functions on_press and on_click are defined;
(keyboard also supports on_release, mouse can handle on_scroll and on_move events.)

 Between these functions but also in the main thread (therefore global) my variable "keyDown" "transports" information whether the key recognized as Key.shift was pressed. I named its content "57.shift" like AS' "shift" key code.

 I needed "keyDown" as I decided to let the on_press function only do the key recognition while on_click evaluates the key, decides what action to take and for the current "run" stops the Listeners.

 The imported module os comes into play when the on_… functions call "back" to MacOS' application "System Events" via 2 osascripts (= Open Scripting Architecture language), as AppleScrips.

 The osascripts instruct MacOS' own system to invoke 2 "integrated" Mission Control (arrow-key) shortcuts that will switch to left-side (key code 123) and right-side (124) spaces (s.t. called "Desktops").

 At the end of the on_click function 2 different Listeners appear, actually to stop their listening (once the osa/AppleScript has worked).

 Next, keyboard.Listener and mouse.Listener are eventually defined and start() ed;
these on the other hand are brought into connection with the 2 vital functions.

 Remaining code first defines "keyDown" delivers a dummy starting value for key and finally "joins" both Listener threads so they "wait" for each other (simply said).

   I mainly researched these codes from pure interest; for testing purposes (unfortunately I use a MacBook with no buttons 4 and 5) I used this line: print(key, "(", button.value[1], ")", keyDown+" >> ", button).

WARNING: As there is no error handling strange things may happen if you experiment my code!

( Anybody more softwarely educated than me is welcome to improve or comment my efforts, but please leave my bullet list mostly as is.)

1
  • Having finished this thing, a few questions remain with me, first things first: WHY do "key" und "listener" habe to be imported "separately" once more although " pynput.Keyboard" already WAS??? ... Most codes on the web used "with pynput.mouse ..." - - my choice worked better: WHY??? ... I lost some time with "subprocess module" which did NOT allow me use some AppleScript system commands: HOW to apply "subprocess" so it is not DISABLING AS commands??? Commented Nov 10, 2021 at 6:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .