Window which was active when script was invoked

Started by fhammer, July 09, 2016, 02:11:30 PM

Previous topic - Next topic

fhammer

I would like to obtain the name (or id) of the user-window which was active, just-prior to invoking my script.

Simple Example Script (EnterDate.wbt):
--------------------------------------

; When invoked via Windows shortcut hot-key (e.g. Ctrl-d), ...
; ... this script sends the current date and time, to the "active" user window.

awin = ???         ; Determine application window which was active just prior to invokation of this script

SendKeysTo(awin,TimeDate())   ; Send date to user application

Exit

--------------------------------------

In this example, HOW CAN I SET VARIABLE awin?

Unfortunately, "awin = WinGetActive()" just returns "Program Manager", not the name of the previously-active window (the one I was working in, when I invoked the script). If I hard-code the window name (e.g. awin = "Untitled - Notepad"), the script works fine. The time and Date are sent to the application.
However, I would like to make the script generic, so that whatever application window I am working in (Notepad, email editor, MS Word, etc), the time and date are sent to that application window.

Thank you very much!

Note: I'm using WinBatch 2016B, installed on a Windows 10 system.

td

I may just be suffering from vapor lock but I can't think of any guaranteed-to-work method of obtaining the last foreground window.  When you press a short cut key sequence a Windows shell thread's window is going to become the foreground window replacing the existing foreground window.  You can't rely on the order of the windows returned from a call to WinItemize either.  This is particularly true of Windows 10.  You may be able to use a kluge that results from Microsoft flipping the Windows Runtime bit in the process structure of shell threads on Windows 10 even though the Window shell is not a runtime application.  It would look something like the following:
Code (winbatch) Select
lWins = WinItemize()
nCnt = ItemCount(lWins, @Tab)
for nItem = 1 to nCnt
   if !WinIsRuntimeApp(ItemExtract(nItem, lWins, @Tab))
      Message("Last Window",ItemExtract(nItem, lWins, @Tab))
      exit
   endif
next


Again, can't say that this would work reliably. 
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

fhammer

Thanks td! The following code works for me (at least on Windows 10).

#DefineFunction GetPrevWin()
; returns the name of the previously-active (foreground) application window or "" if none found

  open_wins = WinItemize()

  n = ItemCount(open_wins,@TAB)
 
  For i = 1 To n
    win = ItemExtract(i,open_wins,@TAB)
    If !WinIsRuntimeApp(win) && WinState(win) > 1 Then Break
  Next

  If i > n Then Return ""
  Return win

#EndFunction


For some reason the list returned by WinItemize(), always has the active foreground application window AHEAD of other open desktop application windows. Lucky for me.


kdmoyers

The mind is everything; What you think, you become.

td

Quote from: fhammer on July 11, 2016, 08:24:13 PM
Thanks td! The following code works for me (at least on Windows 10).

#DefineFunction GetPrevWin()
; returns the name of the previously-active (foreground) application window or "" if none found

  open_wins = WinItemize()

  n = ItemCount(open_wins,@TAB)
 
  For i = 1 To n
    win = ItemExtract(i,open_wins,@TAB)
    If !WinIsRuntimeApp(win) && WinState(win) > 1 Then Break
  Next

  If i > n Then Return ""
  Return win

#EndFunction


For some reason the list returned by WinItemize(), always has the active foreground application window AHEAD of other open desktop application windows. Lucky for me.

The 'normal' behavior for Windows before Windows 10 was to  return an enumerated windows in previous-foreground order most of the time.  As of Windows 10 all windows marked as Windows Runtime (WinRT) based are enumerated before any win32 windows regardless of previous-foreground. 

Since you are filtering out WinRT applications, you more or less are left with the old pre-Windows 10 behavior.  The downside of filtering WinRT applications is that if the last foreground window happens to be a WinRT window, the script will not detect it.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

fhammer

Update:

I updated the above GetPrevWin() function to handle duplicate window names. It now returns the window ID, as opposed to the window NAME.
I also included a change, which allows the function to work, in compiled form, on older versions on Windows.

The new version is:

#DefineFunction GetPrevWin()
; Returns the window ID of the previously-active application window or "" if none found

; Notes: 1) The WinIsRuntimeApp() function does not exist in old versions of WinBatch,
;           therefore this version of GetPrevWin() won't run with older versions
;           of the WinBatch INTERPRETER.
;    2) Scripts COMPILED with recent versions of Winbatch can call this version
;           of GetPrevWin(), however when run on older OS's, the WinIsRuntimeApp() will always return @FALSE.
;           However, the first window name returned by WinItemNameId() is always "Start", which satisfies the other selection criteria.
;           To accomodate this, the "For" loop starts with item-pair 2, which appears to work for both old & new OS's.

  open_wins = WinItemNameId()         ; name1|id1|name2|id2 ...
                                          ; Note: previously-active (foerground) window appears ahead of other active windows
  n = ItemCount(open_wins,"|")         ; number of open windows*2 (often > 100)
 
  For i = 3 To n/2 By 2            ; start w item-PAIR 2 to accomodate older OS's (e.g. Vista)
    win = ItemExtract(i+1,open_wins,"|")   ; extract ID
    If !WinIsRuntimeApp(win) && WinState(win) > 1 Then Break
  Next

  If i > n/2 Then Return ""
  Return win

#EndFunction