Message without focus

Technical support and scripting issues

Moderators: Dorian (MJT support), JRL

Post Reply
ccris
Newbie
Posts: 19
Joined: Fri Aug 27, 2010 1:53 pm

Message without focus

Post by ccris » Fri Mar 02, 2012 12:08 am

If this was already covered, I apologize. I ran a search and could not find it.
Would it be possible to have a small Message> box (or another similar small window) that I can place ON TOP (will not be covered by other windows), in an unused (or seldomly used) portion of the screen, that will update WITHOUT setting the focus on itself?

I want Mac Sched to monitor certain processes in the background and give me update messages, but without stealing the focus (so I can keep on typing, or doing whatever on the computer).

Thanks,
CC

P.S. A quick note of "thanks" to jpuziano for answer to my previous inquiry about how to deal with"multiple instances of the same program". Using the example provided, I have built an awesome macro that does exactly what I needed.

User avatar
JRL
Automation Wizard
Posts: 3518
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Fri Mar 02, 2012 7:02 am

Here's a sample that displays the cursor position

Code: Select all

OnEvent>key_down,VK27,0,Quit

Dialog>Dialog1
object Dialog1: TForm
  AutoSize = True
  BorderIcons = []
  FormStyle = fsStayOnTop
  Caption = '       Message'
  object Label1: TLabel
    Caption = 'Label1'
  end
end
EndDialog>Dialog1

Show>Dialog1

Label>Loop
  Wait>0.01
  Let>WIN_USEHANDLE=1
    GetWindowPos>Dialog1.handle,winX,winY
    MoveWindow>Dialog1.handle,winX,winY
  Let>WIN_USEHANDLE=0
  GetCursorPos>CurX,CurY
  SetDialogProperty>Dialog1,label1,caption,X Pos = %CurX%%crlf%Y Pos = %CurY%
Goto>Loop

SRT>Quit
  Exit>0
END>Quit

ccris
Newbie
Posts: 19
Joined: Fri Aug 27, 2010 1:53 pm

Post by ccris » Fri Mar 02, 2012 2:31 pm

Thanks JRL!

I went over sample line by line and understand how it works. It does EXACTLY what I have been looking for!

Thanks a bunch!

CC

ccris
Newbie
Posts: 19
Joined: Fri Aug 27, 2010 1:53 pm

Post by ccris » Sat Mar 03, 2012 9:29 pm

Coming back to this topic:
Although I understand the example provided, which works in a very fast 0.01 sec. loop that keeps dieplaying the dialog, I am not able to understand what exactly makes the dialog to persist On Top.
In my application, Mas Sch is performing a complex script, that involves looking for files, windows, waiting for data to appear, files to appear, images, a variety of stuff.
As long as I keep the fast loop going, yes, the dialog is On Top and I can type and keep the focus.
I figured I would put the info I need to see as text in the "Caption" using SetDialogProperty>
Then Mac Sch execution moves to another part of the program. The dialog no longer stays On Top (it disappears, covered by the other windows that get focus). When I need somthing else displayed, I do again Show> with new text in SetDialogProperty>. The dialog reappears, but does not stay On Top (as I focus on other windows, it gets covered). If I put the SetDialogProperty> in a loop for a while the dialog SOMETIMES becomes persistent On Top, and SOMETIMES gets covered by active window.
The end result is a constantly flashing on and off dialog.
I have not been able to figure out what exactly makes the dialog persist On Top. "FormStyle = fsStayOnTop" is on, but I can not see it doing anything. I know that WIN_USEHANDLE=1 + GetWindowPos> + MoveWindow> does something, but one execution does not seem to be enough to make the dialog persist On Top. Looping for a while seems to do that. But for how long? And why sometimes looping will bring dialog persistent On Top, but other times exactly the same loop will not. And I can not keep MacSch looping for dialog display as it needs to do other stuff.

I was looking for something like MSG_STAYONTOP=1, a persistent window that is always On Top and never gets covered, BUT that does NOT grab focus every time new info is being displayed (when Message> is called). Kind of like the Windows Task Manager: constantly refreshed, always On Top, but never grabbing focus.

Sorry if, because my inexperience, I am overlooking something very obvious.

CC

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Sun Mar 04, 2012 2:15 am

