What's It For
When you get tired of dragging the mouse back and forth between two or more big screens and you really don't care to Alt-Tab your way around umpteen applications, you
may find this tool an easier way to cover vast cursor distances in a single bound. The default "Last Position" mode will move the cursor to the last position it was at when
jumping back to a screen when a hotkey is hit. The "Same Position" mode moves the cursor on the current screen to the relative same position, or near the same position, on
the next monitor screen to the right or left when the hotkey is hit.
"Jump Right" and "Jump Left" only show a difference in behavior when you have a desktop extended across more than two monitors.
Since I am just a poor man and don't have freakish amounts of hardware, you can be the first to tell us whether this tool works on a 3 or more monitor systems. I think
it should work.
Due Diligence
PLEASE tell me if I've wasted my time. I think I'm a fair Googler and I haven't found any Windows trick or free tool to do this. Although,
I did uncover a few shortcuts I hadn't seen before:
- Desktop publishing forum: Windows Short Cuts & Hot Keys by: Dohadwala June 5, 2007.
- Win+B: Move focus to systray icons. You can use Left and Right arrow keys to move between icons. 'Enter' for left-click menu.
- Ctl+Alt+Down arrow: Rotate screen 180, Ctl+Alt+Up arrow: Rotate screen back. Really?!! Are these a gag? What is the use of these? You can tell I'm not a tablet user (remember - no freakish amounts of hardware). Operates on the screen with the cursor.
- Useful New Windows 7 HOTKEYS-Keyboard Shortcuts January 29, 2009.
- Here are a few notable shortcuts:
- Win+Left : Snap to left, Win+Right : Snap to right. Kind of neat. Works great on Win8 but this feature doesn't work on my Win7 system. Aero Flip 3D (Ctl+Win+TAB) works on my Win7 machine but I can't get Aero Snaps to work for anything.
- Win+Shift+Left : Jump to left monitor, Win+Shift+Right : Jump to right monitor. Nnnngh. Almost. Now just leave the active window behind and move the cursor instead and you have what I want. Works sensibly when the active window spans screens. Left of leftmost cycles back to rightmost and vice versa.
- Ctl+Esc : Go to Win8 Start screen. My current favorite shortcut. If you are on the Start screen, Ctl+Esc will return you to whatever you were viewing before. This will probably remain useful even in Windows 8.1, wherein Microsoft admits it was a mistake to eliminate the desktop Start ball.
- Win+Page Up, Win+Page Down : Switch Metro to other screens. I am still trying to find how to extend Metro across screens. I am not sure I really want to, but I would
probably be scrolling the mousewheel Up(aka Left) and Down(aka Right) a lot less.
Parts and Pieces
I started this tool by finding
this link. I don't want a Form, Window, or Page hanging around. I wanted the smallest
desktop manifestation possible that would allow controlling a hot key to use in jumping the cursor from screen to screen, allow control of what "screen to
screen" means, and would quietly go away (Exit) when I want. This application's ProcessIcon
class plus ContextMenus
class is pretty much
all that minus the hotkey. What is a little unusual is the initial steps in this project:
- Create a new Windows Forms Application.
- Delete Form1.cs from the project.
- Open Program.cs - remove the line that reads
Application.Run(new Form1());
.
In place of running a Form, the Program.cs module displays a ProcessIcon
's NotifyIcon
(system tray icon) and starts a
message pump to handle context menu selections (Application.Run()
with no parameter). Mark Merrens uses a using
statement to create
the ProcessIcon
instance and, since this class implements IDisposable
, to clean up
resources when the application exits. Here is the main part of Program.cs in that project:
using (ProcessIcon pi = new ProcessIcon())
{
pi.Display();
Application.Run();
}
In my case, I detect during the ProcessIcon
constructor whether the system has at least two monitor screens. If not, public
member
terminate
is set to true
. For one monitor or more than one, the NotifyIcon
is instantiated since we know Dispose()
will always
be called on exit. Here is the same section in ScreenHopper
's Program.cs:
using (ProcessIcon pi = new ProcessIcon())
{
if (pi.terminate)
{
return;
}
pi.Display();
Application.Run();
}
The other main part of ScreenHopper
is the hotkey used to jump the cursor. I wanted something that didn't require taking your hand off the mouse, but I couldn't use plain
mouse clicks since they are claimed by most applications and regular desktop use. Most right-handed people can locate the Left Control key without looking so I chose
Control
as the default modifier. The other choices of modifier are Shift
and Alt
or any combination of these you choose except the "no modifier" case
(Right Click the ScreenHopper systray icon, choose the Hotkey
menu item). The Win
key can also be a modifier but I didn't want to tempt fate.
Win
key up is definitely more than a modifier.
The hotkey trigger can be any "modified" mouse button. I chose the mousewheel (middle mouse button) as default since most mice have a wheel switch
now and its use is otherwise less common.
The hotkey library I found is well-described
here. This library is perfect since it handles both global keyboard and global
mouse events (vs clicks and presses for an active, focused, non-systray app).
The most recent version (Version 3) is actually hosted on CodePlex here, but I am calling it a CodeProject project since it appeared here first (How could you leave us,
George Mamaladze? Weren't we good for you?)
A Pressing Matter
From examining the library, you would think you could detect mouse key presses in a KeyboardHookManager
. Something like:
private void HookManager_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LButton || e.KeyCode == Keys.MButton || e.KeyCode == Keys.RButton)
DoSomething();
}
Alas, I couldn't get this to detect mouse presses. From what I can tell, keyboard hooks and mouse hooks are completely separate. You can't detect mouse buttons in
KeyEventArgs
and you can't detect Ctl/Alt/Shift/ modifiers in MouseEventArgs
. What to do? Well, obviously you handle Control key, Alt key,
and Shift key KeyDown
and KeyUp
events to set a few global variables and then use their setting when processing MouseEventArgs
. Below is my
HookManager_KeyUp
handler and my HookManager_MouseDown
handler. HookManager_KeyDown
is the same as HookManager_KeyUp
except for setting the three globals:
shiftDown
, controlDown
, and altDown
. The assignment statement for
modifiersDown
is the same in both keyboard hook handlers. We don't need a HookManager_MouseUp
handler since we take the jump only on
detecting mouse button down events. I tried to keep processing as light as possible since these are global for all keys and mouse button events.
private void HookManager_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LShiftKey || e.KeyCode == Keys.RShiftKey)
shiftDown = false;
else if (e.KeyCode == Keys.LControlKey || e.KeyCode == Keys.RControlKey)
controlDown = false;
else if (e.KeyCode == Keys.LMenu || e.KeyCode == Keys.RMenu)
altDown = false;
else
return;
modifiersDown = (shiftDown == shiftChecked) &&
(controlDown == controlChecked) && (altDown == altChecked);
}
private void HookManager_MouseDown(object sender, MouseEventArgs e)
{
if (!modifiersDown)
return;
if ((e.Button == MouseButtons.Left && mouseLeftSelected) ||
(e.Button == MouseButtons.Middle && mouseWheelSelected) ||
(e.Button == MouseButtons.Right && mouseRightSelected))
{
JumpCursor();
}
}
Summary
I would go over the JumpCursor
method, but it's really just a bunch of if
-then
-else
's. This project at least shows how to handle combining mouse and
keyboard events to effect mouse clicks with modifiers. I've found the "Last Position" mode more natural to me. If you prefer
the "Same Position" mode as the default, change the initial assignment of lastPosition
to false
.
You can start more than one ScreenHopper
. Nothing bad happens but they make confusing hops or no hop (Same same). ScreenHopper
works when one monitor is desktop
and one is Metro.
History
- First submission to CodeProject, June 2013
- Update submitted Jun 21, 2013. Failed to imagine negative screen bounds. Fixed for primary screen on right.