Assign ESCape key to hotkey

Ideas for new features & functions

Moderators: Dorian (MJT support), JRL

Post Reply
pseakins
Newbie
Posts: 8
Joined: Wed Apr 11, 2007 7:33 am
Location: Bundaberg, Australia

Assign ESCape key to hotkey

Post by pseakins » Mon Apr 16, 2007 9:56 am

I first purchased Macro Scheduler Oct 1997 for automated testing but haven't used it for years. Just upgraded as I have new needs. Have been testing with F9 and F10 hotkeys and planning several other hotkeys all of which use a method to identify the focussed app and then call appropriate macros.

Here's the killer. The MOST important need is to be able to capture the ESCape key and translate it to AltF4 or throw it away as needed. Just went to change the hotkey assignment on a test macro and I find the ESCape key isn't in the list of hotkeys! What! This is absolutely essential!

Eg, If you hit F1 in the macro editor you get contextual help. But then you hit escape to kill the help and nothing happens. Doh! There's several apps around where the escape key isn't wired into the help system. Similarly, Trillian kills the Instant Messenger window if you accidently hit escape and loses the conversation history. In this case escape needs to be suppressed.

What can I do?

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

Post by jpuziano » Mon Apr 16, 2007 4:14 pm

Hi pseakins,

I agree, I think more apps should at least give the user the option of using ESC to exit. Reaching for ALT-F4 is much slower. I thought a little macro that could be running all the time should be able to do this...

My first thought was to use WaitKeyDown> in a loop... but that won't work as it will wait forever (Note: a timeout value might be a useful addition to this command).

Then I thought to use OnEvent> (see Help for OnEvent>). Here's what I have so far:

Code: Select all

/*
=======================================================================
2007-04-16 09:55:08 Monday by jpuziano
ESC to ALT-F4 Converter

Written to test an idea - in response to this post:
Assign ESCape key to hotkey (t=3752)
=======================================================================
*/

//VK27=ESC key, 0=no modifier key
OnEvent>KEY_DOWN,VK27,0,User_Hit_Escape_Key

//Hit ALT-ESC to exit, 3=ALT key as modifier
OnEvent>KEY_DOWN,VK27,3,User_Wants_To_Exit

MDL>ESC to ALT-F4 Converter Macro now turned on%CRLF%%CRLF%Press ALT-ESC to turn this macro off

//When variable Keep_Running=0, we will Exit
Let>Keep_Running=1

Label>start
//A short wait state will make this macro more responsive
//but too short will make it hog too much CPU... adjust as desired
Wait>0.1
If>Keep_Running=0,Exit
Goto>start

SRT>User_Hit_Escape_Key
Press ALT
Press F4
Release ALT
END>User_Hit_Escape_Key

SRT>User_Wants_To_Exit
Let>Keep_Running=0
END>User_Wants_To_Exit

Label>Exit
MDL>ESC to ALT-F4 Converter Macro now turned off

It works but *beware*, it does have some quirks, for instance:
  • - get the macro above running
    - Open ten Notepad windows (don't type anything into them).
    - Tap ESC very breifly, it may or may not see the ESC key and close a Notepad window for you.
    - Tapping a little longer will help it see the ESC key (fire an event).
    - Problem is, it may fire multiple events and close down multiple notepad windows.
    - If you have changed the text in the notepad windows, multiple firings of ALT-F4 isn't going to hurt because Notepad will throw a dialog asking if you want to save changes and the next ALT-F4 will just cancel that dialog so you haven't lost anything.
    - But still... depending on which windows get focus next, trigging multiple ALT-F4's from one looong press of ESC could be a problem.
Perhaps when the event fires, in the handler (subroutine) it should first wait for ESC to be *released*? Is there a way to do that? Then any multiple "ESC" events that may have made it into the "queue" should be flushed... and only then should one ALT-F4 sequence be generated. Or maybe just a Wait> or two in the proper place is all that's needed?

A little macro to add "EXC to Exit" functionality to any windows app would sure be handy to have around... Can Marcus or any of the other macro wizards on here could devise a way to modify this macro so that a single press and release of ESC would generate only *ONE* ALT-F4 sequence?

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 - :-)

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

