12

I'm wondering what would be the process of enabling/disabling the grayscale mode in the Accessibility panel in System Preferences?

I would like to run a simple script, either by clicking on an app in the Dock or by a Terminal command, and have it switch from grayscale to regular mode.

Any ideas?

6 Answers 6

6

Note: The example AppleScript code was updated to handle the current latest macOS (Mojave) and add additional code improvements. On earlier versions of OS X/macOS you may have to remove of group 1 from the two lines of example AppleScript code that have it, for the code to work.


If you want to create an AppleScript application to put in the Dock you can use the following code in OS X Yosemite (and latter, I believe).

if running of application "System Preferences" then
    try
        tell application "System Preferences" to quit
    on error
        do shell script "killall 'System Preferences'"
    end try
end if

repeat while running of application "System Preferences" is true
    delay 0.01
end repeat

tell application "System Preferences" to reveal anchor "Seeing_Display" of ¬
    pane id "com.apple.preference.universalaccess"

tell application "System Events" to tell process "System Preferences"
    repeat until exists checkbox "Use grayscale" of group 1 of ¬
        window "Accessibility"
        delay 0.01
    end repeat
    click the checkbox "Use grayscale" of group 1 of window "Accessibility"
end tell

tell application "System Preferences" to quit

In Script Editor, save it as Toggle Grayscale changing the File Format: to: Application

You can give the App a different icon via copy and paste into the icon of the App's Get Info sheet and then drag and drop the App bundle onto the Dock.

You'll have to give permission under Accessibility on the Privacy tab of Security & Privacy in System Preferences in order to run it successfully.


If you'd like to use a bash script using the code provided by IconDaemon, the following code will toggle between using color and grayscale based on how it's currently set.

#!/bin/bash

setGrayscale () {

    defaults write com.apple.universalaccess grayscale -bool $1
    defaults write com.apple.CoreGraphics DisplayUseForcedGray -bool $1
    launchctl unload /System/Library/LaunchAgents/com.apple.universalaccessd.plist
    launchctl load /System/Library/LaunchAgents/com.apple.universalaccessd.plist

    case "$1" in
        "NO")
            echo "  Changing Display to use color. This will take a moment..."
        ;;
        "YES")
            echo "  Changing Display to use grayscale. This will take a moment..."
        ;;
    esac

}

_bool="$(defaults read com.apple.universalaccess grayscale 2>/dev/null)"

case "$_bool" in
    "0")
        setGrayscale "YES"
    ;;
    "1")
        setGrayscale "NO"
    ;;
    *)
        setGrayscale "YES"
    ;;
esac

enter image description here

3
  • 2
    It worked after I added delay 1 before the click checkbox. Thanks!
    – ArleyM
    Commented Feb 21, 2017 at 16:21
  • user3439894 I get this error: System Events got an error: Can’t get window "Accessibility" of process "System Preferences". (-1728) Trying to troubleshoot where I went wrong... thanks! Commented Apr 3, 2019 at 16:21
  • @Cory Snider, I've updated the example AppleScript code to handle the current latest macOS (Mojave) and add additional code improvements. On earlier versions of OS X/macOS you may have to remove of group 1 from the two lines of example AppleScript code that have it, for the code to work. Commented Apr 3, 2019 at 17:02
10

This requires developer tools to compile an objective C program. The program is based on this Stackoverflow answer.

Create a file called grayscale.c with the following contents:

// clang -g -O2 -std=c11 -Wall -framework ApplicationServices
// https://stackoverflow.com/questions/14163788/how-does-on-screen-color-inversion-work-in-os-x
#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>

CG_EXTERN bool CGDisplayUsesForceToGray(void);
CG_EXTERN void CGDisplayForceToGray(bool forceToGray);

int
main(int argc, char** argv)
{
    bool isGrayscale = CGDisplayUsesForceToGray();
    printf("isGrayscale = %d\n", isGrayscale);
    CGDisplayForceToGray(!isGrayscale);
    printf("Grayscale is now: %d\n", CGDisplayUsesForceToGray());

    return 0;
}

Then run the following command to compile it:

clang -g -O2 -std=c11 -Wall -framework ApplicationServices ./grayscale.c -o toggle-grayscale

Now run ./toggle-grayscale This instantly makes the screen grayscale or not across all applications, but doesn't update the setting in System Preferences.

Tested on MacOS High Sierra 10.13.6, clang version Apple LLVM version 10.0.0 (clang-1000.10.44.4).

6
  • 4
    This is amazing. I took your executable and made it a service via Automator, and then assigned a keyboard shortcut to that service, essentially mapping Cmd+Option+Ctrl+9 to toggle grayscale
    – redolent
    Commented Feb 18, 2019 at 10:58
  • 2
    This is interesting. When used with color inversion, this simple approach to grayscale provides nicer output than one of native macOS Accessibility grayscale color filter (which I believe does not work with color inversion at all lately). Found one drawback, though: when using multiple displays, grayscale behavior gets toggled off once I switch to a window on another display (still looking into that issue). Commented May 22, 2020 at 22:17
  • 1
    Great option. Echo what Anton says: this works better than the functionality of enabling the Greyscale color filter.
    – Anthony
    Commented Sep 1, 2021 at 0:37
  • 2
    Unfortunately, doesn’t work on M1/Big Sur. Not sure why. printf will report flag toggling between 0 and 1, but no visual change occurs. Commented Aug 14, 2022 at 6:09
  • 1
    @AntonStrogonoff These were private APIs, so it's not surprising they stopped working at some point. You could try the remapping-color-table approach in this answer: stackoverflow.com/a/14165523/303931 Supposedly that's using public APIs. Commented Jun 30, 2023 at 22:38
