如何强制立即调用AppleScript的idle handler并生效新频率?
如何让AppleScript的idle handler修改频率后立即生效?
问题描述
我并非资深AppleScript开发者,目前正在学习并尝试使用idle handler。通过查阅资料,我编写了一个常驻脚本,其idle handler每20秒被调用一次(为简洁未添加错误处理),脚本带有菜单栏选项可修改handler的调用频率。
代码运行正常,但修改后的调用频率无法立即生效,需等待下一次idle handler被调用时才会启用新频率。我希望能强制立即调用该handler并让新频率即时生效,请问这是否可行?
原代码:
--******************* Begin Timer Code ******************* global sleepTimeSeconds set sleepTimeSeconds to 20 on idle say "Hi!! I'm awake now." return sleepTimeSeconds end idle --******************** End Timer Code ******************** --****************** Begin MenuBar Code ****************** use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" -- init new menu bar to build menus from scratch set menubar to current application's NSMenu's alloc()'s init() -- clear predefined menus set menuBarItem to current application's NSMenuItem's new() menubar's addItem:menuBarItem current application's NSApp's setMainMenu:menubar current application's NSApp's mainMenu()'s removeAllItems() -- make and edit App name's menu set asstMenuItem to menubar's addItemWithTitle:"" action:(missing value) keyEquivalent:"" set asstMenu to current application's NSMenu's alloc()'s init() menubar's setSubmenu:asstMenu forItem:asstMenuItem set quitMenuItem to asstMenu's addItemWithTitle:"Quit" action:"actionHandler:" keyEquivalent:"q" (quitMenuItem's setTarget:me) -- make and edit "File" menu set asstMenuItem to menubar's addItemWithTitle:"" action:(missing value) keyEquivalent:"" set asstMenu to current application's NSMenu's alloc()'s initWithTitle:"File" menubar's setSubmenu:asstMenu forItem:asstMenuItem set openMenuItem to asstMenu's addItemWithTitle:"Show Sleep Time Seconds" action:"actionHandler:" keyEquivalent:"t" (openMenuItem's setTarget:me) -- make and edit "Edit" menu set asstMenuItem to menubar's addItemWithTitle:"" action:(missing value) keyEquivalent:"" set asstMenu to current application's NSMenu's alloc()'s initWithTitle:"Edit" menubar's setSubmenu:asstMenu forItem:asstMenuItem set openMenuItem to asstMenu's addItemWithTitle:"Edit Sleep Time Seconds" action:"actionHandler:" keyEquivalent:"e" (openMenuItem's setTarget:me) on actionHandler:sender set theMenuItemTitle to title of sender as string if theMenuItemTitle is "Quit" then quit if theMenuItemTitle is "Show Sleep Time Seconds" then showSleepTimeSeconds(theMenuItemTitle) end if if theMenuItemTitle is "Edit Sleep Time Seconds" then editSleepTimeSeconds(theMenuItemTitle) end if end actionHandler: on showSleepTimeSeconds(theMenuItemTitle) display alert "Sleep Time = " & (sleepTimeSeconds as string) & " seconds." giving up after 3 end showSleepTimeSeconds on editSleepTimeSeconds(theMenuItemTitle) try set theResultReturned to (display dialog "Provide new Sleep Time in seconds:" default answer (sleepTimeSeconds as string) buttons {"Save", "Cancel"} default button "Cancel") on error showSleepTimeSeconds(theMenuItemTitle) return end try set theTextReturned to the text returned of theResultReturned set theButtonReturned to the button returned of theResultReturned if theButtonReturned = "Save" then set sleepTimeSeconds to theTextReturned as number end if showSleepTimeSeconds(theMenuItemTitle) end editSleepTimeSeconds --******************* End MenuBar Code *******************
解决方案
可以实现,只需在修改完间隔时间后,手动调用一次idle handler,并通过AppKit的API重置空闲计时器,就能让新频率立即生效。
修改后的关键代码部分:
on editSleepTimeSeconds(theMenuItemTitle) try set theResultReturned to (display dialog "Provide new Sleep Time in seconds:" default answer (sleepTimeSeconds as string) buttons {"Save", "Cancel"} default button "Cancel") on error showSleepTimeSeconds(theMenuItemTitle) return end try set theTextReturned to the text returned of theResultReturned set theButtonReturned to the button returned of theResultReturned if theButtonReturned = "Save" then set sleepTimeSeconds to theTextReturned as number -- 新增:立即触发idle并重置计时器 my idle() current application's NSApp's resetIdleTimer() end if showSleepTimeSeconds(theMenuItemTitle) end editSleepTimeSeconds
原理说明
- 手动调用
idlehandler:修改完sleepTimeSeconds后直接执行my idle(),会立即触发一次任务执行,同时让idle返回新的间隔值。 - 调用
resetIdleTimer():这个AppKit方法会让系统抛弃原来的剩余等待时间,立即基于新返回的间隔值重新计算下一次idle的触发时间,确保新频率即时生效。
内容的提问来源于stack exchange,提问作者Uncle Bill
相关产品推荐
相关产品推荐