Post by JRL » Mon Apr 16, 2007 4:59 pm

jpuziano,

I think your script works... I think the problems you've pointed out are simple timing issues. Try this. The changes are a shorter wait in the "start" loop and added a wait in the "User_Hit_Escape_Key" subroutine. This worked for me in one trial of 10 notepad windows. If timing is the only issue the values I've inserted might not work perfectly for everyone. And holding the Esc key down still will keep firing it, just at 1 second intervals.

Code: Select all

/*
=======================================================================
2007-04-16 09:55:08 Monday by jpuziano
ESC to ALT-F4 Converter

Written to test an idea - in response to this post:
Assign ESCape key to hotkey (t=3752)
=======================================================================
*/

//VK27=ESC key, 0=no modifier key
OnEvent>KEY_DOWN,VK27,0,User_Hit_Escape_Key

//Hit ALT-ESC to exit, 3=ALT key as modifier
OnEvent>KEY_DOWN,VK27,3,User_Wants_To_Exit

MDL>ESC to ALT-F4 Converter Macro now turned on%CRLF%%CRLF%Press ALT-ESC to turn this macro off

//When variable Keep_Running=0, we will Exit
Let>Keep_Running=1

Label>start
//A short wait state will make this macro more responsive
//but too short will make it hog too much CPU... adjust as desired
Wait>0.01
If>Keep_Running=0,Exit
Goto>start

SRT>User_Hit_Escape_Key
Press ALT
Press F4
Release ALT
Wait>1
END>User_Hit_Escape_Key

SRT>User_Wants_To_Exit
Let>Keep_Running=0
END>User_Wants_To_Exit

Label>Exit
MDL>ESC to ALT-F4 Converter Macro now turned off

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

Post by jpuziano » Mon Apr 16, 2007 10:34 pm

Hi JRL,

Thanks, that did the trick. The macro is useable for me now with those Wait> statements added... but it still fires repeatedly every second so a long keypress could still cause a problem as multiple Alt-F4 sequences will be sent.

I could increase the Wait time to 2 seconds but that would just annoy users who want to close windows one after another faster than that... they might as well tap ALT-F4.

What's really needed is the ability to sense a key changing from the down state to the up state but I don't see any way to do that with existing Macro Scheduler commands.

Marcus (or anyone), is it possible to do this with Win32 API calls?

If not, would it be technically possible to add OnEvent>KeyUp :?:

Assuming such a command existed and I had the following line:
  • OnEvent>KEY_UP,VK27,0,User_Just_Released_ESC_Key
And if the ESC key (and only the ESC key) was pressed then released, would it:

a) only fire the KEY_UP event once? or...
b) fire continually once the ESC key was released?

b) would mean it triggers on the state (like KeyDown seems to do) while a) would mean its triggers on the change of state from down to up (which seems more useful here).

Any thoughts out there? Could anyone else use this capability?
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 - :-)

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

Post by JRL » Tue Apr 17, 2007 3:17 am

Try this.

A variable prevents Esc from firing more than once. The variable can't be reset until Esc has been released for some amount of time. This time is controlled by the value of another variable"EscTimerMax"

Edit- Changed the value of "EscTimerMax" from 100 to 10. 100 was way too long 10 might still be a little long.

Code: Select all

/*
=======================================================================
2007-04-16 09:55:08 Monday by jpuziano
ESC to ALT-F4 Converter

Written to test an idea - in response to this post:
Assign ESCape key to hotkey (t=3752)
=======================================================================
*/

//VK27=ESC key, 0=no modifier key
OnEvent>KEY_DOWN,VK27,0,User_Hit_Escape_Key

//Hit ALT-ESC to exit, 3=ALT key as modifier
OnEvent>KEY_DOWN,VK27,3,User_Wants_To_Exit