Hi ccris,
ccris wrote:P.S. A quick note of "thanks" to jpuziano for answer to my previous inquiry about how to deal with"multiple instances of the same program". Using the example provided, I have built an awesome macro that does exactly what I needed.
Again... you're welcome. While I don't help posters near as often as say JRL does (just compare the difference in reputation points earned so far)... I do like to jump in now and then.

Here's a big thank you going out to all posters who help out by answering questions here... I've learned a lot just by following the forums and you all make this a great place to visit... much appreciated.

JRL's code here is interesting. I recall him posting a trick before and thought the following line was what was making the dialog stay on top:

MoveWindow>Dialog1.handle,winX,winY

But commenting out that line, the dialog still stayed on top. I then commented out the following line as well and...

SetDialogProperty>Dialog1,label1,caption,X Pos = %CurX%%crlf%Y Pos = %CurY%

...yup, it still stayed on top. So I put the above two lines back in and changed the wait line to the following...

Wait>3.01

...to give me a bit more time in between to see how it reacts... then compiled it and ran it without MS itself running.

Even compiled, it stays on top... until you hit Windows Key + D... then it remains hidden and the stay-on-top behavior will not return... until you setfocus back to it by either clicking on its taskbar button in the taskbar at the bottom of the desktop or... by hitting ALT + TAB to set focus back to it. From then on, it will again stay-on-top.

I note that adding the following line (there are 7 spaces in the line below)...

Code: Select all

SetFocus>       Message
...somewhere inside the loop (but not between the WIN_USEHANDLE lines) will get it to stay-on-top even after you have hit Windows Key + D however it will now steal "keyboard" focus making it impossible to interact with other windows so this isn't really an option here.

I'm curious what JRL or anyone might come up with to get past the Windows Key + D problem... but in the meantime... ccris, if you have MS v13, open up the Help File and read up on AddTrayIcon>.

You can define a systray icon and when you move your mouse over that systray icon, you'll see the tooltip text which can be anything you want.

Originally, there was no way to change it... I requested an enhancement and now Marcus has added ModTrayIcon>. That will let you modify the tooltip text at any time so you could continually update it to say anything you'd like to display about the "current status" of your script... for example...

10% done, 0 errors encountered
20% done, 1 error encountered
75% done, 3 errors encountered

It does not take up any space on your desktop so you have no stay-on-top or focus stealing issues to deal with. Yes you have to mouse over that systray icon to see the tooltip but if that's no problem then this could work for you.

Take care
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

ccris
Newbie
Posts: 19
Joined: Fri Aug 27, 2010 1:53 pm

Post by ccris » Sun Mar 04, 2012 11:53 pm

Eureka!

I figured out how to do what I want.
The reason for not being able to have the dialogs persist On Top is because of all the "stuff" the script has to do. I think every time I do a Focus operation, the dialog is covered. The macro is too complex to keep watching for when the dialog will dissappear.

The solution:
Instead of displaying in main script, I leave the main script to do all the complicated stuff. I write the messages I want displayed to display.INI file. I have a separate script "Display" do nothing but loop and read the display.INI and show the dialog. The dialog stays On Top forever and never steals the focus. I compiled both scripts so they will have a "program name". When I start the main script, it runs the "Display" script hidden. The Display script watches for the name of the main script and keeps running in the background as long as the main script is running.

The main script does the job, the Display script provides the display function. When main script terminates, using some VB, the Display script "kills" itself. So I have both scripts run/terminate with one click.

Thanks to all for suggestions.

CC

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Mon Mar 05, 2012 5:15 am

ccris wrote:The solution:
Instead of displaying in main script, I leave the main script to do all the complicated stuff. I write the messages I want displayed to display.INI file. I have a separate script "Display" do nothing but loop and read the display.INI and show the dialog. The dialog stays On Top forever and never steals the focus. I compiled both scripts so they will have a "program name". When I start the main script, it runs the "Display" script hidden. The Display script watches for the name of the main script and keeps running in the background as long as the main script is running.

The main script does the job, the Display script provides the display function. When main script terminates, using some VB, the Display script "kills" itself. So I have both scripts run/terminate with one click.
Well done ccris, two scripts frees up the display script to keep in its tight loop... however hitting Windows Key + D (a keyboard shortcut used to minimize all windows so you can see your desktop)... still hides your display dialog i.e. stay-on-top is still defeated... yes? If not, please post your code.

Of course, if you never use Windows Key + D then this is fine... but can anyone come up with a way to make this display dialog stay-on-top... even after hitting Windows Key + D ?
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

