How to make preview stop wrapping around when paging

pdfpreview

If I open a PDF document in Preview and navigate through the pages normally using Page down and Page up, then if I hold down the keys to trigger auto-repeat, when I reach the bottom (or top) of the document, Preview wraps around and shows me the top (or bottom) again. For example, if I press and hold Page down to page forward, then when it reaches the end of the document, it doesn't stop there; it starts back at the top, going around in a kind of loop. The behavior only happens if I set my key repeat rate (in system preferences) to the maximum possible.

What could cause this, and how can I prevent this from happening (short of reducing the keyboard repeat rate), so that Preview stops when it reaches the top or bottom of a document?

This is on macOS 10.13.6, on an iMac. This happens both with a Kinesis Pro keyboard and a bog-standard Dell USB keyboard; both have dedicated page up/down keys. In Preview settings, "opening for the first time" is set to continuous scroll. Example of a random PDF file where it happens: https://www.apple.com/procurement/pdf/impact-accelerator.pdf Here is a video recording showing the behavior: https://share.getcloudapp.com/8LubXNo5

Best Answer

As discovered, this issue currently only exists with Preview when the Key Repeat slider on the Keyboard tab of the Keyboard pane in System Preferences is set to Fast, where the slider is all the way to the right. By default it's one position from the right.

This is a workaround solution that sets the Key Repeat slider to the default position when Preview is activated, and to Fast when it's deactivated, (i.e. given/lost keyboard/mouse focus).

It uses the third-party application Hammerspoon along with a bit of Lua code to watch for Preview being activated/deactivated, and an AppleScript script using UI Scripting to adjust the Key Repeat slider on the Keyboard tab of the Keyboard pane in System Preferences.

The example Lua code and exampleAppleScript code, shown further below, was tested under macOS High Sierra 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 setting in System Preferences > Security & Privacy > Privacy > Accessibility have been set/addressed as needed.


  • Note that the download and install instructions assume Safari and default preference [√] Open “safe” files after downloading checked.

Download Hammerspoon



Install Hammerspoon

  • Open the Downloads folder and drag and drop the Hammerspoon application bundle into Applications.

  • Before you open Hammerspoon, add it to: System Preferences > Security & Privacy > Privacy > Accessibility

Open Hammerspoon from Applications or Spotlight, then:

From the Hammerspoon menu, on the menu bar, click it, then click Preferences…, and set them as follows:

Hammerspoon Preferences

Behavior:

  • [√] Launch Hammerspoon at login
  • [√] Check for updates
  • [ ] Show dock icon
  • [√] Show menu icon
  • [ ] Keep Console window on top
  • [ ] Send crash data (requires restart)

Accessibility: Accessibility is enabled. Your all set!
         Enable Accessibility (Should be grayed out.)

Close Hammerspoon Preferences.



Adding the Lua code to Hammerspoon

Open the Hammerspoon configuration file by clicking the Open Config command from the Hammerspoon menu, on the menu bar.

Add the example Lua code to the init.lua configuration file and save the document, then close it.



Example Lua code:

function applicationPreviewWatcher(appName, eventType, appObject)
    if (eventType == hs.application.watcher.activated) then
        if (appName == "Preview") then
            local asFile = "/.hammerspoon/Scripts/ChangeKeyRepeatValue.applescript"
            local ok, status = hs.osascript.applescriptFromFile(os.getenv("HOME") .. asFile)
        end
    end
    if (eventType == hs.application.watcher.deactivated) then
        if (appName == "Preview") then
            local asFile = "/.hammerspoon/Scripts/ChangeKeyRepeatValue.applescript"
            local ok, status = hs.osascript.applescriptFromFile(os.getenv("HOME") .. asFile)
        end
    end 
end
appPreviewWatcher = hs.application.watcher.new(applicationPreviewWatcher)
appPreviewWatcher:start()
-- appPreviewWatcher:stop()


