Question
How do I program AutoHotKey to detect the Microsoft Outlook Search field at the top of the window, so as to only enable hotkeys when outside of that window? That search field looks like this:
Details
I'm intending to add single-character hotkeys similar to what gmail has: https://support.google.com/mail/answer/6594?hl=en#zippy=%2Cactions , notably the # keybinding for deletion. I'm basing my experimentation with AutoHotKey scripts such as this one:
https://github.com/pimlottc-gov/gmailkeys/blob/master/gmailkeys-2013.ahk#L37
That script limits its hotkeys to the main Outlook window using #IfWinActive:
#IfWinActive, - Outlook ahk_class rctrl_renwnd32, NUIDocumentWindow ;for Outlook 2013, uncomment this line
However, if I do not change the above #IfWinActive statement, and then add the # hotkey via:
+3::Send {Delete} ; Means "#" key: Delete selected message(s)
then when running the script, then clicking in the above Search field, then typing #, then of course it sends the Delete key into that field, instead of just passing the # into the search field.
I've hacked around this by rebinding both Ctrl+e and / (the latter being the Gmail binding for searching/filtering) to a temporary input popup where I type in the search expression, and then let AutoHotKey type it into the field. But this of course is a hack:
; Search for some expression
;
; Hack: We have to popup an input dialog box, prompt for the
; search expression, and then when done, type it into the
; underlying search field. This is needed to avoid having other
; single-key bindings get "eaten" when needing to type into the
; Outlook search field, as as of 2021-05-23 I could not find a way
; to detect that specific input field.
;
^e::
/::
; Save current active (Outlook) window so we can return to after prompting for the search expression:
WinGet, winid ,, A ; <-- need to identify window A = active
; Prompt for the search expression:
InputBox, search_expr, Search Expression, Enter the search expression.
; Return to the Outlook window:
WinActivate ahk_id %winid%
; If the user presses Escape or clicks on the Cancel button, do nothing:
if (!ErrorLevel) {
; but if we are doing the search:
; Get into the search field:
Send ^e
; Select all prior text so we can wipe it out:
Send ^a
; ... by typing in all of the expression:
Send %search_expr%
; then do the search:
Send {Enter}
}
return
No matter where I click around in the main Outlook window, Window Spy (app that comes with AutoHotKey), the class always stays the same.
AutoHotkey version: 1.1.33.08
Note that Shift+3 only happens to produce a # on your keyboard layout. It would be more correct to actually use the # key as the hotkey.
Also, the code you're referencing is very legacy AHK. Quite a few things in there that don't belong to modern AHK.
I'd maybe also recommend just doing this with a context sensitive hotkey.
This way you'll retain the # key's native functionality.
The context sensitive hotkey could be done like this:
SetTitleMatchMode, 2
#If, WinActive("A") == WinExist("- Outlook ahk_exe OUTLOOK.EXE") && !SearchBarFocused()
#::SendInput, {Delete}
#If
SearchBarFocused()
{
ControlGetFocus, ctrl
return InStr("RICHEDIT60W1,RichEdit20WPT1", ctrl)
}
I'm also checking if Outlook is actually the active window first. Might be kind of redundant, but makes it so the remap couldn't be active in some other window that could have a control by that name.
I found the solution after some experimentation (including simplification from per 0x464e's answer), and essentially reversing the logic, somewhat, at https://github.com/pimlottc-gov/gmailkeys/blob/master/gmailkeys-2013.ahk#L76 via this:
; Outlook-specific Hotkeys:
;
; Reference material used in this implementation:
; https://autohotkey.com/board/topic/38389-archiving-email-in-outlook-with-a-single-keystroke/
;
; As best I can tell, the window text 'NUIDocumentWindow' is not present
; on any other items except the main window. Also, I look for the phrase
; ' - Outlook' in the title, which will not appear in the title (unless
; a user types this string into the subject of a message or task).
#IfWinActive - Outlook ahk_class rctrl_renwnd32, NUIDocumentWindow
#::
if (SentNormalKeyInOutlookEditControl("#"))
{
return
}
Send {Delete} ; Delete selected message(s)
return
#IfWinActive
SentNormalKeyInOutlookEditControl(normal_key)
{
; Find out which control in Outlook has focus
ControlGetFocus, currentCtrl
; ; set list of controls that should respond to specialKey. Controls are the list of emails and the main (and minor) controls of the reading pane, including controls when viewing certain attachments.
; ; The control 'RichEdit20WPT1' (email subject line) is used extensively for inline editing. Thus it had to be included in bad_ctrl_list.
; ctrlList = Acrobat Preview Window1,AfxWndW5,AfxWndW6,EXCEL71,MsoCommandBar1,OlkPicturePreviewer1,paneClassDC1, RichEdit20WPT2,RichEdit20WPT4,RichEdit20WPT5,RICHEDIT50W1,SUPERGRID1,_WwG1
bad_ctrl_list = RICHEDIT60W1,RichEdit20WPT1
; RICHEDIT60W1 is the search field at the top of the window
if currentCtrl in %bad_ctrl_list%
{
; MsgBox, BAD Control with focus = %currentCtrl% normal_key = %normal_key%
Send %normal_key%
return 1
}
return 0
}
Edit 2021-05-25 06:58:23: Replace legacy "+3" with "#" per 0x464e's answer.
Edit 2021-05-25 08:20:09: Prevent " - Message" windows from receiving the hotkeys (separate message windows, not main window)
Related
I just want W to correspond to the Up Arrow key and S to correspond to the Down Arrow key, and work just like they do, and for A/D to move the focus to the last/next tab.
When i hold S, the page skips down erratically and then Firefox opens the "Save as" window multiple times.
When i hold W, the page skips up erratically and then multiple tabs are closed.
D does what it's supposed to, and A straight up doesn't work.
#IfWinActive ahk_exe firefox.exe
w::
Send {Up} ; Move page up.
s::
send {down} ; Move page down.
a::
send, ^{pgup} ; Go to tab on the left.
d::
send, ^{pgdn} ; Go to tab on the right.
#IfWinActive
Return
What exactly is happening? It should work normally but it isn't.
#IfWinActive ahk_exe firefox.exe
w:: Send {Up} ; Move page up.
s:: send {down} ; Move page down.
#IfWinActive ; turn off context sensitivity
The above examples are known as single-line hotkeys because each consists of only one command.
To have more than one command executed by a hotkey, put the first line beneath the hotkey definition and make the last line a return. For example:
#n::
Run http://www.google.com
Run Notepad.exe
return
https://autohotkey.com/docs/Hotkeys.htm#Intro
I'm trying to have 2 clipboards (or more), with an ahk script.
Desired behaviour is working with the standard ^v plus !v so it will be 2 clipboards. ^v being the usual one, !v will be the previous content that ^v had.
If I copy 'text1' on clipboard, I will have this as ^v. If I copy 'text2' I will have 'text2' on clipboard with ^v, plus the old 'text1' available with !v, and so on.
This is so far:
lastclip = %clipboard%
!v::
global lastclip
sendclip(lastclip)
return
ClipWaitChange()
ClipWaitChange()
{
While changed=0 {
global lastclip
lastclip = %clipboard%
Sleep 10
}
OnClipboardChange:
changed = 1
return
}
But it returns a blank clipboard or maybe ^v stops working.
Any hints how to do that?
sendclip is just a custom func to send the clipboard contents by keyboard
I tried put lastclip = %clipboard% inside onclipboardchange but it copies the current changed clipboard, so has to be done before that.
I assume your question is of an academic nature. If not, I recommend one of the many Clipboard Managers already out there.
Here's a solution with comments:
lastClip := ""
bufferedClip := Clipboard
OnClipboardChange("clipChangeHandler")
; Note that the ALT key can change focus, better use WIN+V
#v::
; Since we temporarily switch Clipboard's contents,
; we want to ignore the event it will fire
OnClipboardChange("clipChangeHandler", 0)
; I recommend pasting rather than sending
tmpClip := Clipboard
Clipboard := lastClip
Send, ^v
Clipboard := tmpClip
tmpClip := ""
OnClipboardChange("clipChangeHandler")
return
clipChangeHandler(evtInfo) {
global lastClip, bufferedClip
; Check if Clipboard contains actual text
if(evtInfo = 1) {
lastClip := bufferedClip
bufferedClip := Clipboard
}
}
See also OnClipboardChange in AHK docs.
A few remarks:
The event function checks for the event type being (partially) real text, ignoring pure non-text like images and also empty clipboards
clipBuffer always stores the current clipboard and lastClip contains the previous clipboard. You need the buffer variable, since the event doesn't offer something like a previous clipboard
ALT + v can be problematic when working with windows that have a classic menu bar. Hitting ALT (even before releasing it) will often switch focus away from the current control.
I recommend pasting rather than sending. E.g. when there's large text in the clipboard with thousands of words (maybe even put there by another program or simply by mistake), sending each character one by one can take a long time or may even come with other side effects. If you want to Send regardless, at least use SendRaw so that certain characters won't be mistreated as control sequences (e.g. sending #e will open Windows Explorer).
Always consider security aspects of your application. If you (our your password safe e.g.) empty your clipboard to delete sensitive data, your script will still keep an (unencrypted) copy of it, for every other process to see.
What is wrong with my script?
Context: Inbox folder of Outlook. I want to click (focus) just only one email (the one with the gray color), but my script ALSO "colors" all emails the are above it. I'm not sure what is the matter.
#IfWinActive ahk_class rctrl_renwnd32
+F7::
PixelSearch, Px, Py, 14,98,754,962, 0xE1E1E1, 3, Fast
if ErrorLevel
MsgBox, That color was not found in the specified region.
else
Click, %Px%, %Py%
return
#IfWinActive
It seems that you are oh, say, scrolling or moving the cursor around in the preview panel, and now you want to jump the cursor to that same email's entry in the mailbox listing.
If this be the case, then here is a possible solution for you:
Okay, so we know that by default, whatever message you are viewing in the preview pane should be the highlighted entry in the mailbox list. That means all we have to do is to set focus to the mailbox list pane - when that pane receives focus, then the highlighted entry should be able to receive your immediate keyboard commands since it is already selected.
Therefore, all you need to do with your ahk script is create a hotkey that sets focus to the mailbox pane. Use your window spy to spy the class of the mailbox pane and just set focus to it. You shouldn't have to worry about colours at all.
Maybe something like this for Office 2010:
+F7::
ControlFocus, SUPERGRID2, ahk_class rctrl_renwnd32
return
or, for Office 2013:
+f7::
ControlFocus, OutlookGrid1, ahk_class rctrl_renwnd32
if ErrorLevel
MsgBox, You don't seem to be in context.
return
Or, instead of hacking the window, you could just push ctrl+1 - Outlook has a built-in keyboard command to set focus to the mailbox list.
I want to use AutoHotKey to bind a command to Ctrl+Shift, in the same way that Windows detects it in order to change text direction from right-to-left to left-to-right. That is: I want it to be invoked when Ctrl+Shift is let go, and only if no keys were pressed between pressing Ctrl+Shift and letting them go.
I bound a hotkey on ^~ Shift Up and I expected it to behave the same way as when Windows binds to it for changing the text direction. But, I found that it gets invoked even in cases where I don't want it to be invoked.
For example, I could be selecting a few words by pressing Ctrl and Shift, and then using the arrow keys. Then I let go of Ctrl and Shift and the hotkey gets invoked. I don't want this. I want a hotkey that gets invoked only if I held nothing else then Ctrl and Shift. If I use any other keys, I want the hotkey not to be invoked.
Is there a way to do this with AHK?
#InstallKeybdHook
Hotkey, ^LShift Up, ControlShiftUp
Return
ControlShiftUp:
if (A_PriorKey != "LShift") ; [v1.1.01+]
return
; do something
msgbox hi
Return
Question for all you webdev guys/gals who have found a minimal-hassle development environment.
OS: Win7
Editor: JEdit
Task: Previewing work in a web browser
I would like to program a single hotkey to pack the following series of hotkeys into one. I use this sequence many times a day to preview my work in a browser.
The key commands are:
(from JEdit) ctrl + e ctrl + s [save all files]
(win) alt + tab [switch me over to browser]
(browser) ctrl + r [reload page]
I have not used Dreamweaver or flash in years but I remember punching f12 or ctrl + enter and having a browser pull up previewing the current work file. I am looking for a similar workflow but I cannot simply link to the saved file on disk. I need to look at the file through a local webserver. Typically I just have the browser open to the page I need and refresh it when I need to preview what I have done.
Another issue is the alt+tab step is not explicit enough. Often times the browser is not correctly sequenced in the open apps list to get to it without multiple tabs.
Thanks for any suggestions, workflow tips, etc.
Use this answer to create a command line method of refreshing a webpage ( it will work for any browser).
Next, create a baseline macro in JEdit for activating that script that you created:
In JEdit, you can record macros with Macros->Record Macro.
Do ctrl + e + s
Stop recording the macro with Macros->Stop Recording.
Open the JEdit browser tab with the newly created macro buffer that is now open in JEdit and add a system call at the end of it to run your visual basic script for refreshing the browser tab:
Runtime.getRuntime().exec("c:/PATH/TO/VB_SCRIPT AND ARGS IF YOU NEED THEM");
Save the macro.
Create a JEdit keyboard shortcut with utilities->global options, select "Shortcuts" then search for you macro and create a new keyboard binding.
Note that the Java beanshell exec command is non-blocking, so if you want to do anything else after executing the command, you may have to insert a sleep like:
Thread.currentThread().sleep(2000);
Just Press Alt + F5 and get it done!
To accomplish that, install AutoHotKey and run the script below (copy in a text file and change extension to .ahk). There is a portable version here. It was tested with AutoHotKey version is 1.0.48.05
This solution is pretty flexible since you can change Keys, Editors, Browsers and everything else. It works with Firefox and IE but you can easily customize.
The varTextEditor and varBrowsers where discovered using "WindowSpy" utility that comes bundled into AutoHotKey.
;###############################################################################
; Save all unsaved documents, refresh all opened browsers and return to text editor
;###############################################################################
!F5::
;Configuration vars. Edit here the settings of this script
; jEdit Eclipse
varTextEditor = SunAwtFrame,SWT_Window0
;varBrowsers = MozillaUIWindowClass,MozillaWindowClass,Chrome_WidgetWin_0,IEFrame,OpWindow,{1C03B488-D53B-4a81-97F8-754559640193}
; Firefox3 Firefox4 Chrome IEca Opera Safari
varBrowsers = MozillaWindowClass,IEFrame
;End of configuration vars.
WinGetClass, thisWindowClass, A ;Get the active window class
if (InStr(varTextEditor, thisWindowClass, true, 1) > 0) { ;true = case sensitive
varTextEditorClass = ahk_class %thisWindowClass%
if (thisWindowClass = "SunAwtFrame") {
OutputDebug, ...Saving everything
; SetKeyDelay, 100, 100, Play
Send ^+s ;Ctrl + Shift + S = Save all
} else if (thisWindowClass = "SWT_Window0") {
SendPlay ^s ;Ctrl + S = Save
}
Sleep, 500 ;Give some time to the data be recorded on hard disk
} else {
MsgBox, 0, Ops!, You must be in on these text editors: (%varTextEditor%) to get this script running, 5
return
}
;Refresh all opened (and maximized) browsers
Loop, parse, varBrowsers, `,
{
varClasseBrowser = ahk_class %A_LoopField%
if WinExist(varClasseBrowser) {
WinGet, winState, MinMax, %varClasseBrowser% ;get window state. -1 = minimized
if (winState != -1) {
WinActivate, %varClasseBrowser%
OutputDebug, ...Refresh browser %A_LoopField%
Send, {F5}
}
}
}
;Return to text editor
WinActivate, %varTextEditorClass%
return