Search code examples
applescriptcalculatorautomator

How to use AppleScript with Calculator.app to Automatically select the number of Decimals


Every time I enter a number in Calculator.app I need to go the top menu and select: View >> Decimal Places >> [0 , 15] And choose the number of decimals.

Is there a way to make an AppleScript that will automatically do so, based on the number I entered?

My input ways are:

  1. by pasting the number
  2. by typing the number

For the pasting part, if you PASTE a number ending in 0, Calculator.app won't show the 0, so it will show one decimal less than the reality. I don't know if this could be also overcome.

Example, if you paste: 12.30 it will show 12.3 if you type: 12.30 it will show 12.30


Solution

  • Building on the addendum to my answer to your other question How can I copy result from Calculator.app to the clipboard using AppleScript, here is a way the trap ⌘V in Calculator and set Calculator > View > Decimal Places to the number of decimal places of the number on the clipboard.

    What the example AppleScript code does:

    When pressing ⌘V in Calculator the contents of the clipboard is set to a variable and if it contains a decimal point it sets the Calculator > View > Decimal Places menu to the number of decimal places in the number, then keystrokes the number into Calculator. Note that keystroking the number would probably not require you to set the number of decimal places, however I'll leave that up to you to decide.

    Example AppleScript code:

    set theNumberToType to the clipboard as text
    
    if theNumberToType contains "." then
        set theNumberOfDecimalPlaces to count characters ((offset of "." in theNumberToType) + 1) thru -1 of theNumberToType
        if theNumberOfDecimalPlaces is greater than 15 then set theNumberOfDecimalPlaces to 15
    else
        set theNumberOfDecimalPlaces to -1
    end if
    
    tell application "Calculator" to activate
    
    tell application "System Events"
        if theNumberOfDecimalPlaces is greater than -1 then
            click (first menu item of menu 1 of menu item "Decimal Places" of menu 1 of menu bar item "View" of menu bar 1 of process "Calculator" whose name is theNumberOfDecimalPlaces)
        end if
        delay 0.1
        keystroke theNumberToType
    end tell
    

    The example AppleScript code above is saved as CalculatorSetDecimalPlaces.applescript in: ~/.hammerspoon/Scripts/, like in my other answer to your other question.

    Example Lua code:

        --  Create a hotkey used to trap the command v shortcut and disable it.
        --  It will then be enabled/disabled as Calculator is focused/unfocused.
        --  When enabled and command v is pressed it runs the AppleScript script.
    
    local applicationCalculatorCommandVHotkey = hs.hotkey.bind({"cmd"}, "V", function()
        local asFile = "/.hammerspoon/Scripts/CalculatorSetDecimalPlaces.applescript"
        local ok, status = hs.osascript.applescriptFromFile(os.getenv("HOME") .. asFile)
        if not ok then              
            msg = "An error occurred running the CalculatorResultToClipboard script."
            hs.notify.new({title="Hammerspoon", informativeText=msg}):send()            
        end
    end)
    applicationCalculatorCommandVHotkey:disable()
    
    
        --  Add the following two line respectively before or after the lines
        --  applicationCalculatorEnterHotkey:enable()
        --  applicationCalculatorEnterHotkey:disable()
        --  in either of the two methods presented in my other answer.
    
    applicationCalculatorCommandVHotkey:enable()
    
    applicationCalculatorCommandVHotkey:disable()
    

    Notes:

    With the example Lua code, as coded, the behavior of the ⌘V keyboard shortcut is only trapped and modified to trigger the example AppleScript code while Calculator has focus. The ⌘V keyboard shortcut should work normally in all other applications.

    The example Lua code above is added to the ~/.hammerspoon/init.lua file from my other answer to your other question.

    The example Lua code and API's of Hammerspoon and AppleScript code, shown above, were tested respectively with Hammerspoon and Script Editor under macOS Mojave and macOS Catalina with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.

    • 1 Assumes necessary and appropriate settings in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.


    Update using only Lua without AppleScript

    The following example Lua code eliminates the use of AppleScript from both this answer and the code in the other answer to your other related question.

    Overwriting the existing code, copy and paste this into your ~/.hammerspoon/init.lua file, save it and run Reload Config from the Hammerspoon menu on the menu bar.

    I have performed all the various actions and calculations discussed in the comments and had no issues occur with this new code. Hopefully this will eliminate any issues you were having.

    This should also run faster now that it does have to process AppleScript code as well.

    Note that as coded it is not automatically reloading the configuration file as that just should not be necessary.

        --  Create a hotkey used to trap the enter key and disable it.
        --  It will then be enabled/disabled as Calculator is focused/unfocused
        --  When enabled and the enter key is pressed it presses = then command C.
    
    local applicationCalculatorEnterHotkey = hs.hotkey.bind({}, "return", function()
            --  Press the '=' key to finish the calculation.
        hs.eventtap.keyStroke({}, "=")
            --  Copy the result to the clipboard.
        hs.eventtap.keyStroke({"cmd"}, "C")
    end)
    applicationCalculatorEnterHotkey:disable()
    
    
        --  Create a hotkey used to trap the command v shortcut and disable it.
        --  It will then be enabled/disabled as Calculator is focused/unfocused.
        --  When enabled and command v is pressed it runs the Lua code within.
    
    local applicationCalculatorCommandVHotkey = hs.hotkey.bind({"cmd"}, "V", function()
            --  Get the number copied to the clipboard.
        local theNumberToType = hs.pasteboard.readString()
            --  See if there is a decimal in the number
            --  and if so how many decimal places it has.
        local l = string.len(theNumberToType)
        local s, e = string.find(theNumberToType, "%.")
        if s == nil then
             theNumberOfDecimalPlaces = -1
        elseif l - s > 15 then
             theNumberOfDecimalPlaces = 15
        else
             theNumberOfDecimalPlaces = l - s
        end
            --  Set the number of decimal places to show.
        if theNumberOfDecimalPlaces > -1 then
            local calculator = hs.appfinder.appFromName("Calculator")
            local vdpn = {"View", "Decimal Places", theNumberOfDecimalPlaces}
            calculator:selectMenuItem(vdpn)
        end
            --  Type the number into Calculator.
        hs.eventtap.keyStrokes(theNumberToType)
    end)
    applicationCalculatorCommandVHotkey:disable()
    
    
        --  One of two methods of watching Calculator.
        --  
        --  The other is below this one and commented out.
    
        --  Initialize a Calculator window filter.
    
    local CalculatorWindowFilter = hs.window.filter.new("Calculator")
    
        --  Subscribe to when the Calculator window is focused/unfocused.
    
    CalculatorWindowFilter:subscribe(hs.window.filter.windowFocused, function()
            --  Enable hotkeys when Calculator is focused.
        applicationCalculatorCommandVHotkey:enable()
        applicationCalculatorEnterHotkey:enable()
    end)
    CalculatorWindowFilter:subscribe(hs.window.filter.windowUnfocused, function()
            --  Disable hotkeys when Calculator is unfocused.
        applicationCalculatorCommandVHotkey:disable()
        applicationCalculatorEnterHotkey:disable()
    end)
    
    
        --  Alternate method to wait for Calculator and enable/disable the hotkey.
        --  
        --  Uncomment below method and comment the above method to test between them.
        --  The opening '--[[' and closing '--]]' and removed from below added to above.
    
    --[[    
    
    function applicationCalculatorWatcher(appName, eventType, appObject)
        if (eventType == hs.application.watcher.activated) then
            if (appName == "Calculator") then
                    --  Enable hotkeys when Calculator is activated.
                applicationCalculatorCommandVHotkey:enable()                
                applicationCalculatorEnterHotkey:enable()
            end
        end
        if (eventType == hs.application.watcher.deactivated) then
            if (appName == "Calculator") then
                 -- Disable hotkeys when Calculator is deactivated.
                applicationCalculatorCommandVHotkey:disable()            
                applicationCalculatorEnterHotkey:disable()
            end
        end
    end
    appCalculatorWatcher = hs.application.watcher.new(applicationCalculatorWatcher)
    appCalculatorWatcher:start()
    -- appCalculatorwWatcher:stop()
    
    --]]