3

In Applescript, we can get the index number of the current page we are viewing in Skim with the following code:

tell application "Skim"
    activate
    set theDoc to front document
    get index for current page of theDoc
end tell

Is there a way to access the metadata page number instead of the regular page index?

metadata vs index


Assessibility Inspector Results

Accessibility Inspector just indicates that it is a text field. (Page number has been changed to 1098)

inspector results


Another way to access the text field

With the following code, in which {350, 55} is the position where the text field is located on my screen,

tell application "System Events" to click at {350, 55}

I've found out that the text field can be accessed with:

text field "Page" of group 2 of toolbar 1 of window "程元敏 - 2013 - 尚書學史.pdf (page 1150 of 1696)" of application process "Skim" of application "System Events"

Hence, the following attempt to get its value.

tell application "Skim"
    activate
    set theDoc to front document
    get value of text field "Page" of group 2 of toolbar 1 of theDoc
end tell

The above script resulted in this syntax error:

Expected end of line, etc. but found “"”.


Questions:

Besides telling me how to access the text field with code, I would also like to know why Accessibility Inspector failed to indicate any information about the text field?

Is there a way to directly access the metadata in of a pdf document with applescript?

Why do we have to embed tell application "System Events" to tell application process "Skim" within tell application "Skim" for the code to work?

  • Hi @sati ! Try accessibility inspector app and see if it is readable property – ankii Feb 7 at 5:16
  • The text field can be accessed by text field "Page" of group 2 of toolbar 1 of window "程元敏 - 2013 - 尚書學史.pdf (page 1150 of 1696)" of application process "Skim" of application "System Events" – Sati Feb 7 at 6:00
  • 2
    How about: tell application "System Events" to tell application process "Skim" to get value of text field "Page" of group 2 of toolbar 1 of window 1 – user3439894 Feb 7 at 6:20
  • It worked. But can window 1 be accessed through theDoc? The window might not be active all the time. – Sati Feb 7 at 6:24
  • Picking from @user3439894 set appName to (name of every application process whose frontmost is true and visible is true) as string answer here: apple.stackexchange.com/a/381473/313842 – ankii Feb 7 at 6:31
1

Below is an AppleScript that declares a handler to obtain a list of pages from a PDF document, to which you supply the file path. When the handler is called, if the file path is valid, it should return an AppleScript list that contains the page label of every page, ordered by page index. However, bear in mind that PDF pages are indexed from zero, while AppleScript lists are indexed from one. Therefore, item n from the returned list gives you the page label for the page at index n - 1.

use framework "Foundation"
use framework "PDFKit"
use scripting additions

property this : a reference to the current application
property PDFDocument : a reference to PDFDocument of this

on PDFPagesInDocument at filepath
        local filepath

        try -- test file exists
                set fileURL to filepath as text ¬
                        as {alias, POSIX file} ¬
                        as «class fsrf»
        on error
                return false
        end try

        script pages
                property list : {}
        end script

        tell PDFDocument to tell alloc()
                initWithURL_(fileURL)
                repeat with i from 0 to pageCount() - 1
                        tell pageAtIndex_(i) to set the end of the ¬
                                list of pages to its label() as text
                end repeat
        end tell

        return the list of pages
end PDFPagesInDocument

After pasting the above code into the top of your own script, you could then use it like this:

choose file of type "com.adobe.pdf" with prompt "Select PDF File"
set PDFpath to the result

PDFPagesInDocument at PDFpath

This would allow the user to select a PDF file themselves whenever the script runs. However, you can specify your own, hard-coded file path, as I do here:

PDFPagesInDocument at "/Users/CK/Library/Mobile Documents/iCloud~com~apple~iBooks/Documents/Sun Tzu - The Art of War trans Giles Pax Librorum 2009.pdf"
set pageList to the result

--> {"Cover", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "1", "2", "3", ¬
    "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", ¬
    "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", ¬
    "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", ¬
    "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", ¬
    "53", "54", "55", "56"}

As you can see, this particular PDF copy of Sun Tzu's The Art of War has 65 pages, where the page that a reader traditionally thinks of as being page 1, i.e. the first page one would flick to in order to begin reading a book's narrative, is the tenth page in the PDF file.


Other Questions:

