DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post your working scripts, libraries and tools for AHK v1.1 and older
XMCQCX
Posts: 228
Joined: 14 Oct 2020, 23:44

DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by XMCQCX » 28 Sep 2022, 17:34

DeviceIDPnP
Run scripts/programs when a specific device is connected/disconnected to your PC.

How to use:
-Run "DeviceIDFinder.ahk" to identify your device.
-Add your devices IDs and devices names at the top of the script. (DeviceIDPnP.ahk) The device's name doesn't have to exactly match the name found with "DeviceIDFinder.ahk". You can name it whatever you want.
-Add the devices names and the scripts/programs that you want to run/close when the devices are connecting/disconnecting.

DeviceIDFinder
Find your device's unique IDs.

How to use:
-Run the program and follow the instructions.

Get the latest version on GitHub.
https://github.com/XMCQCX/DeviceIDPnP

Code: Select all

/*
Script:     DeviceIDFinder.ahk
Author:    XMCQCX
Date:       2022-09-24
Version:   1.0.0
*/

#NoEnv
#SingleInstance, Force
SendMode Input
SetWorkingDir, %A_ScriptDir%

MsgBox, 64, Find deviceID, Plug your device and press OK

;=============================================================================================

; List all devices connected
For Device in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_PnPEntity")
    ListConnectedDeviceIDs .= device.name ":" A_Tab Device.DeviceID "`n"

;=============================================================================================

; Remove duplicates from ListConnectedDeviceIDs
Loop, Parse, ListConnectedDeviceIDs, "`n"
{
    ListConnectedDeviceIDs := (A_Index=1 ? A_LoopField : ListConnectedDeviceIDs . (InStr("`n" ListConnectedDeviceIDs
    . "`n", "`n" A_LoopField "`n") ? "" : "`n" A_LoopField ) )
}

;=============================================================================================

; Add all devices connected in oConnectedDeviceIDs
oConnectedDeviceIDs := {}
Loop, Parse, ListConnectedDeviceIDs, "`n"
    oConnectedDeviceIDs.Push({"DeviceID":A_Loopfield})

;=============================================================================================

MsgBox, 64, Find deviceID, Unplug your device and press OK

;=============================================================================================

; List all devices connected
For Device in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_PnPEntity")
    strListConnectedDeviceIDs .= device.name ":" A_Tab Device.DeviceID "`n"

;=============================================================================================

; Remove duplicates from strListConnectedDeviceIDs
Loop, Parse, strListConnectedDeviceIDs, "`n"
{
    strListConnectedDeviceIDs := (A_Index=1 ? A_LoopField : strListConnectedDeviceIDs . (InStr("`n" strListConnectedDeviceIDs
    . "`n", "`n" A_LoopField "`n") ? "" : "`n" A_LoopField ) )
}

;=============================================================================================

; Find the device that was connected/disconnected
Loop, Parse, strListConnectedDeviceIDs, "`n"
{
    For Index, Element in oConnectedDeviceIDs  
    {
        If InStr(strListConnectedDeviceIDs, Element.DeviceID)
            oConnectedDeviceIDs.RemoveAt(Index)
    }
}

;=============================================================================================

; List the IDs of the device
For Index, Element in oConnectedDeviceIDs
    DeviceIDFound .= Element.DeviceID "`n"

;=============================================================================================

; Format the IDs of the device
strDeviceIDFound := ""
For each, line in StrSplit(DeviceIDFound, "`n")
{
    RegExMatch(line, "`nm)^(.*?)" A_TAB "(.*)$", OutputVar)
        strDeviceIDFound .= OutputVar1 "`n" OutputVar2 "`n`n"
}
strDeviceIDFound := RTrim(strDeviceIDFound, "`n`n")

If !strDeviceIDFound
    strDeviceIDFound := "No device found !"

;=============================================================================================

Gui, New
Gui, Add, Text,, DeviceID:
Gui, Add, Edit, vTextDeviceID ReadOnly, %strDeviceIDFound%
Gui, Add, Button, w175 vCopyToClipboard gCopyToClipboard, Copy to Clipboard
Gui, Add, Button, x+10 w175 gFindAnotherDeviceID, Find ID of another device
Gui, Add, Button, x+10 w175 gExit, Exit
GuiControl, Focus, CopyToClipboard
Gui, Show
return

;=============================================================================================

CopyToClipboard:
Clipboard := strDeviceIDFound
MsgBox, 64, Success, Device ID copied to Clipboard !
return

FindAnotherDeviceID:
Reload

Exit:
GuiClose:
Exitapp

Code: Select all

