AppleScript IOBluetooth 问题,但仅当导出为应用程序时
AppleScript IOBluetooth issue, but only when exported as an app
基于 我正在使用 IOBluetooth
框架来检测我的键盘 disconnect/reconnect,因此将其切换到第二个主机会触发将显示输入更改为该主机嗯
当我在脚本编辑器中运行它时,它会在我来回切换时检测连接和断开状态。当我将它导出为应用程序(仅 运行-only)和 运行 时,它开始检测正确的状态。然而,一旦键盘断开并稍后重新连接,它就再也检测不到连接状态。
如果重要的话,我在 2019 MacBook Pro 上使用 Catalina (10.15.7)。
use framework "IOBluetooth"
use scripting additions
property lastStatus : true
set debug to true
set myKeyboard to "Keychron"
repeat
set kbStatus to isDeviceConnected(myKeyboard)
if kbStatus is not equal to lastStatus then
if debug is false then
if kbStatus is true then
do shell script "/usr/local/bin/ddcctl -d 1 -i 27"
else
do shell script "/usr/local/bin/ddcctl -d 1 -i 17"
end if
else
log "Status changed to " & kbStatus
end if
set lastStatus to kbStatus
end if
delay 1
end repeat
on isDeviceConnected(substring)
repeat with device in (current application's IOBluetoothDevice's pairedDevices() as list)
if (device's nameOrAddress as string) contains substring then
if device's isConnected then
return true
else
return false
end if
end if
end repeat
return false
end isDeviceConnected
编辑:我在不同的地方插入了很多调试日志消息。当它未能检测到重新连接时,它仍在 pairedDevices()
列表中匹配我的键盘名称,只是未连接。
我怀疑问题是您没有为某些 objC 方法添加括号,特别是:nameOrAddress()
和 isConnected()
。我要补充一点,使用空闲循环比使用无休止的重复循环要好得多。看起来像这样:
property lastStatus : true
property debug : true
property myKeyboard : "Keychron"
on idle
set kbStatus to isDeviceConnected(myKeyboard)
if kbStatus is not equal to lastStatus then
if debug is false then
if kbStatus is true then
do shell script "/usr/local/bin/ddcctl -d 1 -i 27"
else
do shell script "/usr/local/bin/ddcctl -d 1 -i 17"
end if
else
log "Status changed to " & kbStatus
end if
set lastStatus to kbStatus
end if
return 1
end idle
但是把所有这些放在一边,因为我认为最好的解决方案是使用 IOBluetoothDevice 方法来注册观察者。这样你的应用程序将在后台安静地休眠,直到它收到设备已连接或断开连接的通知。将以下脚本复制到脚本编辑器中:
use AppleScript version "2.4" -- Yosemite 10.10 or later
use framework "IOBluetooth"
use scripting additions
property IOBluetoothDevice : class "IOBluetoothDevice"
property myKeyboard : "Keychron"
property connectionNotifObj : missing value
property disconnectionNotifObj : missing value
on run
try
set connectionNotifObj to IOBluetoothDevice's registerForConnectNotifications:me selector:"didConnectNotif:forDevice:"
on error errstr
display dialog errstr
end try
end run
on quit
try
connectionNotifObj's unregister()
end try
set connectionNotifObj to missing value
continue quit
end quit
on didConnectNotif:notif forDevice:dev
if (dev's nameOrAddress() as text) contains myKeyboard then
set disconnectionNotifObj to (dev's registerForDisconnectNotification:me selector:"didDisconnectNotif:forDevice:")
end if
end didConnectNotif:forDevice:
on didDisconnectNotif:notif forDevice:dev
if (dev's nameOrAddress() as string) contains myKeyboard then
try
disconnectionNotifObj's unregister()
end try
set disconnectionNotifObj to missing value
end if
end didDisconnectNotif:forDevice:
将脚本另存为应用程序——确保点击 stay open after run handler
复选框,这样脚本应用程序就不会自动退出——这样你就可以开始了。
如果您希望脚本应用对 Dock 和 App Picker 不可见,运行 在终端中执行以下命令:
defaults write '/path/to/$name.app/Contents/Info.plist' LSUIElement -bool yes
当然,这让手动退出有点让人头疼(你必须使用终端或 Activity 监视器才能看到它 运行ning),但它在视觉上更令人愉悦.
基于 IOBluetooth
框架来检测我的键盘 disconnect/reconnect,因此将其切换到第二个主机会触发将显示输入更改为该主机嗯
当我在脚本编辑器中运行它时,它会在我来回切换时检测连接和断开状态。当我将它导出为应用程序(仅 运行-only)和 运行 时,它开始检测正确的状态。然而,一旦键盘断开并稍后重新连接,它就再也检测不到连接状态。
如果重要的话,我在 2019 MacBook Pro 上使用 Catalina (10.15.7)。
use framework "IOBluetooth"
use scripting additions
property lastStatus : true
set debug to true
set myKeyboard to "Keychron"
repeat
set kbStatus to isDeviceConnected(myKeyboard)
if kbStatus is not equal to lastStatus then
if debug is false then
if kbStatus is true then
do shell script "/usr/local/bin/ddcctl -d 1 -i 27"
else
do shell script "/usr/local/bin/ddcctl -d 1 -i 17"
end if
else
log "Status changed to " & kbStatus
end if
set lastStatus to kbStatus
end if
delay 1
end repeat
on isDeviceConnected(substring)
repeat with device in (current application's IOBluetoothDevice's pairedDevices() as list)
if (device's nameOrAddress as string) contains substring then
if device's isConnected then
return true
else
return false
end if
end if
end repeat
return false
end isDeviceConnected
编辑:我在不同的地方插入了很多调试日志消息。当它未能检测到重新连接时,它仍在 pairedDevices()
列表中匹配我的键盘名称,只是未连接。
我怀疑问题是您没有为某些 objC 方法添加括号,特别是:nameOrAddress()
和 isConnected()
。我要补充一点,使用空闲循环比使用无休止的重复循环要好得多。看起来像这样:
property lastStatus : true
property debug : true
property myKeyboard : "Keychron"
on idle
set kbStatus to isDeviceConnected(myKeyboard)
if kbStatus is not equal to lastStatus then
if debug is false then
if kbStatus is true then
do shell script "/usr/local/bin/ddcctl -d 1 -i 27"
else
do shell script "/usr/local/bin/ddcctl -d 1 -i 17"
end if
else
log "Status changed to " & kbStatus
end if
set lastStatus to kbStatus
end if
return 1
end idle
但是把所有这些放在一边,因为我认为最好的解决方案是使用 IOBluetoothDevice 方法来注册观察者。这样你的应用程序将在后台安静地休眠,直到它收到设备已连接或断开连接的通知。将以下脚本复制到脚本编辑器中:
use AppleScript version "2.4" -- Yosemite 10.10 or later
use framework "IOBluetooth"
use scripting additions
property IOBluetoothDevice : class "IOBluetoothDevice"
property myKeyboard : "Keychron"
property connectionNotifObj : missing value
property disconnectionNotifObj : missing value
on run
try
set connectionNotifObj to IOBluetoothDevice's registerForConnectNotifications:me selector:"didConnectNotif:forDevice:"
on error errstr
display dialog errstr
end try
end run
on quit
try
connectionNotifObj's unregister()
end try
set connectionNotifObj to missing value
continue quit
end quit
on didConnectNotif:notif forDevice:dev
if (dev's nameOrAddress() as text) contains myKeyboard then
set disconnectionNotifObj to (dev's registerForDisconnectNotification:me selector:"didDisconnectNotif:forDevice:")
end if
end didConnectNotif:forDevice:
on didDisconnectNotif:notif forDevice:dev
if (dev's nameOrAddress() as string) contains myKeyboard then
try
disconnectionNotifObj's unregister()
end try
set disconnectionNotifObj to missing value
end if
end didDisconnectNotif:forDevice:
将脚本另存为应用程序——确保点击 stay open after run handler
复选框,这样脚本应用程序就不会自动退出——这样你就可以开始了。
如果您希望脚本应用对 Dock 和 App Picker 不可见,运行 在终端中执行以下命令:
defaults write '/path/to/$name.app/Contents/Info.plist' LSUIElement -bool yes
当然,这让手动退出有点让人头疼(你必须使用终端或 Activity 监视器才能看到它 运行ning),但它在视觉上更令人愉悦.