Is there a way to access the metadata page number instead of the regular page index?

Solution above.

I would also like to know why Accessibility Inspector failed to indicate any information about the text field?

The software developer who codes an application gets to choose what information gets exposed for accessibility hooks. There are guidelines that Apple lays out for developers to follow, and thankfully, most are conscientious and make sure their software reports information about the main UI elements, which, at a minimum, is meant to include the elements' name, description, object class, its purpose (or role), its position in the hierarchy, and a few other basic bits.

Besides being nice for those who script the UI to death, they actually serve a greater purpose, in aiding users with special needs to be able to interface with software that they otherwise wouldn't be able to use (for example, a blind person cannot see the value displayed for a page index, but voice over software would use accessibility hooks to retrieve the information and read it aloud to the user...provided the information has been exposed).

It appears Skim developers are just lazy or don't wish blind people to be using their software.

I've found out that the text field can be accessed with:
text field "Page" of group 2 of toolbar 1 of window "程元敏 - 2013 - 尚書學史.pdf (page 1150 of 1696)" of application process "Skim" of application "System Events"
Hence, the following attempt to get its value:
tell application "Skim"
    activate
    set theDoc to front document
    get value of text field "Page" of group 2 of toolbar 1 of theDoc
end tell
The above script resulted in this syntax error:
Expected end of line, etc. but found “"”

The information you gleaned from the first snippet are class objects that all belong to the application System Events. So when you then try to get application Skim to reference these objects, it can't: it's never heard of a text field. It does, however, recognise text as the name of a class object (the class of all AppleScript strings), and then tentatively assumes that field is an identifier for a variable that it will need to look up and read the value from. That's where it would ordinarily then complain that you never declared a variable with that identifier, but the word "Page" that immediately follows is a bigger concern, as this makes no sense to it in any context.

That's when the compiler categorises this as being a syntax error, reports the double quote as the definitively-illegal character that makes the entire expression impossible to evaluate.

That said, even if it wasn't a syntactical error, it would have led to a runtime error because your reference stops at toolbar 1, having completely omitted the parent object of toolbar 1, which is window "程元敏 - 2013 - 尚書學史.pdf (page 1150 of 1696)" (which you could also refer to as window 1 for convenience), and its parent object, which is process "Skim", and its parent object, which is application "System Events".

What you needed to do is to take the snippet you were given, and use that with one tiny adjustment: the topmost object--which is the one at the end of the reference--is always going to be an application object, which in this case is "System Events". This is the object that owns all of the other objects that the reference contains, and is therefore the thing you need to be tell-ing:

tell application "System Events"
    value of text field "Page" of ¬
        group 2 of toolbar 1 of ¬
        window 1 of process "Skim"
end tell

However, do not--as you have done--put your tell application "System Events" block inside a tell application "Skim" block. Although you don't see it, AppleScript bitches about this, generates an error (quietly), figures out what you do mean, then thankfully gets on with it. But it slows things down, which is the best case scenario, but in other situations, it can cause overlapping object classes or terminology to clash. If you're lucky, it'll just cause the script to terminate in a runtime error. If you're unlucky, things get overwritten and data gets lost.

Unless there's a specific reason to, and you know precisely what you're doing when doing it, don't ever put one application tell block (or clause) inside another. Generally speaking, since most languages only carry out one operation at a time anyway (this isn't true, but pretend it is, because it is for AppleScript), you will only ever be getting AppleScript to talk to one application at any particularly point in your script, so try and make sure that this is the case when you review what you've written.

  • 1
    Updated answer, which is now complete. Answered all questions from OP. – CJK Feb 14 at 21:00
0

Here's my final code that worked:

tell application "Skim"
    activate
    set theDoc to front document
    tell application "System Events" to tell application process "Skim"
        set metaPage to (get value of text field "Page" of group 2 of toolbar 1 of window 1)
    end tell
end tell

Hope some of you could answer my other questions indicated above.


Taking the advice from @CJK's answer above, I have amended my code as follows:

tell application "Skim"
    activate
    set theDoc to front document
end tell

tell application "System Events" to tell application process "Skim"
     set metaPage to (get value of text field "Page" of group 2 of toolbar 1 of window 1)
end tell

You must log in to answer this question.

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