Adding the AppleScript script to Hammerspoon

In Terminal:

mkdir -p ~/.hammerspoon/Scripts
touch ~/.hammerspoon/Scripts/ChangeKeyRepeatValue.applescript
open ~/.hammerspoon/Scripts/ChangeKeyRepeatValue.applescript

Close: Terminal (Assumes no errors from previous commands.)


In Script Editor:

Add the example AppleScript code, shown below, to the opened ChangeKeyRepeatValue.applescript document, then save it, and close the document.

Close: Script Editor

NOTE: With that done, you can now click the Reload Config command on the Hammerspoon menu, on the menu bar.

This should now toggle the Key Repeat slider on the Keyboard tab of the Keyboard pane in System Preferences as Preview is activated/deactivated.



Example AppleScript code:

--  # 
--  # NOTE: Hammerspoon does not allow the use of the
--  #       AppleScript line continuation character.
--  #       Therefore code must be written in long form.
--  #       It also doesn't like the use of some characters
--  #       such as symbols for modifier keys and others
--  #       in comments and possibly in code as well.
--  # 
--  # ChangeKeyRepeatValue.applescript
--  #
--  # Change the value of Key Repeat on the Keyboard tab 
--  # of the Keyboard pane in System Preferences. 
--  # 

--  # Check to see if System Preferences is 
--  # running and if yes, then close it.
--  # 
--  # This is done so the script will not fail 
--  # if it is running and a modal sheet is 
--  # showing, hence the use of 'killall' 
--  # as 'quit' fails when done so, if it is.
--  #
--  # This is also done to allow default behaviors
--  # to be predictable from a clean occurrence.

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

--  # Make sure System Preferences is not running before
--  # opening it again. Otherwise there can be an issue
--  # when trying to reopen it while it's actually closing.

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

--  # Get the name of the frontmost application.

tell application "System Events"
    set appName to name of process 1 whose frontmost is true
end tell

--  # Open System Preferences to the Keyboard tab of the Keyboard pane.

tell application "System Preferences"
    reveal anchor "keyboardTab" of pane id "com.apple.preference.keyboard"
end tell

--  # Change the value of Key Repeat as coded.

tell application "System Events"
    tell application process "System Preferences"
        set i to 0
        repeat until exists slider 2 of tab group 1 of window 1
            delay 0.1
            set i to i + 1
            if i > 30 then return
        end repeat
        if appName = "Preview" then
            set value of slider 2 of tab group 1 of window 1 to 6.0
        else
            set value of slider 2 of tab group 1 of window 1 to 7.0
        end if
    end tell
end tell

delay 0.1
tell application "System Preferences" to quit


Notes:

As currently coded, it assumes when Hammerspoon is first loaded that the Key Repeat slider on the Keyboard tab of the Keyboard pane in System Preferences is set to Fast and Preview is not frontmost.

It is normal to see the System Preferences icon on the Dock bounce once briefly showing the open indicator under it when Hammerspoon sees that Preview has been activated/deactivated. It's running the AppleScript script to change the position of the Key Repeat slider on the Keyboard tab of the Keyboard pane in System Preferences. This on my system takes less than a second. If I can find a way to programmatically behind the scene make this change without having to use UI Scripting with AppleScript I will update the code and notify the OP.

There is an issue with this workaround when manually clicking on System Preferences in the Dock when Preview is frontmost. To manually open System Preferences from the Dock when Preview is frontmost you need to set focus away from Preview first before clicking on System Preferences in the Dock. The behavior when Preview is frontmost and manually trying to open System Preferences from the Dock results in System Preferences being opened and closed, bouncing on the Dock, without further user interaction. (I'll see what I can do to resolve this issue, although I think it's a nature of the beast type bug that one will just need to be aware of and live with for the benefit of what this solution provides.)

I am not affiliated with the developers of Hammerspoon, just a satisfied user of the product.



Note: The example Lua and 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.