ccris
Newbie
Posts: 19
Joined: Fri Aug 27, 2010 1:53 pm

Post by ccris » Mon Mar 05, 2012 12:54 pm

Hi jpuziano,

Happy to report that the display dialog stays-on-top... even after hitting Windows Key + D

THIS IS THE DISPLAY SCRIPT

Code: Select all

rem Provides persistent display

//Esc=VK27
OnEvent>KEY_DOWN,VK27,8,quit

rem Name of the main program this is providing display for
Let>proc_to_monitor=MAIN_PROGRAM.exe

rem Enter your path to message_display.ini
Let>message_ini_path=%ENTER PATH HERE%message_display.ini
Let>null=
GetScreenRes>Width_Reso,Height_Reso

rem ***********************************************************************************
rem Prepare VB functions
VBSTART
'returns the number of copies of ProcessName that are running
'will return 0 if ProcessName is not running
Function IsProcessRunning(ProcessName)
    Set oWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
	Set colProcessList = oWMIService.ExecQuery ("Select Name from Win32_Process where Name='" & ProcessName & "'")
	IsProcessRunning = colProcessList.count
End Function
VBEND
rem ***********************************************************************************

rem ***********************************************************************************
rem Create dialog. One line (label), AutoSize, fsStayOnTop
rem Message On Top (bottom right)
Dialog>dialog_message_ontop_bottom_right
object dialog_message_ontop_bottom_right: TForm
  AutoSize = True
  BorderIcons = []
  FormStyle = fsStayOnTop
  OnTaskBar = True
  Caption = '       Message'
  object Label1: TLabel
    Caption = 'Label1'
  end
end
EndDialog>dialog_message_ontop_bottom_right
rem ***********************************************************************************

rem Execute this as a SRT
GoSub>dialog_message_display
rem It should run endless.  If not, end.
Goto>end

rem ***********************************************************
rem BEGIN Dialog Message Display
SRT>dialog_message_display
Let>dialog_message_display_bottom_right_left=Width_Reso-275
Let>dialog_message_display_bottom_right_top=Height_Reso-100
Show>dialog_message_ontop_bottom_right
Let>WIN_USEHANDLE=1
MoveWindow>dialog_message_ontop_bottom_right.handle,dialog_message_display_bottom_right_left,dialog_message_display_bottom_right_top
Let>WIN_USEHANDLE=0

rem Infinite loop
Let>k=0
Label>loop_refresh

rem To reduce number of reads, read ini file only when counter is at 0 (once every 50 cycles)
If>k=0

rem Create message to display
Gosub>create_message_to_display

rem See if your MAIN_PROGRAM.exe is still running.
rem If it is no longer running, kill this_process.
GoSub>test_to_kill

EndIf

rem If text in z_message_text_1 is null, close dialog box
If>z_message_text_1=null
    CloseDialog>dialog_message_ontop_bottom_right
    Let>showing=NO
Else
    If>showing=NO
        Show>dialog_message_ontop_bottom_right
        Let>showing=YES
    Else
    EndIf
EndIf
Label>after_read_file
  Let>WIN_USEHANDLE=1
    GetWindowPos>dialog_message_ontop_bottom_right.handle,dialog_message_display_bottom_right_left,dialog_message_display_bottom_right_top
    MoveWindow>dialog_message_ontop_bottom_right.handle,dialog_message_display_bottom_right_left,dialog_message_display_bottom_right_top
  Let>WIN_USEHANDLE=0
  Let>message_to_display=%z_message_text%
  SetDialogProperty>dialog_message_ontop_bottom_right,label1,caption,%message_to_display%

rem 0.01 sec is your refresh rate
Wait>0.01
Let>k=k+1
rem 50 is number of cycles between read ini file operations (in this case, 0.5 sec)
If>k>50
    Let>k=0
EndIf
Goto>loop_refresh
END>dialog_message_display
rem END Dialog Message Display
rem ***********************************************************

rem ***********************************************************
rem BEGIN Create message to display
SRT>create_message_to_display
rem Make sure variables are clean before reading into them
Let>z_message_text_1=null
Let>z_message_text_2=null
Let>z_message_text_3=null
rem Read the 3 parts
ReadiniFile>%message_ini_path%,message_section,message_text_1,z_message_text_1
ReadiniFile>%message_ini_path%,message_section,message_text_2,z_message_text_2
ReadiniFile>%message_ini_path%,message_section,message_text_3,z_message_text_3