/*
Script:    DeviceIDPnP.ahk
Author:   XMCQCX
Date:      2022-09-28
Version:  1.2.0
Link:       https://www.autohotkey.com/boards/viewtopic.php?f=6&t=108930

Change log:
2022-09-28 -> 1.2.0 - Fixed an issue when connecting/disconnecting multiple devices at the same time or in quick succession.
2022-09-27 -> 1.1.1 - Fixed an issue with some devices status not properly updating when connecting/disconnecting.
2022-09-24 -> 1.1.0 - Added run or close scripts/programs if the devices are connected/disconnected when the script start.
*/

#NoEnv
#SingleInstance, Force
SendMode Input
SetWorkingDir, %A_ScriptDir%
CoordMode, ToolTip

;=============================================================================================

oMyDevices := {}
oMyDevices.Push({"DeviceName":"USB Kingston DataTraveler 3.0", "DeviceID":"USB\VID_0951&PID_1666\E0D55EA573DCF450E97C104C"})
oMyDevices.Push({"DeviceName":"BLUETOOTH PLAYSTATION(R)3 Controller", "DeviceID":"BTHPS3BUS\{53F88889-1AAF-4353-A047-556B69EC6DA6}&DEV&VID_054C&PID_0268&04766E9094F3\9&320AC31D&0&0"})
oMyDevices.Push({"DeviceName":"HDMI Samsung TV", "DeviceID":"SWD\MMDEVAPI\{0.0.0.00000000}.{ED3C7A62-B05B-44C6-ACD8-BCAA1E894265}"})

;=============================================================================================

DevicesActions(ThisDeviceStatusHasChanged) {

    If (ThisDeviceStatusHasChanged = "USB Kingston DataTraveler 3.0 Connected")
        If !WinExist("ahk_exe Notepad.exe")
            Run, Notepad.exe

    If (ThisDeviceStatusHasChanged = "USB Kingston DataTraveler 3.0 Disconnected")
        If WinExist("ahk_exe Notepad.exe")
            Winclose, % "ahk_exe Notepad.exe"

    ;=============================================================================================

    If (ThisDeviceStatusHasChanged = "BLUETOOTH PLAYSTATION(R)3 Controller Connected")
        If !WinExist("ahk_exe wordpad.exe")
            Run, wordpad.exe

    If (ThisDeviceStatusHasChanged = "BLUETOOTH PLAYSTATION(R)3 Controller Disconnected")
        If WinExist("ahk_exe wordpad.exe")
            Winclose, % "ahk_exe wordpad.exe"

    ;=============================================================================================

    If (ThisDeviceStatusHasChanged = "HDMI Samsung TV Connected")
        If !WinExist("ahk_exe mspaint.exe")
            Run, mspaint.exe
    
    If (ThisDeviceStatusHasChanged = "HDMI Samsung TV Disconnected")
        If WinExist("ahk_exe mspaint.exe")
            Winclose, % "ahk_exe mspaint.exe"

    ;=============================================================================================
}

; Check devices connected
oDevicesConnected := {}
For Device in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_PnPEntity")
    oDevicesConnected.Push({"DeviceName":Device.Name, "DeviceID":Device.DeviceID, "DevicePNPClass":Device.PNPClass, "DeviceStatus":Device.Status})

;=============================================================================================

; Establish the status of the devices in oMyDevices
For Index, MyDevice in oMyDevices
{
    DeviceFound := ""
    For Index, DeviceConnected in oDevicesConnected
    {
        If (MyDevice.DeviceID = DeviceConnected.DeviceID)
        {
            If (DeviceConnected.DeviceStatus = "OK"), DeviceFound := "Yes"
                MyDevice.DeviceStatus := "Connected"

            If (DeviceConnected.DeviceStatus = "Unknown"), DeviceFound := "Yes"
                MyDevice.DeviceStatus := "Disconnected"
        }
    }
    If !DeviceFound
        MyDevice.DeviceStatus := "Disconnected"
}

;=============================================================================================

; Run or close scripts/programs if the devices are connected/disconnected when the script start.
Loop % oMyDevices.Count()
{
    DeviceStatustStartup := oMyDevices[A_Index].DeviceName A_Space oMyDevices[A_Index].DeviceStatus
    DevicesActions(DeviceStatustStartup)
    DeviceStatustStartup := StrReplace(DeviceStatustStartup, "Disconnected", "Not connected")
    strTooltip .= DeviceStatustStartup "`n"
}
If strTooltip
    strTooltip := RTrim(strTooltip, "`n")
        Tooltip, % strTooltip, 0, 0
            SetTimer, RemoveToolTipDeviceStatus, -6000

