AppleScript: move cursor (up/down arrow) – with repeat loop - applescript

I’m trying to write an AppleScript to insert ["some text"] above ["found text"].
Here is what I wrote:
tell application "BBEdit"
activate
find "====" searching in text 1 of text document 1 with selecting match
key code 126 # Up Arrow
key code 126 # Up Arrow
keystroke "<tabhere>"
key code 125 # Down Arrow
key code 125 # Down Arrow
key code 125 # Down Arrow
end tell
I get the following error, with the first instance of "code" highlighted:
"Expected end of line, etc. but found identifier"
Following suggestion by #red_menace, I amended as follows:
tell application "BBEdit"
activate
find "====" searching in text 1 of text document 1 with selecting match
tell application "System Events"
key code 126 # Up Arrow
key code 126 # Up Arrow
keystroke "<tabhere>"
key code 125 # Down Arrow
key code 125 # Down Arrow
key code 125 # Down Arrow
end tell
end tell
… which works, but of course only once.
Now how can I get this into a repeat loop that runs until the end of the document? The following attempt runs amok (it caused my computer to cycle wildly through all open windows in all applications and I had to fore quit):
tell application "BBEdit"
activate
repeat
find "====" searching in text 1 of text document 1 with selecting match
set findClass to find "====" searching in text 1 of text document 1 with selecting match
if not found of findClass then exit repeat
tell application "System Events"
key code 126 # Up Arrow
key code 126 # Up Arrow
key code 48 # Tab
key code 125 # Down Arrow
key code 125 # Down Arrow
key code 125 # Down Arrow
end tell
end repeat
end tell
Thanks for any further help.

BBedit can replace text without keystrokes
tell application "BBEdit"
tell front document
replace "===" using "---" & return & "===" options {wrap around:true}
end tell
end tell

Related

Check whether scroll is finished using AppleScript

I have an AppleScript script to open the Mail app, open a mail, scroll down and take screenshot of the whole mail body. I am taking the screenshot by scrolling the page using keystroke 121 (page down). I don't know how much time I have to repeat the loop to reach the page end. Is there anyway we can identify if the scroll has reached the page end using AppleScript?
This is my code snippet for page down and taking screenshot:
open each_message
tell application "System Events"
delay 5
keystroke "f" using {command down, control down}
delay 3
key code 20 using {command down, shift down}
delay 5
key code 121
delay 5
key code 20 using {command down, shift down}
delay 5
keystroke "f" using {command down, control down}
end tell
After reading your question and ensuing comments...
Is there anyway we can identify if the scroll has reached the page end using AppleScript?
Yes
For some emails, it's fine. For some, it is duplicating the last page, for some, the screenshots are incomplete.   (From comments under the question.)
That is the nature of different length documents and pressing the Page Down key, and why maybe using a third-party application like Snagit is a better way to go.
That all said...
The example AppleScript code, shown below, was tested in Script Editor under 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.
As you did not include the complete code of your script, the following example AppleScript code is presented more as a proof of concept. It too may/will have extra screenshots, however, it ensures the page it all the way to the top before it starts taking the screenshots and ensures a screenshot of the whole last page is taken too, based on it stopping appropriately.
For testing purposes I started with an individual email opened in its own window, assuming that is what the open each_message at the top of the code you included does or represents.
Example AppleScript code:
tell application "Mail" to activate
delay 1
tell application "System Events"
keystroke "f" using {command down, control down}
delay 1
repeat while my getEmailFullScreenWindowScrollPosition() > 0.0
key code 116
delay 0.1
end repeat
delay 1
repeat while my getEmailFullScreenWindowScrollPosition() < 1.0
key code 20 using {command down, shift down}
delay 1
key code 121
delay 1
end repeat
key code 121
delay 1
key code 20 using {command down, shift down}
delay 1
keystroke "f" using {command down, control down}
end tell
to getEmailFullScreenWindowScrollPosition()
tell application "System Events" to ¬
return value of ¬
scroll bar 1 of ¬
scroll area 1 of ¬
window 1 of ¬
process "Mail"
end getEmailFullScreenWindowScrollPosition
Notes:
In Mail in macOS Catalina on my system there was no horizontal scroll bar when an opened email in its own window is in Full Screen view, and why the handler is directed to scroll bar 1. However, if you do need to query for its orientation, then for the handler use:
to getEmailFullScreenWindowScrollPosition()
tell application "System Events" to ¬
return value of ¬
first scroll bar of ¬
scroll area 1 of ¬
window 1 of ¬
process "Mail" whose ¬
orientation is ¬
"AXVerticalOrientation"
end getEmailFullScreenWindowScrollPosition
In testing the getEmailFullScreenWindowScrollPosition() handler, it would report 1.0 when there was still some page left but not showing on the screen, so I added the additional lines of code after the second repeat loop to ensure it was all captured.
The test email had content to the very end of the page and maybe isn't really representative of most emails. If you find that there is ample white space at the end of your emails then you may want to remove the following lines of code after the second repeat loop:
key code 121
delay 1
key code 20 using {command down, shift down}
Also note that I ended up using delay 1 for all but one of the delay commands, and it worked fine for me in testing, however, adjust as necessary for your system.
As this is just being presented as a proof of concept, I'll leave it to you to tweak the code to fit your needs.
Note that I am not affiliated with the developer of Snagit and have mentioned it as a possible option to capturing the entire scroll area of the screen in a single screenshot.
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.
Here's a handler that returns the current vertical scroll bar position for a message viewed in the frontmost message viewer. It makes a bunch of assumptions about which panels you have open and what orientation the viewer has, but it should give you something to work with:
set sp to my findMailScrollPosition()
on findMailScrollPosition()
tell application "System Events"
tell process "Mail"
tell window 1
tell splitter group 1
tell splitter group 1
tell scroll area 2
tell (first scroll bar whose orientation is "AXVerticalOrientation")
-- this will return a value between 0 and 1 (top to bottom)
return value
end tell
end tell
end tell
end tell
end tell
end tell
end tell
end findMailScrollPosition

