Operating System | most versions of Windows (tested in 7 and 8.1) |
Required software | AutoHotkey |
The Problem
I recently started using Windows again after some months of using Ubuntu exclusively, and I decided to fix something that had always bugged me about its built in file browser, Windows Explorer.
If you press Ctrl+Z while Windows Explorer is in focus (this includes the taskbar and desktop), you will Undo the last file operation such as a delete, rename, move, or copy. The same goes for Ctrl+Y and Redo.
This is, of course, intended behaviour, but the way I work I'm always looking back and forth between open instances of Windows Explorer and e.g. a code editor arranged on multiple displays. If I do something in the Windows Explorer window, look back at the code editor window, and decide to undo an edit to the code, I might press Ctrl+Z without remembering to put the code editor window in focus first. The Windows Explorer window, up as it is on my other display and completely out of mind, would still be in focus and receive the Ctrl+Z hotkey, reversing a file operation I may have done hours ago.
Worse, this happens silently, so I might not even notice that it happened at all, until later when the un-deleted, un-copied, un-moved, or un-renamed file is needed and disaster ensues.
To be fair, this doesn't happen often, but in my opinion it's just a catastrophe waiting to happen. And that's not even considering what might happen if un-renaming a file causes a filename conflict, or if undoing a copy or move involves hundreds of files or very large ones. So a fix would definitely be nice.
The Solution
It would be ideal if Windows Explorer just alerted you that you were attempting to Undo or Redo, with a little prompt explaining exactly what file operation was in question. You could then choose to continue or cancel from there.
But I can't just add features to Windows Explorer. I don't work for Microsoft. (And even if I did, I'd be too busy adding bloated, unnecessary background processes to the latest version of Windows to get around to it either.)
So I did the next best thing, and just prevented Windows Explorer from receiving Ctrl+Z or Ctrl+Y commands altogether, protecting myself from potentional future Undo/Redo mishaps.
I did this with a program called AutoHotkey, which I learned about in a video by the always excellent Tom Scott.
AutoHotkey, or AHK, is useful for about a million other things, some of which I'll very likely blog about in the future, so if you are wary of getting it just for this fix alone, you don't have to be. (You can also use this standalone fix I made if downloading an executable from some git with a blog doesn't squick you out.)
What is AHK, though? I'll let their own site answer that (saves me typing).
AutoHotkey (AHK) is a free, open-source macro-creation and automation software for Windows that allows users to automate repetitive tasks. It is driven by a scripting language that was initially aimed at providing keyboard shortcuts, otherwise known as hotkeys, that over time evolved into a full-fledged scripting language. — www.autohotkey.com
I just needed something that could detect when keys were pressed and prevent the focused window from receiving them, and AHK fit the bill.
AHK works by running scripts, which are just text files with an ".ahk" extension that you can edit in the code editor of your choice. With AHK installed, you can easily make a new script by using the context menu in Windows Explorer: New → AutoHotkey Script. If you do it that way, some lines of code setting up the script will be filled in for you automatically. These aren't strictly necessary, but they don't hurt.
AHK associates the ".ahk" extension, so once a script file exists you can launch it by e.g. double-clicking it. A new script doesn't do anything, of course, so I had to write some code to get it to listen for a press of Ctrl+Z. Don't despair, the code for an AHK script is kind of weird and terse, but it's not hard.
The Code
Here's the code I added to the script first. It doesn't do everything yet, but building it up step by step makes it easier to understand.
^z::
Return
The caret (^
) followed by z
is just shorthand for Ctrl+Z. The double colon (::
) after it means that this is a hotkey declaration: the following block of code is what will run when that key combination is pressed. (It may help to visualise this as a function declaration like in other languages, something like function OnControlZ() { return; }
.)
At the moment, the code consists entirely of a Return
statement, which means we don't do anything at all. This actually prevents the default behaviour of Ctrl+Z; no other special commands are needed.
Running the script at this point will prevent Ctrl+Z from doing anything - but it will be applied universally, no matter what program is running or what window is focused. That's progress of a sort, but of course we want this to be restricted to Windows Explorer.
Fortunately AHK allows this. Before my hotkey declaration, I used the #IfWinActive
directive followed by the criteria that the focused (i.e. active) window has to satisfy in order for the hotkey to work.
#IfWinActive ahk_exe explorer.exe
^z::
Return
In this case I used ahk_exe explorer.exe
, which means any window that belongs to the "explorer.exe" process.
(AHK lets you use other criteria, like the window's title or class, but those were inappropriate for my purposes. Windows Explorer windows can have any title, depending on the directory being browsed, and they have a different class from the taskbar and desktop, which also needed to be covered. However all of those windows belong to the "explorer.exe" process, so that's what I went with.)
I wasn't able to just guess that ahk_exe explorer.exe
was what I should type by some kind of magic, though. AHK includes a utility for checking info about the active window, called Window Spy. If an AHK script is currently running, you can launch Window Spy by right-clicking the script's icon in the system tray. Otherwise you'll need to find "Active Window Info (Window Spy)" in your Apps list or just hunt for "AU3_Spy.exe" in AHK's program directory.
With Window Spy running, I clicked on a Windows Explorer window to get information about it. In Window Spy's "Window Title, Class and Process" field, I could see the title, class, and process of the window. I then clicked on the taskbar and desktop to be sure they were the same process.
Okay. So if you run the script now, Ctrl+Z will be disabled only in Windows Explorer. That's more like it! But instead of simply silently blocking it, wouldn't it be nice to show a little message saying "Undo has been disabled for your protection" or something?
Improvement
Even better. Let's have a prompt asking if you really want to Undo or not, with "Yes" and "No" buttons.
#IfWinActive ahk_exe explorer.exe
^z::
MsgBox, 4, Windows Explorer, Do you want to undo the last file operation?
Return
MsgBox
is a command that makes AHK show a message box. The parameters I used were
- Button Type —
4
. A constant specifying "Yes" and "No" buttons will be present. - Title —
Windows Explorer
. This is the title of the message box. - Text —
Do you want to undo the last file operation?
. This is the text in the body of the message box.
Of course, this prompt is just for show until we write code to respond to it. If the user says "yes", then Windows Explorer should receive Ctrl+Z.
#IfWinActive ahk_exe explorer.exe
^z::
MsgBox, 4, Windows Explorer, Do you want to undo the last file operation?
IfMsgBox Yes
SendInput ^z
Return
The new lines should be pretty self-explanatory.
IfMsgBox Yes
is akin to a classic if-statement, conditionally performing the following command. (It doesn't have a #
at the beginning like #IfWinActive
because it's sublty different; it controls program flow instead of being a directive that affects hotkey declarations.)
SendInput
is a command that sends key presses to the system as if the user actually typed them. In this case I used ^z
(which means Ctrl+Z just like in the hotkey declaration) so that if the user selects "yes", the system receives Ctrl+Z as if nothing ever happened and the Undo operation can go through.
I wasn't done yet, though, because the prompt isn't modal - it doesn't freeze up Windows Explorer while it waits for the user to answer. It can't, because it doesn't really belong to Windows Explorer, it's just a message box shown by AHK. So it's possible that the user can focus a different window before answering the prompt, at which point (if they say "yes") the input will be sent to the wrong window.
I solved that simply by activating the Windows Explorer window again before sending Ctrl+Z.
#IfWinActive ahk_exe explorer.exe
^z::
MsgBox, 4, Windows Explorer, Do you want to undo the last file operation?
IfMsgBox Yes
{
WinActivate
SendInput ^z
}
Return
(Now that there are two commands in the conditional block after IfMsgBox Yes
, they need to be wrapped in braces.)
WinActivate
is a command that can activate a specified window; in this case, used without parameters, it activates the window that received the hotkey in the first place. (This helpfully obviates the need to get and store the ID of the active window manually.)
So that's done it. Testing the script at this point gives the behaviour I wanted for Undo in Windows Explorer. But of course the same needs to be done for Redo as well. So here's the entire script.
#IfWinActive ahk_exe explorer.exe
^z::
MsgBox, 4, Windows Explorer, Do you want to undo the last file operation?
IfMsgBox Yes
{
WinActivate
SendInput ^z
}
Return
^y::
MsgBox, 4, Windows Explorer, Do you want to redo the last file operation?
IfMsgBox Yes
{
WinActivate
SendInput ^y
}
Return
Now that the script was complete I added a shortcut to it in my Windows startup folder so that it would run whenever I ran Windows. And with that, I was done. Fix complete!
Conclusion
If you want this fix without installing AutoHotkey, the makers of the program have covered that eventuality. AHK optionally comes with a program that can compile scripts into standalone executables that anyone can use whether the whole program is installed or not.
I've provided download links to the script and its compiled form below if you want to grab them. Use at your own risk, etc.
- NoUndoRedo.ahk – Script
- NoUndoRedo.exe – Executable
Until next time, happy coding!
Thanks for solving this troublesome issue! Your "incremental code&feature-improving" tutorial style is greatly appreciated, and will certainly help introduce folks to the remarkable tool AHK.
ReplyDeleteI'm glad you found the post and its structure helpful!
ReplyDeleteIndeed, AHK is a real lifesaver - I just helped my brother use it to automate a laborious process at his workplace.
Very nice, thank you! I'd hacked together something similar awhile ago but it was buggy. Yours isn't, and the "confirmation box" idea is great. :-)
ReplyDeleteI had this problem since 1995, and unfortunately this doesn't solve the issue of accidentally right-clicking the Undo context menu entry when you want to use a command, especially New -> Folder/File which is right next to it :(
ReplyDeletetoday is perhaps the 99th time that I've been googling for a solution and found this blog
Terrible things have happened because of this. After hours of work I might not remember the last thing that I've copied, moved, renamed, etc.
so what I'm doing since 22 years, which evolved into a compulsive obsessive disorder is to right-click, create a new textfile, then delete it to the trash bin and empty the trash bin. then this freaking context menu is finally gone
screw you Microsoft
maybe I'll create a Macro that automatically does the crap that I have to do all the time. Autohotkey really is amazing and made my Windows Life so much better.
Well, that's great! And I've added a "Are you sure?" step for extra security.
ReplyDeletewow thanks! this option should've been implemented in windows long time ago, not only for the undo/redo thing and also for drag and drop which happens more often. Thank you again and keep it up!
ReplyDelete