;=============================================================================================

OnMessage(0x219, "WM_DEVICECHANGE") 
WM_DEVICECHANGE(wParam, lParam, msg, hwnd)
{
    SetTimer, CheckDevicesStatus , -1250
}
Return

;=============================================================================================

CheckDevicesStatus:

    ;=============================================================================================
    
    ; Check devices connected
    oDevicesConnected.Delete(1, oDevicesConnected.Length())
    For Device in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_PnPEntity")
        oDevicesConnected.Push({"DeviceName":Device.Name, "DeviceID":Device.DeviceID, "DevicePNPClass":Device.PNPClass, "DeviceStatus":Device.Status})

    ;=============================================================================================

    ; Find which devices status has changed in oMyDevices
    oMyDevicesStatusHasChanged := []
    For Index, MyDevice in oMyDevices
    {
        DeviceFound := ""
        For Index, DeviceConnected in oDevicesConnected
        {
            If (MyDevice.DeviceID = DeviceConnected.DeviceID)
                If (DeviceConnected.DeviceStatus = "OK")
                    If (MyDevice.DeviceStatus = "Disconnected"), MyDevice.DeviceStatus := "Connected", DeviceFound := "Yes"
                            oMyDevicesStatusHasChanged.Push(MyDevice.DeviceName " Connected")
                
                If (DeviceConnected.DeviceStatus = "Unknown")
                    If (MyDevice.DeviceStatus = "Connected"), MyDevice.DeviceStatus := "Disconnected", DeviceFound := "Yes"
                            oMyDevicesStatusHasChanged.Push(MyDevice.DeviceName " Disconnected")
        }
        If !DeviceFound
            If (MyDevice.DeviceStatus = "Connected"), MyDevice.DeviceStatus := "Disconnected"
                    oMyDevicesStatusHasChanged.Push(MyDevice.DeviceName " Disconnected")
    }

    ;=============================================================================================

    ; If devices in oMyDevices status has changed go to DevicesActions()
    If (oMyDevicesStatusHasChanged)
    {
        strTooltip := ""
        Loop % oMyDevicesStatusHasChanged.Count()
        {
            DevicesActions(oMyDevicesStatusHasChanged[1])
            strTooltip .= oMyDevicesStatusHasChanged[1] "`n"
            oMyDevicesStatusHasChanged.RemoveAt(1)
        }
        If strTooltip
            strTooltip := RTrim(strTooltip, "`n")
                Tooltip, % strTooltip, 0, 0
                    SetTimer, RemoveToolTipDeviceStatus, -6000
    }
    
    ;=============================================================================================

return

;=============================================================================================

RemoveToolTipDeviceStatus:
ToolTip
return

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by jNizM » 29 Sep 2022, 01:43

:thumbup:
You can do the detection with ExecNotificationQueryAsync too (example 2 viewtopic.php?f=83&t=105171)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

XMCQCX
Posts: 228
Joined: 14 Oct 2020, 23:44

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by XMCQCX » 29 Sep 2022, 14:31

jNizM wrote:
29 Sep 2022, 01:43
:thumbup:
You can do the detection with ExecNotificationQueryAsync too (example 2 viewtopic.php?f=83&t=105171)
Thanks for sharing this info and your scripts. I will definitely take a look at it.

XMCQCX
Posts: 228
Joined: 14 Oct 2020, 23:44

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by XMCQCX » 03 Oct 2022, 11:40

jNizM wrote:
29 Sep 2022, 01:43
:thumbup:
You can do the detection with ExecNotificationQueryAsync too (example 2 viewtopic.php?f=83&t=105171)
I'm trying to combine 2 of those scripts, but I'm not able to do it. The script break when trying to add a line. You can take a look here if you want to help me solve the issue.
viewtopic.php?f=76&t=109039

Gewerd_Strauss
Posts: 24
Joined: 12 Nov 2020, 02:34

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by Gewerd_Strauss » 15 Oct 2022, 11:20

Short question, I have been trying to get this to work for bluetooth devices, especially a set of bluetooth headphones so that I can autoreload a script depending on that. So far, the script does not detect said pair of headphones unfortunately. Or does connect in the sense of this script mean I must delete the pairing first?

XMCQCX
Posts: 228
Joined: 14 Oct 2020, 23:44

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by XMCQCX » 18 Oct 2022, 01:33