Message>ESC to ALT-F4 Converter Macro now turned on%CRLF%%CRLF%Press ALT-ESC to turn this macro off
Wait>2
CloseWindow>Message*
//When variable Keep_Running=0, we will Exit
Let>Keep_Running=1
//If variable EscTimeOut=0 Pressing esc will press Alt+F4
Let>EscTimeOut=0
//Variable will disallow EscTimeOut from equalling zero until a timeout has expired
Let>EscTimer=0
//Variable to adjust EscTimer timeout
Let>EscTimerMax=10

Label>start
//A short wait state will make this macro more responsive
//but too short will make it hog too much CPU... adjust as desired
Wait>0.01
If>%EscTimeOut%=1
  Add>EscTimer,1
EndIf
If>%EscTimer%>%EscTimerMax%
  Let>EscTimeOut=0
  Let>EscTimer=0
EndIf
If>Keep_Running=0,Exit
Goto>start

SRT>User_Hit_Escape_Key
If>EscTimeOut=1,SkipAltF4
Press ALT
Press F4
Release ALT
Let>EscTimeOut=1
Label>SkipAltF4
Let>EscTimer=0
END>User_Hit_Escape_Key

SRT>User_Wants_To_Exit
Let>Keep_Running=0
END>User_Wants_To_Exit

Label>Exit
Message>ESC to ALT-F4 Converter Macro now turned off
Wait>2
Last edited by JRL on Tue Apr 17, 2007 12:44 pm, edited 1 time in total.

pseakins
Newbie
Posts: 8
Joined: Wed Apr 11, 2007 7:33 am
Location: Bundaberg, Australia

Post by pseakins » Tue Apr 17, 2007 7:18 am

Fantastic. I post my problem, go to bed and when I get up it's been bandied around and a workable solution found. Thanks Guys!

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

Post by jpuziano » Tue Apr 17, 2007 5:13 pm

Hi pseakins,

No problem, glad it works for you and thanks for your enhancements JRL!

I've contributed it to the "Scripts and Tips" forum and Marcus has just posted it there... hope its useful for others as well.
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 - :-)

pseakins
Newbie
Posts: 8
Joined: Wed Apr 11, 2007 7:33 am
Location: Bundaberg, Australia

Post by pseakins » Thu Jun 21, 2007 4:26 pm

This solution is still a little quirky. Firstly, the actual escape keypress is not being read/absorbed by anything. The escape keystroke is still passed to the underlying windows system. If (say) notepad has focus then it doesn't matter (and isn't obvious) because notepad throws the escape away anyway. In my original post I explained I wanted to conditionally process the keystroke depending on which app has focus at the time. In some cases it should be ignored.

Secondly, it's rather intermitent in operation. Try this. Create a new script using the posted example and save it. Put a shortcut to the test macro on the desktop. Double click it - the intro message pops up - don't touch it, let the message time out. There will be a new flashing MS icon on the taskbar. Don't move the mouse, just simply press escape - nothing happens. Now click in a blank area anywhere on the desktop. The desktop shortcut icon to the macro gives a quick flash. Now press escape, voila! up come the windows shutdown message because the ALT-F4 has now been passed through to Windows. So, why do I need to click the desktop before the macro "activates"? The same situation will occur with the ALT-ESC release hotkey, doesn't work without desktop focus.

This is still a good basis for the solution I am working towards but I have yet to find a way to "read off" the escape keystroke in cases where having the escape reach the application would produce undesirable actions. What I am looking for is an equivalent to the old Basic Inkey$ function or C's getchar(). VBScript doesn't appear to have such a function and neither does MacroScheduler (that I can find). WaitKeyDown might work, haven't tried it yet, but seems a bit clunky as a solution.

(XPSP2 all patches)

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

Post by jpuziano » Thu Jun 21, 2007 6:31 pm

Hi pseakins,
  • Replace line 19:
    CloseWindow>Message*

    With this:
    CloseWindow>Macro Scheduler Message
That will work better but know that its possible that another window may be up that has that same exact name (quite possible if you run a lot of macros) so its possible the wrong window could be closed. To make this more foolproof, remove the notice altogether if you like or... instead just play a wav file to provide an audible indication that the "ESC to ALT-F4 Converter" macro is running.

