MacOS – Detect fn and function key simultaneously pressed

applescriptcommand linekeyboardmacospython

I am using ControllerMate to try to change what my volume buttons do.

Unfortunately, I haven't figured out how I can detect that the F11 or F12 keys are being pressed at the same time as the fn key.

Originally I'd planned to combine an F11 keypress detector and an AppleScript that checks for the fn key.

enter image description here

I haven't been able to find a way in AppleScript to detect the fn key. Research led me to possible solutions, such as

do shell script "/usr/bin/python -c 'import Cocoa; print Cocoa.NSEvent.modifierFlags()'"

But this can't distinguish between the different function keys or fn.

After almost a week trying to figure this out myself I ask you; is there a way to detect in ControllerMate a simultaneous fn and function key press?

Best Answer

I found a way to do this that uses the awesome Karabiner-Elements. This has been so useful for me in many situations, and it works here too.

Karabiner can detect function keys being pressed, and tell whether it's with or without the fn key modifier.

We can make our own "Complex modification" that takes advantage of this:

  1. Complex modifications are stored in ~/.config/karabiner/assets/complex_modifications as json files. Create a file in here with your favourite text editor:

    vim ~/.config/karabiner/assets/complex_modifications/detect_fn.json
    
  2. You need to fill the file with your own rules, here's what mine looks like now:

    {
      "title": "The fn keys can control volume of built-in output even when a multi-output device is being used.",
      "rules": [
        {
          "description": "Map fn volume keys to execute applescript which changes volume of built-in output.",
          "manipulators": [
            {
              "type": "basic",
              "from": {
                "key_code": "f10",
                "modifiers": {
                  "mandatory": [
                    "fn"
                  ]
                }
              },
              "to": [
                {
                  "shell_command": "osascript -e 'set volume alert volume 0' && osascript -e 'set volume (alert volume of (get volume settings))*7/100'"
                }
              ]
            },
            {
              "type": "basic",
              "from": {
                "key_code": "f11",
                "modifiers": {
                  "mandatory": [
                    "fn"
                  ]
                }
              },
              "to": [
                {
                  "shell_command": "osascript -e 'set volume alert volume ((alert volume of (get volume settings)) - 100/16)' && osascript -e 'set volume (alert volume of (get volume settings))*7/100'"
                }
              ]
            },
            {
              "type": "basic",
              "from": {
                "key_code": "f12",
                "modifiers": {
                  "mandatory": [
                    "fn"
                  ]
                }
              },
              "to": [
                {
                  "shell_command": "osascript -e 'set volume alert volume ((alert volume of (get volume settings)) + 100/16)' && osascript -e 'set volume (alert volume of (get volume settings))*7/100'"
                }
              ]
            }
          ]
        }
      ]
    }
    
  3. It should be obvious how you can replace the keys with whichever ones you want, and you can also replace the shell command with any shell command.

  4. Add the rule into karabiner-elements by

    1. Starting it up

    2. Choosing "Complex Modifications" from the top

    3. Clicking "(+) Add rule"

    4. Enabling the rule you just defined