Get text from current cursor position From Pages app in Mac

Is it possible to get the text of Pages app, from its current cursor position?
My requirement is like, when user type something in "Pages", I have to show suggestions for the word they are typing.
so I want to find out the current or last word, near current cursor position from "Pages" app.
Either by using AppleScript or Accessibility?
Text is not selected.
I am not looking for "Services" also.
For apps other than "Pages", I used Accessibility and appleScript. but for pages I am not finding any way.
I have also tried below AppleScript, but some reason it works perfectly in "Script Editor", but when I use it in my code, it goes to infinite loop.
tell application "Pages"
activate
end tell
tell application "System Events"
tell application "System Events"
key code 123 using {shift down, command down} -- shift-command-left
end tell
tell process "Pages"
keystroke "c" using {command down}
delay 1
tell application "System Events"
key code 124 -- shift-command-left
end tell
set myData to (the clipboard) as text
return myData
end tell
end tell
If I run this AppleScript in my app, it freeze my Mac only, I have to force quit the Mac to stop it.
This works for me using the latest versions of macOS Mojave and Pages
property theApp : "Pages" -- change value to name of any other application (TextEdit)
tell application theApp to activate
delay 3
tell application "System Events"
tell application process theApp
-- Move the insertion point to the beginning of the previous word.
key code 123 using {option down} -- left arrow key while holding option down
delay 0.2
-- Move the insertion point to the end of the next word. (selects the word)
key code 124 using {shift down, option down} -- right arrow key while holding option and shift down
delay 0.2
keystroke "c" using {command down} -- copies selected wprd
delay 0.2
-- Next 2 key code commands attempt to restore cursor location
key code 124 using {option down} -- right arrow key while holding option down
delay 0.2
key code 123 using {option down} -- left arrow key while holding option down
tell current application to set myData to (the clipboard) as text
delay 4
return myData
end tell
end tell

Applescript: Pasting Clipboard Text into Open/Save Dialog Box

I have many untitled TextEdit files. I'd like to use applescript to save each using, as a name, the text of the top line of each document.
The following will select and copy the first line of a document (not elegant, but it works), but I can't figure out how to paste the clipboard into the save dialog box (and hit "save" afterwards). Can anyone help?
tell application "TextEdit" to activate
tell application "TextEdit"
tell application "System Events" to key code 126 using command down
tell application "System Events" to key code 125 using shift down
tell application "System Events" to key code 8 using command down
end tell
There are 2 ways of doing:
1) the method using GUI scripting: this is what you've started to do. You simulate keyboard events like a user. It is not recommended for mainly 3 reasons: It is usually slow (you need to add delays to leave time for system open window, close them,..). During the script, if user hits key/mouse by mistake, your script will fail. And finally, you're hardly dependent of user interface of the application: if the editor (here Apple with TextEdit) changes something, like a short cut key, your script will no longer work.
Despite that, if you still want to use that way, here is the script that does it for you. I recommend that you add comments as I did (how to remember that key code 8 is 'c' !). I added some extra options to select the path to save (go home folder, enter special path,...). Up to you to use them or not:
tell application "TextEdit"
activate
tell application "System Events"
key code 126 using command down -- command up (cursor at start)
key code 125 using shift down -- shift down (select 1st line)
keystroke "c" using command down -- command C (copy)
keystroke "s" using command down -- open save dialog
delay 0.5 -- to let save as dialog time to open
keystroke "v" using command down -- paste the title from clipboard
-- other options
-- keystroke "h" using {command down, shift down} -- go home directory
delay 0.5
keystroke "g" using {command down, shift down} -- go to dialog
delay 0.5
keystroke "Desktop/Sample" -- path from Documents folder to Sample folder on Desktop
delay 0.5
keystroke return -- close the go to dialog
delay 0.5
keystroke return -- close the save as dialog
end tell
end tell
2) the method using Applescript instructions. It is usually much shorter, more elegant script, much faster to run, and user can't break it during execution. The script bellow does same as script above: It selects the first text row and save the document with that title. Line 1 defines the folder where to save:
set myPath to (path to desktop folder) as string -- path where to save file
tell application "TextEdit"
activate
tell front document
set myTitle to first paragraph
set myTitle to text 1 thru -2 of myTitle -- to remove the return at end of paragraph
save in (myPath & myTitle)
end tell
end tell
I hope it helps