pseakins wrote:This solution is still a little quirky. Firstly, the actual escape keypress is not being read/absorbed by anything.
I have been assuming that the following line establishes an event handler which does "absorb it completely"...
  • OnEvent>KEY_DOWN,VK27,0,User_Hit_Escape_Key
...but perhaps you are right. I would really like Marcus to jump in here and confirm or deny this (however I think he's on vacation as he hasn't posted for a while).

pseakins wrote:The escape keystroke is still passed to the underlying windows system. If (say) notepad has focus then it doesn't matter (and isn't obvious) because notepad throws the escape away anyway.
If that macro is running, and if Notepad has focus, and you press the ESC key (note I said press, not tap really breifly... you have to press it long enough to be noticed)... then that ESC press will be noticed by the event handler, and it will send ALT-F4 to Notepad and Notepad will immediately close. Are you saying that the ESC key has also been sent to Notepad but it just threw it away? How can you tell?

But you do give me cause to wonder here... because if the event handler had truly inserted itself into the stream of how characters are processed by Windows itself, it would be inspecting each and every key as it was processed by Windows (taken out of the Keyboard Buffer) and if it was the code for ESC, it would do what we've setup the event handler to do. It would not pass that ESC keystoke on at all and... IT WOULD NOT MATTER HOW FAST WE TAPPED THE ESC KEY because if we tapped it hard enough to actually register, a code for ESC would be inserted into the Keyboard Buffer and when that code was processed by Windows, it should be recognized by our event handler. Again... Marcus if you can shed some light here, it would really be appreciated.

pseakins wrote:In my original post I explained I wanted to conditionally process the keystroke depending on which app has focus at the time. In some cases it should be ignored.
OK, so go ahead and do that, modify this subroutine:
  • SRT>User_Hit_Escape_Key
    ...insert mods here...
    If>EscTimeOut=1,SkipAltF4
    Press ALT
    Press F4
    Release ALT
    Let>EscTimeOut=1
    Label>SkipAltF4
    Let>EscTimer=0
    END>User_Hit_Escape_Key
You need to immediately grab the title of the window that has focus. Then you could use one or more If statements to compare it to one or more Window title names of windows that you want to ignore. If it matches, you don't want to send an ALT-F4 so jump to the Label>SkipAltF4 line.

Try that and let us know how it goes...

pseakins wrote:Secondly, it's rather intermitent in operation. Try this. Create a new script using the posted example and save it. Put a shortcut to the test macro on the desktop. Double click it - the intro message pops up - don't touch it, let the message time out. There will be a new flashing MS icon on the taskbar. Don't move the mouse, just simply press escape - nothing happens. Now click in a blank area anywhere on the desktop. The desktop shortcut icon to the macro gives a quick flash. Now press escape, voila! up come the windows shutdown message because the ALT-F4 has now been passed through to Windows. So, why do I need to click the desktop before the macro "activates"? The same situation will occur with the ALT-ESC release hotkey, doesn't work without desktop focus.
Agreed, there is some flakyness there to do with focus. I notice that if the Macro Scheduler main window is visible and has focus, you have to hit ALT-ESC not once but twice to shut down this macro. The first ALT-ESC seems to remove focus from the Macro Schedulaer Main window and the second ALT-ESC is seen by the event handler in the macro and it shuts down.

Why isn't the very first press of ALT-ESC seen by the event handler? I'd guess because that event handler is running "within" or "as a part of" the Macro Scheduler process itself. Also, ALT-ESC may have been an unfortunate and bad choice for a keystroke combination to shut down this macro as... ALT-ESC is a Windows System Keyboard Shortcut to task switch and that may be confusing things (being processed first by Windows). Feel free to change this in the macro, change the exit event handler here...

//Hit ALT-ESC to exit, 3=ALT key as modifier
OnEvent>KEY_DOWN,VK27,3,User_Wants_To_Exit

...to watch for some other key combination, something you don't use in any other apps. Even just experiment using say F11 for example... to see if doing that makes shutting down the macro more reliable.