rem Combine the 3 parts in one z_message_text and separate lines with %CRLF%
Let>z_message_text=null
ConCat>z_message_text,z_message_text_1
If>z_message_text_2<>null
    ConCat>z_message_text,%CRLF%
    ConCat>z_message_text,z_message_text_2
Else
    Goto>done_combining
EndIf

If>z_message_text_3<>null
    ConCat>z_message_text,%CRLF%
    ConCat>z_message_text,z_message_text_3
Else
    Goto>done_combining
EndIf
Label>done_combining
END>create_message_to_display
rem END Create message to display
rem ***********************************************************

rem ***********************************************************
rem BEGIN Terminate
rem If pushing Window+Esc, terminate this display program
SRT>exit
  CloseDialog>dialog_message_ontop_bottom_right
  Exit>0
END>exit
rem END Terminate
rem ***********************************************************


rem ***********************************************************
rem BEGIN Test and kill
rem If your MAIN_PROGRAM.exe is not running, kill this
SRT>test_to_kill
VBEval>IsProcessRunning("%proc_to_monitor%"),eval_result
    If>eval_result=0
      rem If you are here, your MAIN_PROGRAM.exe is not running.  Kill this program
      Exit
    Endif
END>test_to_kill
rem END Test and kill
rem ***********************************************************

SRT>quit
  Exit>0
END>quit


Label>end
As to the MAIN_PROGRAM script, I have a SRT>dialog_message_display that takes in 3 variables (for 3 lines of text display) and writes them to your message_ini_path.
Every time you want to display something, do something like:
GoSub>dialog_message_display,My message line 1,My message line 2, My message line 3
(of course, do not use = or , or anything that will confuse read/write on an INI file)

Here is my SRT>dialog_message_display

Code: Select all

rem ***********************************************************
rem BEGIN Dialog Message Display
SRT>dialog_message_display
rem Receiving dialog_message_display_Var_1, dialog_message_display_Var_2, dialog_message_display_Var_3

Let>data_1=dialog_message_display_Var_1
Let>data_2=dialog_message_display_Var_2
Let>data_3=dialog_message_display_Var_3

EditiniFile>%message_ini_path%,message_section,message_text_1,null
EditiniFile>%message_ini_path%,message_section,message_text_2,null
EditiniFile>%message_ini_path%,message_section,message_text_3,null

Label>after_divide_parts
EditiniFile>%message_ini_path%,message_section,message_text_1,dialog_message_display_Var_1
If>data_2<>literal_2
EditiniFile>%message_ini_path%,message_section,message_text_2,dialog_message_display_Var_2
EndIf
If>data_3<>literal_3
EditiniFile>%message_ini_path%,message_section,message_text_3,dialog_message_display_Var_3
EndIf

Let>dialog_message_display_Var_1=null
Let>dialog_message_display_Var_2=null
Let>dialog_message_display_Var_3=null

END>dialog_message_display
rem END Dialog Message Display
rem ***********************************************************
This was made for a very small Auto Size box, with 3 lines of data, but you can make it bigger, fixed size, more data, etc.

I'm glad I got this figured out!

CC

ccris
Newbie
Posts: 19
Joined: Fri Aug 27, 2010 1:53 pm

Post by ccris » Mon Mar 05, 2012 1:06 pm

I forgot a bit that is outside SRT>dialog_message_display

If my SRT call has only 1 or 2 lines, like
GoSub>dialog_message_display,My message line 1
the SRT will get confused and see a non-existent Var_2 like:
"dialog_message_display_Var_2"

So at the beginning I store the literal name like:

Code: Select all

Let>literal_1=dialog_message_display_Var_1
Let>literal_2=dialog_message_display_Var_2
Let>literal_3=dialog_message_display_Var_3
and in the SRT
I assign

Code: Select all

Let>data_1=dialog_message_display_Var_1
Let>data_2=dialog_message_display_Var_2
Let>data_3=dialog_message_display_Var_3
and only write lines 2 and 3 in INI if there is real data in there:

Code: Select all

If>data_2<>literal_2
EditiniFile>%message_ini_path%,message_section,message_text_2,dialog_message_display_Var_2

Post Reply
Sign up to our newsletter for free automation tips, tricks & discounts