applescript copy paste between textedit and 3rd party application not working

I have searched all over this site and cannot find an answer to why this code isn't doing what I need it to do. I have a textedit doc with a list of numbers. I want to copy 1 number at a time paste that number into a 3rd party application at a specific place in url, and then hit some buttons in the ui of that application. I need this process to repeat for each individual number in the textedit document.
Here is what I came up with after researching applescript.
tell application "TextEdit" to activate
tell application "System Events"
tell process "TextEdit"
key code 124 using {shift down, command down}
keystroke "c" using command down
key code 125
end tell
end tell
delay 1.0
tell application "import.io" to activate
tell application "System Events"
tell process "import.io"
keystroke tab
keystroke tab
key code 124
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 51
keystroke "v" using command down
keystroke tab
key code 76
end tell
end tell
-- Make a selection from the popupbutton.
delay 2.231426
set timeoutSeconds to 10.0
set uiScript to "click pop up button 1 of window \"Save\" of application process \"import.io\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
end run
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
-- Click the “<fill in title>” checkbox.
delay 1.496275
set timeoutSeconds to 10.0
set uiScript to "click checkbox 1 of window \"Save\" of application process \"import.io\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
-- Type “Data” into the text field.
delay 7.290406
set timeoutSeconds to 10.0
set uiScript to "click text field 1 of group 17 of list 1 of scroll area 1 of scroll area 1 of browser 1 of splitter group 1 of splitter group 1 of group 2 of window \"Save\" of application process \"import.io\""
keystroke "Data"
keystroke "."
tell application "System Events" to tell process "import.io"
keystroke "v" using command down
end tell
my doWithTimeout(uiScript, timeoutSeconds)
return input
-- Click the “Save” button.
delay 1.475013
set timeoutSeconds to 10.0
set uiScript to "click UI Element \"Save\" of window \"Save\" of application process \"import.io\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
my textedit document is formatted like this:
50
100
150
200
etc
When I run the script this is what it does to my textedit document:
50
50
100
150
200
etc
Any idea what is going on here? I can't make heads or tails of it.
Looking for result in your TextEdit file, first you must start to simplify the textEdit copy part. I assumed that the TextEdit document is already open.
The script bellow provides simplification for copy part :
tell application "TextEdit"
activate
set myNumbers to every paragraph of front document
end tell
repeat with aNumber in myNumbers -- loop through each number
set the clipboard to aNumber
-- insert here the paste instructions in your third party application
end repeat
You must insert the instruction about the paste in the loop, after the 'set clipboard...' instruction which fills the clipboard with a number.
I can't help you for the paste part, because I don't know your third party application, however, your program calling other scripts in doWithTimeout routine does not seems to be very clean and efficient.
If this third party application is not scriptable, at least you may have to go via GUI scripting or java (if java based application).
For instance, instead of doing all the key arrows to move to correct input cell, try to address that cell directly by its GUI properties.
Same for the checkbox, you can also use GUI click function.
The disadvantage of GUI scripting is that application interface must not changed. But this is already the case in your script.

Automator Apple Script for Switching to Next Space

I'm very new to Applescript and I was looking to create an application that automatically switches between the desktops or spaces (as Apple calls them). Here is the code I have so far:
tell application "System Events"
key code 39 using {control down}
end tell
If I replace the "key code 39 using {control down}" section with keystroke "n" or any other key letter, it appears to work, but with my current code nothing occurs. Why would it not be executing?
Code 39 is not the arrow you want for space changes. I found a list of numbers in another answer and key code 124 was the equivalent of using the right arrow to switch to the next space in my setup. I plugged that number into your code:
tell application "System Events"
key code 124 using {control down}
end tell
And this successfully switched to my next space.
Note that with your code, something did happen when running it inside of Script Editor: an apostrophe was added to the end of the code.

Resources