pseakins wrote:This is still a good basis for the solution I am working towards but I have yet to find a way to "read off" the escape keystroke in cases where having the escape reach the application would produce undesirable actions. What I am looking for is an equivalent to the old Basic Inkey$ function or C's getchar(). VBScript doesn't appear to have such a function and neither does MacroScheduler (that I can find). WaitKeyDown might work, haven't tried it yet, but seems a bit clunky as a solution.

(XPSP2 all patches)
If you compiled that macro to an exe, put a shortcut to that exe on your desktop and ran the macro by clinking that icon to run the exe... perhaps all focus-related problems would disappear. Be sure to compile it to have "No System Tray Icon" and to "Run Hidden" if that is what you are after.

Let us know your findings and 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 - :-)

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

Post by JRL » Thu Jun 21, 2007 10:18 pm

Hi Guys,

First, the esc press alt+F4 script can only be taken as an example. It may need modification to work with some applications and may not work at all with others.

Second, OnEvent> does NOT intercept a keypress. It merely detects a keypress. If you press ESC in an application that deletes data when ESC is pressed. OnEvent> will not prevent this from occurring.

What can be accomplished in some... but not all... situations is that the results of the keypress can be dealt with. As an example here is a script that will open notepad and give you a chance to type the letter "A". (Case is irrelevant.) The script detects "A" is pressed and sends the letter "B" to notepad. However, OnEvent> does not prevent "A" from being entered into notepad as well.

Code: Select all

OnEvent>KEY_DOWN,VK65,0,KeyPress

Run>notepad.exe
WaitWindowOpen>notepad*
Let>kount=0
SetFocus>notepad*
Send>You have perhaps 15 seconds to press the "A" key and watch what happens
Send>%CRLF%%CRLF%%CRLF%%CRLF%%CRLF%%SPACE%%SPACE%%SPACE%%SPACE%%SPACE%
Label>idle
add>kount,1
If>%kount%>1000,EOF
Wait>0.01
Goto>idle

Label>EOF
CloseWindow>notepad*
Wait>0.5
Send>n

SRT>KeyPress
  SetFocus>notepad*
  Send>B
  Wait>0.1
END>KeyPress
In this case if you wanted to reverse the effect of the "A" being sent to notepad you could simply add a backspace to the KeyPress subroutine and the apparent effect would be that only a "B" was sent.

Code: Select all

OnEvent>KEY_DOWN,VK65,0,KeyPress

Run>notepad.exe
WaitWindowOpen>notepad*
Let>kount=0
SetFocus>notepad*
Send>You have perhaps 15 seconds to press the "A" key and watch what happens
Send>%CRLF%%CRLF%%CRLF%%CRLF%%CRLF%%SPACE%%SPACE%%SPACE%%SPACE%%SPACE%
Label>idle
add>kount,1
If>%kount%>700,EOF
Wait>0.01
Goto>idle

Label>EOF
CloseWindow>notepad*
Wait>0.5
Send>n

SRT>KeyPress
  SetFocus>notepad*
  Press Backspace
  Send>B
  Wait>0.1
END>KeyPress



Hope this is helpful,
Dick

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

Post by jpuziano » Fri Jun 22, 2007 4:56 am

JRL wrote:Hi Guys,
Second, OnEvent> does NOT intercept a keypress. It merely detects a keypress. If you press ESC in an application that deletes data when ESC is pressed. OnEvent> will not prevent this from occurring.
Thanks for confirming that JRL... and thanks for the examples on how to "reverse the effects" of a key that we wanted to intercept.

However, I would like to know if anyone out there knows a method whereby we could actually intercept a certain key such that it absolutely does not get sent to the underlying application.

One method might be to (temporarily) modify how Windows processes keystrokes. I am assuming they are first stored in a keyboard buffer and another process takes them out of there and passes them on to be processed by Windows itself. We'd have to be able to get in between there and have that code from the keyboard buffer go first to our event handler and depending on what code it is, we could decide to pass it on to Windows as-is, pass on some other keystroke/s instead or... just throw it away completely like it never happened.

Any possibility of developing something like that Marcus? Anyone else know anything more on this?
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 - :-)

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