Simulated key command not working since OS upgrade - applescript

I considered posting this to Ask Different but I thought it belonged here due to being mainly focused on code.
I have created a macro on my mac for switching spaces, and since upgrading to Sierra the following AppleScript is no longer working. Does anyone know if something has changed?
tell application "System Events" to key code 124 using control down
and
tell application "System Events" to key code 123 using control down
This is the output when running in terminal (note the ^[[1;5D):
14:16 isaac#Isaac ~ $ osascript -e 'tell application "System Events" to key code 123 using control down'
^[[1;5D14:18 isaac#Isaac ~ $ ;5D
And when running via AppleScript Editor, nothing happens.

Yes, it's a bug.
To simulate some global shortcut with the Control key, the command needs the fn key (a workaround for Sierra).
It's not possible to use the fn key with the AppleScript's key code command, but it's possible with the methods of the Core Graphics framework in a Python script.
Here's the script to simulate this shortcut --> (Right Arrow + Control), you can run the script in the Terminal (in a sh, bash or any similar shell)
/usr/bin/python -c 'import time; import Quartz.CoreGraphics as QCG; e = QCG.CGEventCreateKeyboardEvent(None, 124, True); QCG.CGEventSetFlags(e, (QCG.kCGEventFlagMaskControl | QCG.kCGEventFlagMaskSecondaryFn)); QCG.CGEventPost(QCG.kCGHIDEventTap, e); time.sleep(0.1); QCG.CGEventSetType(e, QCG.kCGEventKeyUp); QCG.CGEventPost(QCG.kCGHIDEventTap, e)'
Here's an AppleScript to test in the "Script Editor" application:
-- For switching spaces, 124 = the Right Arrow key, use 123 for the Left Arrow key
do shell script "/usr/bin/python -c 'import time; import Quartz.CoreGraphics as QCG; e = QCG.CGEventCreateKeyboardEvent(None, 124, True); QCG.CGEventSetFlags(e, (QCG.kCGEventFlagMaskControl | QCG.kCGEventFlagMaskSecondaryFn)); QCG.CGEventPost(QCG.kCGHIDEventTap, e); time.sleep(0.1); QCG.CGEventSetType(e, QCG.kCGEventKeyUp); QCG.CGEventPost(QCG.kCGHIDEventTap, e)'"

Make sure your key codes match the keyboard shortcuts in system preferences. Here are my keyboard shortcuts in system preferences and they do coincide correctly with my AppleScript commands.
tell application "System Events"
key code 18 using (control down) -- Desktop 1
end tell
tell application "System Events"
key code 19 using (control down) -- Desktop 2
end tell
tell application "System Events"
key code 20 using (control down) -- Desktop 3
end tell
tell application "System Events"
key code 21 using (control down) -- Desktop 4
end tell
These function correctly for me in the latest version of Sierra.

Related

AppleScript shortcut for service not working, although clicking on application generated by Script Editor works fine

I created an AppleScript for a sequence of copy-paste keystrokes and delays:
Example AppleScript code:
tell application "System Events"
keystroke "k" using command down
delay 0.1
keystroke "a" using command down
delay 0.1
keystroke "c" using command down
delay 0.1
tell application "Google Chrome"
if it is running then
quit
else
activate
open location "http://translate.google.com"
delay 1
activate
delay 0.7
end if
end tell
tell application "System Events"
keystroke "v" using command down
delay 0.7
keystroke "c" using control down
end tell
end tell
I've exported it from Scripts Editor as an Application, and it works fine when I click on it.
When I try to execute it via a shortcut set at Systems Preferences > Keyboard > Shorcuts > Services, nothing happens; I just see the cog-wheel appearing briefly at the top bar. I already granted permission for the script-app at Systems Preferences > Security & Privacy > Accessibility and already checked if there are hotkeys conflicts at the Terminal typing: defaults find NSServicesStatus or defaults find '#~$]' (the shortcut I've tried to use was Command+Alt+Shift+].
Would you maybe have any suggestion of where can I check what I'm doing wrong?
Here is an option which takes a completely different route, without having to resort to using UI scripting and without having to open any browsers.
To be able to use my solution, you'll have to install the translate-shell shell command. In Terminal.app, I installed it using Homebrew with this command… brew install translate-shell
After successful installation of the translate-shell shell command, it can then be used in AppleScripts and Automator Workflows
This following AppleScript code will take the text, which is currently on your clipboard, and translate it to the language of your choice. It will then set the content of your clipboard to the translated text.
I took the liberty to add a few Language Codes to get you started.
property convertLanguage : {"Convert To Belarusian (be)", "Convert To Bulgarian (bg)", ¬
"Convert To Dutch (nl)", "Convert To English (en)", "Convert To Estonian (et)", ¬
"Convert To French (fr)", "Convert To German (de)", "Convert To Greek (el)", ¬
"Convert To Hebrew (he)", "Convert To Hungarian (hu)", "Convert To Italian (it)", ¬
"Convert To Polish (pl)", "Convert To Romanian (ro)", "Convert To Russian (ru)", ¬
"Convert To Spanish (es)", "Convert To Swedish (sv)", "Convert To Ukrainian (uk)"}
activate
set chosenLanguage to word 4 of ((choose from list convertLanguage ¬
with title "Language Translator" with prompt ¬
"Choose A Language To Convert To" OK button name ¬
"Translate" cancel button name "Cancel") as text)
convertToLanguage(chosenLanguage)
on convertToLanguage(twoLetterLanguageCode)
set textToConvert to the clipboard
delay 0.1
set the clipboard to ¬
(do shell script "export PATH=\"/usr/local/bin:$PATH\";/usr/local/bin/trans -b :" & ¬
quoted form of twoLetterLanguageCode & " " & ¬
quoted form of (textToConvert as text))
end convertToLanguage
This following animation demonstrates the conversion of the English text (already on my clipboard) to French. Then I paste the converted text into the document.
You should reduce GUI scripting to have more stable code. Workaround is shown here:
my copyTextToClipboard()
set sourceText to (the clipboard) as string
my performGoogleTranslate(sourceText)
my getTranslatedTextToClipboard()
on copyTextToClipboard()
tell application "System Events"
keystroke "k" using command down
delay 0.1
keystroke "a" using command down
delay 0.1
keystroke "c" using command down
delay 0.1
end tell
end copyTextToClipboard
on performGoogleTranslate(sourceText)
-- following translates from English (en) to Russian (ru)
-- you can put other languadges settings
set myURL to "https://translate.google.gr/?
hl=el#view=home&op=translate&sl=en&tl=ru&text=" & sourceText
tell application "Google Chrome"
activate
set URL of active tab of window 1 to myURL
end tell
end performGoogleTranslate
on getTranslatedTextToClipboard()
-- HERE you need some mouse tool to move the mouse pointer over
-- the "Copy" button of Google Translate and to click it
end getTranslatedTextToClipboard

Mac OSX - Firefox --new-tab option doesn't work

I was trying to force a new tab to open in firefox via a terminal command.
If I run /Applications/Firefox.app/Contents/MacOS/firefox --help, it tells me that there is a --new-tab <url> parameter.
But when I make use of it, firefox reports:
Close Firefox
A copy of Firefox is already open. Only one copy of Firefox can be open at a time.
Googling online revealed reasons and a potential workaround:
https://support.mozilla.org/en-US/questions/1130718
https://bugzilla.mozilla.org/show_bug.cgi?id=393645
I tried the workaround AppleScript, but it only worked on the first run attempt, and failed on every other occasion.
I mainly posted the question as a means to document and share my solution.
I made use of what I believe to be Ivan Enderlin's Apple Script, "ffnewtab.scpt". The only addition I made to it was to add a one second delay (the "delay 1" line) between activating firefox and creating a new tab. It seemed as though on my system, the script ran too fast and didn't give firefox enough time for the new tab to open, probably due to my macbook being somewhat old and slow:
on firefoxRunning()
tell application "System Events" to (name of processes) contains "Firefox"
end firefoxRunning
on run argv
if (firefoxRunning() = false) then
do shell script "open -a Firefox " & (item 1 of argv)
else
tell application "Firefox" to activate
delay 1
tell application "System Events"
keystroke "t" using {command down}
keystroke item 1 of argv & return
end tell
end if
end run
Then it runs fine for me with:
osascript ffnewtab.scpt <url>

XCode 5 behavior script generating permission error

This morning I thought I'd spend a few minutes to write an XCode 5 script for Prefereces->behaviors to hide panels to better focus on Code and storyboard. A few command keys: how long can that take.....
I used AppleScript, and it runs fine from the applescript editor. I then exported it as a script bundle and hooked it to a behavior within XCode. When I hit the key command, I get the permissions error:
Failed to launch script /Users/sss/Documents/pers/XCode Scripts/XCodeCodeFocus.scptd: The operation couldn’t be completed. Permission denied
The AppleScript is very basic: I've tried:
activate application "Xcode"
tell application "System Events" to keystroke "Y" using command down
tell application "System Events" to keystroke "0" using {command down, option down}
tell application "System Events" to keystroke "1" using command down
and (without the activate command in case that's causing havoc)
tell application "System Events" to keystroke "Y" using command down
tell application "System Events" to keystroke "0" using {command down, option down}
tell application "System Events" to keystroke "1" using command down
File permissions on the file are:
drwxr-xr-x# 3 sss staff 102 Oct 4 06:31 XCode Code Focus copy.scptd
The file is in my code directory, but I can't see why that would affect things.
Is this broken in XCode 5, or am I missing something....
many thanks!

Applescript to Expose all Finder Windows?

I'm trying to figure out how to write an Applescript that will Exposé all Finder Windows.
Application Logic
I think the script needs to have this application logic:
Check a residual setting and get the name of the last "Frontmost
Application" (perhaps use a text file ~/last-application.txt to store this?)
Grab the name of the current Frontmost Application
If the name of the current of the Frontmost Application is Expose, then activate the previous frontmost application
Else, activate finder, and then activate expose for just finder windows
Desired Behavior
When the script is activated all the finder windows (and only the finder windows) will be shown in Exposé
If the script is then run again (and no finder window was selected) the script will just switch back to the last frontmost application
I'm not sure how to get this working though. If there is another utility that does this automatically that'd be great, too.
set f to "/s/x/finderexpose"
set prev to do shell script "touch " & f & "; cat " & f
if prev is not "" then
delay 0.5 -- time to release modifier keys used in a shortcut
tell application "System Events" to key code 53 -- esc, if Exposé is open
delay 0.3 -- for the Exposé animation?
activate application prev
do shell script "echo '' > " & f
else
do shell script "echo " & quoted form of (path to frontmost application as text) & " > " & f
activate application "Finder"
delay 0.05
tell application "System Events" to key code 125 using {control down} -- ⌃↓
end if
It'd be less ugly if the part for switching to the previous application was left out:
activate application "Finder"
delay 0.05
tell application "System Events" to key code 125 using {control down}

Using AppleScript to choose a file in Safari

I am trying to write some automation code (primarily in Ruby Selenium). At some point, a file chooser is opened in Safari so that the user can select a file for upload. Selenium cannot handle this, but I think AppleScript should be able to. I am new to AppleScript and haven't been able to find any boilerplate code of someone automating a file chooser dialog. I'm reading through the AppleScript docs, but any ideas would be most helpful.
Some more searching and I found a great answer here: Applescript file dialog with UI scripting
Here's what I ended up using:
on run argv
tell application "Safari"
activate
-- Usage check
set argc to count argv
if argc is not greater than 0 then
return "Usage: SafariFileChooser file_name [window_name]"
end if
-- The file we will choose to open
set file_name to item 1 of argv
-- Flip to the named window, if specified
if argc is equal to 2 then
set window_name to item 2 of argv
set flip_count to index of window window_name
repeat (flip_count - 1) times
activate
tell application "System Events" to keystroke "`" using command down
end repeat
end if
-- Interact with the dialog using System Events (thanks mcgrailm)
tell front window
activate
tell application "System Events"
keystroke "g" using {shift down, command down}
keystroke file_name
delay 1
keystroke return
delay 1
keystroke return
end tell
end tell
end tell
return 0
end run
Another option I just discovered is to specify the directory using the command-line:
do shell script "defaults write com.apple.Safari NSNavLastRootDirectory /path/to/directory"
This way you can do slightly less in UI scripting. Run this command before you open the file chooser, and it will put you into the directory specified. Include all the files you need in this directory, and you can just script command+a to select them all, and return.

Resources