4

The .plist files which are modified by the Accessibility panel are found in ~/Library/Preferences and they are com.apple.CoreGraphics and com.apple.universalaccess.

No changes are made to any files in ~/Library/Preferences/ByHost

Execute the commands:

defaults write com.apple.universalaccess grayscale -bool yes

defaults write com.apple.CoreGraphics DisplayUseForcedGray -bool yes

Then force the color change to greyscale by unloading and reloading the universalaccessd process:

launchctl unload /System/Library/LaunchAgents/com.apple.universalaccessd.plist

launchctl load /System/Library/LaunchAgents/com.apple.universalaccessd.plist

To switch back to color execute the same commands with the defaults parameters set to no.

Unlike the Accessibility panel, which changes the color instantaneously, this method can take a few seconds to make the transition.

4
  • Testing on a 2.8 GHz Intel Core i7 and wrapped in a bash script, it took 10 seconds after the script executed for the grayscale to show. So I'd have to say "a few seconds" is misleading, but +1 anyway. Commented Jun 2, 2016 at 22:02
  • Perhaps there's a different launchctl command that makes it execute quicker? On my 3.4GHz Intel Core i7 it took no longer than 5-6 seconds, tops. I just timed it.
    – IconDaemon
    Commented Jun 2, 2016 at 22:07
  • I was providing the terminal commands the OP and others could use to create a shell script on their own. I prefer to use perl to create a script with these commands and wrap it in Platypus. Give a person a fish - they'll eat for one day. Teach them how to fish, and they'll never be hungry.
    – IconDaemon
    Commented Jun 2, 2016 at 23:20
  • 1
    On macOS 10.13.3 Beta, the launchctl commands produce this error message: Operation not permitted while System Integrity Protection is engaged. You can disable System Integrity Protection (see here), but doing so makes you more vulnerability to malware. Commented Jan 29, 2018 at 3:05
4

For Catalina and Big Sur, use this AppleScript code by opening the Script Editor application. Open a new document and copy the code. To make it double-clickable (as an application from the desktop, for instance), click File > Export and then choose as File Format > Application.

tell application "System Preferences"
    set the current pane to pane id "com.apple.preference.universalaccess"
    delay 1 #needs time to open universal access
    tell application "System Events" to tell process "System Preferences" to tell window "Accessibility"
        select row 5 of table 1 of scroll area 1 #open display preferences
        click radio button "Color Filters" of tab group 1 of group 1
        click checkbox "Enable Color Filters" of tab group 1 of group 1
    end tell
end tell
tell application "System Preferences" to quit

From here: https://gist.github.com/silesky/2da3a6bef1703e38d901ec9c623eecbd

2
  • Still working in Monterey, though it only worked when I changed "Color" to "Colour" on my (non-US English) system :) Commented Jan 17, 2022 at 9:29
  • Any way to get this working on Ventura? Changing "System Preferences" to "System Settings" doesn't fix it.
    – antoine
    Commented Oct 11, 2023 at 0:40
1

You can install the open-source Grayscale Mode app that lets you turn grayscale on/off with a custom shortcut or a single right-click on its menu bar icon

0

Install scriptisto by

  • Installing Homebrew
  • Installing Cargo with brew install --cask cargo
  • Running cargo install scriptisto

Also you need to have Xcode CLI tools installed (xcode-select --install).

Then save the following as gray_darwin.c, and make it executable (chmod +x gray_darwin.c).

#!/usr/bin/env scriptisto

   // Self-contained, has no dependencies except Xcode CLI.

   // scriptisto-begin
   // script_src: main.c
   // build_cmd: clang -g -O2 -std=c11 -Wall -framework ApplicationServices main.c -o ./script
   // scriptisto-end

#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>

CG_EXTERN bool CGDisplayUsesForceToGray(void);
CG_EXTERN void CGDisplayForceToGray(bool forceToGray);

int main(int argc, char** argv)
{
  bool isGrayscale;
  if (argc > 1) {
    if (argv[1][0] == 'y') {
      isGrayscale = false; // will toggle this to true
    } else if (argv[1][0] == 's') {
      printf("Grayscale is now: %d\n", CGDisplayUsesForceToGray());
      return 0;
    }
    else {
      isGrayscale = true;
    }
  } else {
    isGrayscale = CGDisplayUsesForceToGray();
    printf("isGrayscale = %d\n", isGrayscale);
  }
  CGDisplayForceToGray(!isGrayscale);
  printf("Grayscale is now: %d\n", CGDisplayUsesForceToGray());

  return 0;
}

Now you can use it like so:

function display-gray-is() {
    [[ "$(gray_darwin.c s)" == "Grayscale is now: 1" ]]
}
function display-gray-toggle() {
    gray_darwin.c
}
function display-gray-off() {
    gray_darwin.c n
}
function display-gray-on() {
    gray_darwin.c y
}
6
  • unfortunately scriptisto does not seem to be on brew or brew cask?
    – esaruoho
    Commented Jan 13, 2021 at 8:09
  • @esaruoho Install it via cargo.
    – HappyFace
    Commented Jan 18, 2021 at 21:41
  • please amend your solution/answer so it mentions the installation procedure. Much appreciated! @HappyFace
    – esaruoho
    Commented Jan 25, 2021 at 7:38
  • @esaruoho cargo install scriptisto
    – HappyFace
    Commented Jan 25, 2021 at 12:47
  • Ok @HappyFace, I've edited your original answer to include instructions on chmod +x, xcode cli install and cargo install.
    – esaruoho
    Commented Jan 26, 2021 at 6:26

You must log in to answer this question.

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