The following sends the individual keystrokes: Shift, Hash, Tab, Space.
Code:
send {Shift}{#}{Tab}{Space}
Modifiers should be prepended to the {keyname}, and not surrounded by braces.
Code:
Send +#{Tab}{Space}
Then there is another issue: #{Tab} always begins at the second task button. I use the following function to switch tasks:
Code:
;~ Example code
Loop 2 {
TaskSwitchDelta(-1)
Sleep, 1000
}
Loop 2 {
TaskSwitchDelta(+1)
Sleep, 1000
}
;~ End example code
TaskSwitchDelta(delta, wrap=true)
{
delta := round(delta)
if !delta
return
idxTB := GetTaskSwBar()
ControlGet, hwndTB, Hwnd,, ToolbarWindow32%idxTB%, ahk_class Shell_TrayWnd
if !WinExist("ahk_id " hwndTB)
return
WinGet, pidTaskbar, PID
hProc := DllCall("OpenProcess", "uint", 0x38, "int", 0, "uint", pidTaskbar)
pRB := DllCall("VirtualAllocEx", "uint", hProc, "uint", 0, "uint", 20, "uint", 0x1000, "uint", 0x4)
VarSetCapacity(btn, 20)
SendMessage, 0x418 ; TB_BUTTONCOUNT
count := ErrorLevel
Loop, %count%
{
SendMessage, 0x417, A_Index - 1, pRB ; TB_GETBUTTON
DllCall("ReadProcessMemory", "uint", hProc, "uint", pRB, "uint", &btn, "uint", 20, "uint", 0)
DllCall("ReadProcessMemory", "uint", hProc, "uint", NumGet(btn, 12), "uint*", hwnd, "uint", 4, "uint", 0)
btn%A_Index%_hwnd := hwnd
btn%A_Index%_idn := NumGet(btn, 4, "int")
btn%A_Index%_state := NumGet(btn, 8, "UChar")
}
; Find the active window's button.
Loop, %count%
if ((hwnd := btn%A_Index%_hwnd) && WinActive("ahk_id " hwnd))
{
i := A_Index
break
}
; If the active window has no directly associated button,
; use the first or last button which appears to be active.
if (!i)
{
i = 1
Loop, %count%
{
if (btn%A_Index%_state & 1) ; TBSTATE_CHECKED
{
i := A_Index
if (delta<0)
break
}
}
}
dir := (delta<0) ? -1 : +1
; In the unlikely event that no buttons have an associated hwnd,
Loop % (count>abs(delta) ? count : abs(delta)) ; this prevents infinite loop.
{
if (Abs(delta)<1)
break
i += dir
if (i<1 or i>count) {
i := (i<1 = wrap) ? count : 1
if !wrap
break
}
if (btn%i%_hwnd)
delta -= dir
}
if !(btn%i%_state & 8) ; ! TBSTATE_HIDDEN (if hidden, can't be clicked)
{
SendMessage, 0x433, % btn%i%_idn, pRB,, ahk_id %hwndTB% ; TB_GETRECT
got_rect := ErrorLevel && ErrorLevel != "FAIL"
if got_rect
DllCall("ReadProcessMemory", "uint", hProc, "uint", pRB, "uint", &btn, "uint", 16, "uint", 0)
}
DllCall("VirtualFreeEx", "uint", hProc, "uint", pRB, "uint", 0, "uint", 0x8000)
DllCall("CloseHandle", "uint", hProc)
; Clicking the button is generally more reliable, but is not possible for
; hidden buttons (i.e. buttons which have been grouped.)
; WinActivate often causes flashing button syndrome.
if (got_rect)
{
ControlClick, % "x" NumGet(btn,0,"int") " y" NumGet(btn,4,"int"), ahk_id %hwndTB%
}
else
{
WinActivate, % "ahk_id " btn%i%_hwnd
; Cure flashing button syndrome.
Loop, %count%
{
if (hwnd := btn%A_Index%_hwnd)
{ ; Stop flashing any flashing windows/buttons.
VarSetCapacity(fwi, 20, 0)
NumPut(20, fwi, 0)
NumPut(hwnd, fwi, 4)
DllCall("FlashWindowEx", "uint", &fwi)
}
}
}
}
GetTaskSwBar()
{
WinGet, ControlList, ControlList, ahk_class Shell_TrayWnd
RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)
Loop, %nTB%
{
ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
hParent := DllCall("GetParent", "uint", hWnd)
WinGetClass, sClass, ahk_id %hParent%
If (sClass <> "MSTaskSwWClass")
Continue
idxTB := A_Index
Break
}
Return idxTB
}