Gewerd_Strauss wrote: Or does connect in the sense of this script mean I must delete the pairing first?
Quote from Reddit:
Gewerd_Strauss wrote: Huh... This is weird. I did the same process before contacting you, and now it works. Weird, I must have fucked up some step or another. Not sure which one honestly, I tried this several times. Nonetheless, thank you. It works now, so yay. Now all I have to do is figure out how to completely incorporate it properly into where it is supposed to go :P

The process I did:
Device is already paired, meaning it has been previously linked to the computer and is known by name.

-Toggle bluetooth off
-Launch Script, hold on first msgbox
-Toggle bluetooth on
-Device autoconnects - audio will now be routed to the headphones as windows changes the current audio device
-Close first Messagebox in script, wait till second msgbox opens
-Toggle bluetooth off
-Close second msgbox
-inspect result
All scripts aside from my scriptlauncher are off.
Thanks for reporting this. I think I know what is the issue. When disconnected, some Bluetooth devices are still being shown as entries. Their status is changing to "unknown" instead of "ok" but they are still showing up. This was fixed in the main script with this line:

Code: Select all

If (DeviceConnected.DeviceStatus = "Unknown"), DeviceFound := "Yes"
	MyDevice.DeviceStatus := "Disconnected"
I need to include something similar in "DeviceIDFinder". I will fix it in the next update. For now, for anyone having an issue detecting some Bluetooth devices, just follow the step provide by Gewerd_Strauss above.

Gewerd_Strauss
Posts: 24
Joined: 12 Nov 2020, 02:34

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by Gewerd_Strauss » 18 Oct 2022, 04:12

Hya,

thank you for responding. I'm not sure where that code changed/where it is supposed to go, but so far it works for me.


One question that is only anecdotally connected to this:

My main usecase for this is to trigger an automatic reload in my audio-switcher-script. I need to change audio in/out anywhere from a couple times a week to several times a day, and grew sick of windows rather annoying method.

Now, The sript works wonderfully so far, and is a combination of this code here (only for reloading in case of audio device count change), as well as Flipeandor's code from viewtopic.php?p=221751#p221751 (I still cannot figure out how to properly use bbcode for formatting, sorry. Gimme markdown ;P)

I have almost everything done now. I can switch between any audio in/out windows recognises and the script reloads when devices are connected/removed.

Only issue is that I want to preselect the currently-active speaker/microphone when the script starts. However, I don't know how to
- find the currently-in-use device when starting the script, nor
- how to do so in a format that is useful (although this is arguably less relevant, once I got the information there is probably _some_ way to find out where it correlates)

The current script can be found here, if anyone's wants to take a look:
https://gist.github.com/Gewerd-Strauss/7f1ee8eabcd4ebde34f01c89ac6c834b
It's feature complete, aside from preselecting & disabling the button of the currently set devices when thes script starts up.

I know it is a long shot, but _maybe_ someone here has an idea as to how to solve it.

User avatar
mikeyww
Posts: 26848
Joined: 09 Sep 2014, 18:38

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by mikeyww » 07 Dec 2022, 06:40

Nice script, handy. There could be an easy way to modify the script so that it uses an external config file for all of the changes (device specs & actions), so as not to require changing the script itself.

rimpul
Posts: 1
Joined: 30 May 2021, 03:13

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by rimpul » 27 Jan 2023, 06:32

Great sript!
I wanted to know how I can combine multiple DevicesActions in one?
Like the example below runs the same action for two devices.

Code: Select all

If (ThisDeviceStatusHasChanged = "Logi Keyboard_1 Connected")
Run, C:\Users\trucr\Dropbox\AutoHotKey\Logi_keys.exe

If (ThisDeviceStatusHasChanged = "Logi Keyboard_1 Disconnected")
Run taskkill /f /im Logi_Keys.exe,, hide

;=============================================================================================

If (ThisDeviceStatusHasChanged = "Logi Keyboard_2 Connected")
Run, C:\Users\trucr\Dropbox\AutoHotKey\Logi_keys.exe

If (ThisDeviceStatusHasChanged = "Logi Keyboard_2 Disconnected")
Run taskkill /f /im Logi_Keys.exe,, hide

XMCQCX
Posts: 228
Joined: 14 Oct 2020, 23:44

Re: DeviceIDPnP - Run scripts/programs when a specific device is connected/disconnected to your PC

Post by XMCQCX » 01 Mar 2023, 18:09

rimpul wrote:
27 Jan 2023, 06:32
Great sript!
I wanted to know how I can combine multiple DevicesActions in one?
Like the example below runs the same action for two devices.
I've updated DeviceIDPnP to support groups of devices and added new options. Try it out if you are interested!


Post Reply

Return to “Scripts and Functions (v1)”