Remi
Remi

Reputation: 33

Batch: How to focus on cmd after task is initialized

Say my program is as follows

@ECHO Off
 start "" "Notepad.exe"
 pause

After it opens notepad the windows focus is on notepad so whatever I type is on there, but I want the focus to go back to cmd; is this possible? How?

The specific program i'm trying to run it on, is below:

@ECHO OFF
title SortV8
SETLOCAL ENABLEDELAYEDEXPANSION
cd "C:\img\Unsorted"
:SORT
FOR /R %%f IN (*.jpg *.png *.gif *.jpeg) DO (
 echo Current file is: %%f
 start "" "D:\Downloads\ImageGlass_Kobe_8.6.7.13_x64\ImageGlass.exe" %%f
 powershell.exe -NoProfile -Command "(New-Object -ComObject WScript.Shell).AppActivate((Get-CimInstance Win32_Process -Filter \"ProcessId = $PID\").ParentProcessId)"
 CHOICE /N /C 1234 /M "PICK A NUMBER (1 (Photo), 2 (Video), or 3(Delete), 4 (Terminate Program)"%1
 IF ERRORLEVEL 4 goto END
 IF ERRORLEVEL 3 echo "To the trash it goes!" && move %%f "C:\img\Delete"
 IF ERRORLEVEL 2 echo "Video" && move %%f "C:\img\Videos"
 IF ERRORLEVEL 1 echo "Photo" &&  move %%f "C:\img\Photos"
 taskkill /IM ImageGlass.exe
 cls
 GOTO SORT
)

:END
taskkill /IM ImageGlass.exe
cls
echo "Goodbye!"
pause
:eol

Upvotes: 1

Views: 1195

Answers (1)

mklement0
mklement0

Reputation: 438093

You can use PowerShell via its CLI to reactivate your console window, but note that the execution overhead is not insignificant.

Note: This solution is not fully robust, but may work well enough in practice:

@ECHO Off

:: Asynchronously launch Notepad, which steals the focus
:: (Notepad becomes the active window).
start "" "Notepad.exe"

:: Reactivate this console window with the help of PowerShell.
powershell.exe -NoProfile -Command "(New-Object -ComObject WScript.Shell).SendKeys('%%{tab}')"

pause

The above simulates user input, namely an Alt-Tab keypress, in order to reactivate the current console window. This relies on:

  • Notepad's window already having been activated (which is likely, given the execution overhead of calling powershell.exe)

  • the user not manually activating other windows while the batch file runs.


The following variant is more robust, but has a prerequisite that is unlikely to be met:

  • Rather than sending keystrokes, it properly tries to reactivate the current console window via its process ID.

  • However, this programmatic window activation only succeeds if the effective SPI_GETFOREGROUNDLOCKTIMEOUT value as reported by the SystemParametersInfo WinAPI function in the current OS uses session is 0, which is not the case by default.

    • While it is possible in principle to set this value to 0 on demand with PowerShell code (see this answer), executing such code from cmd.exe (a batch file) inexplicably fails with an Access denied error (whereas direct execution of the same code works fine from PowerShell) - I haven't found a way around this (if someone has an explanation or solution, please tell us).

    • Certain third-party software - notably AutoHotkey - itself sets the value to 0 once it has run in a session, so if you happen to have a run-on-login AutoHotkey script (it doesn't matter what it does), the code below will work. That said, if you have AutoHotkey already installed, you could try to solve the problem at hand with a specific AutoHotkey script.

@ECHO Off

:: Asynchronously launch Notepad, which steals the focus
:: (Notepad becomes the active window).
start "" "Notepad.exe"

:: !! SEE LIMITATION DISCUSSED ABOVE
:: Reactivate this console window with the help of PowerShell.
powershell.exe -NoProfile -Command "$null = (New-Object -ComObject WScript.Shell).AppActivate((Get-CimInstance Win32_Process -Filter \"ProcessId = $PID\").ParentProcessId)"

pause

Upvotes: 2

Related Questions