Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
AppleScript IOBluetooth问题,但仅当导出为应用程序时_Bluetooth_Applescript - Fatal编程技术网

AppleScript IOBluetooth问题,但仅当导出为应用程序时

AppleScript IOBluetooth问题,但仅当导出为应用程序时,bluetooth,applescript,Bluetooth,Applescript,基于此,我正在使用IOBluetooth框架检测键盘的断开/重新连接,这样,将键盘切换到另一台主机也会触发更改该主机的显示输入 当我在脚本编辑器中运行它时,它会在我来回切换时检测连接和断开状态。当我将它导出为应用程序(仅限Run)并运行它时,它开始检测正确的状态。但是,一旦键盘断开连接并随后重新连接,它将不会再次检测到连接状态 如果有关系的话,我将在2019年的MacBookPro上使用Catalina(10.15.7) use framework "IOBluetooth"

基于此,我正在使用
IOBluetooth
框架检测键盘的断开/重新连接,这样,将键盘切换到另一台主机也会触发更改该主机的显示输入

当我在脚本编辑器中运行它时,它会在我来回切换时检测连接和断开状态。当我将它导出为应用程序(仅限Run)并运行它时,它开始检测正确的状态。但是,一旦键盘断开连接并随后重新连接,它将不会再次检测到连接状态

如果有关系的话,我将在2019年的MacBookPro上使用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方法中添加括号,特别是:
nameoradress()
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:
将脚本另存为应用程序-确保单击“运行后保持打开”处理程序复选框,以便脚本应用程序不会自动退出-您应该可以开始了

如果希望脚本应用程序对Dock和应用程序选取器不可见,请在终端中运行以下命令:

defaults write '/path/to/$name.app/Contents/Info.plist' LSUIElement -bool yes

当然,这让手动退出更令人头痛(你必须使用终端或活动监视器才能看到它运行),但它在视觉上更令人愉悦。

在我给出明确答案之前,有几个问题/问题。首先,如果您使用的是保持开放的applescript应用程序,那么您应该使用空闲处理程序,而不是无休止的重复循环。它更高效,并且使应用程序更容易使用。其次,您不应该在
nameoradress()
isConnected()上使用空参数吗?这可能就是失败的原因。但是,请看我的下一条评论……IOBluetoothDevice类具有设置通知的显式方法-
+RegisterForConnectionNotifications:selector:
-registerForDisconnectNotification:selector:
。当您可以要求系统通知您连接/断开连接时,为什么会出现轮询问题?让我知道你想用哪种方式来处理这个问题,我会修改脚本。我会尝试一下所有这些,因为即使我采用了不同的方法,我也想知道为什么会出现这种情况。我同意你的解决方案更优雅,只是我对AppleScript不够熟悉,不知道它。尽管如此,我仍然不明白为什么它只是作为一个应用程序而不是从脚本编辑器中运行|@cfiske:我记得,AppleScript应用程序中的属性从来都不是可靠的持久性的(尽管我做了一些测试,似乎他们已经解决了一些问题;至少,我似乎不能产生以前的问题)。如果我必须在AppleScriptObjC中保留一个持久性属性,那么我已经养成了使用NSUserDefaults创建标准属性列表的习惯。但是让我更彻底地测试一下您的脚本,看看是否可以复制这个问题。@cfiske:好的,这个问题与使用无止境的重复循环有关。我测试了很多东西,但问题并没有消失,直到我将脚本转换为在空闲时使用
处理程序。不要问我为什么会这样;我不知道,但要注意的是AppleScript不是线程化的,因此使用无休止的重复循环显然会阻止系统更新属性或查询蓝牙。无论出于何种原因,我根本无法让空闲循环方法工作,但经过一些调整,您的观察者方法工作起来非常有魅力。(编辑:我未能在粘贴中包含最上面的几行,因此出现了一些错误,现已解决)感谢您的帮助和信息@真的吗?如果您有第一个属性语句-
property IOBluetoothDevice:class“IOBluetoothDevice”
,则不应该是这种情况。但只要它起作用。。。