Работа с окнами как в Windows 7 при помощи hotkeys: Win + [Up|Down|Left|Right]
- modified:
- reading: 3 minutes
Редко пользуешься тем, что пишешь сам. Но вот тот самый редкий случай. В Windows 7 мне очень понравилась возможность позиционирования окон при помощи сочетаний клавиш:
- Win Left - окно крепиться к левому краю
- Win Right - окно крепиться к правому краю
- Win Up - окно максимизируется
- Win Bottom - окно в нормальном состоянии.
Причем крепление окон к правому краю и левому, по-моему, уж очень удобная штука, ведь сколько раз приходилось самому располагать два окна на экране, с возможностью сравнения или перепечатывания...
Windows 7 не хочу использовать в качестве основной ОСь - потому что бета (или CR, главное что не Release), а возможность описанную выше использовать хочу. И вот - не поленился, и написал программку на C#, которая реализует данный функционал в Vista (скорее всего работает и более ранних версиях - просто не проверял). И как оказалось - задача не такая уж и сложная. Пришлось проимпортировать множество WinApi функций, а сама реализация разделилась на две: а) функционал, который перехватывает нажатия необходимых сочетаний клавиш б) позиционирование окон.
Первую задачу решил при помощи статьи Low-Level Keyboard Hook in C #, все что осталось сделать мне - найти возможность узнать когда была нажата клавиша LWin:
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WAKeysHook.WmKeyDown)
{
if ((int)WAKeysHook.GetAsyncKeyState((IntPtr)Keys.LWin) != 0) // Left Win Key
{
Keys key = (Keys) Marshal.ReadInt32(lParam);
if (key == Keys.Left || key == Keys.Right || key == Keys.Up || key == Keys.Down) // Arrows keys
SetWindowLocation(key);
}
}
return WAKeysHook.CallNextHookEx(WaKeysHook.HookId, nCode, wParam, lParam);
}
Вторая часть задачи: найти активное окно и установить ему грамотный размер (само собой нужно учитывать, что менять размеры можно только окнам с такой возможностью (WS_SIZEBOX), а так же что некоторые окна имеют максимально разрешенные размеры своего окна, как у cmd.exe):
private static void SetWindowLocation(Keys k)
{
//Active Window
IntPtr window = WAWindows.GetForegroundWindow();
// Check SIZEBOX Style (Window can sizable)
if (((int)WAWindows.GetWindowLongPtr(window, WAWindows.GwlStyle) & WAWindows.WsSizebox)
== WAWindows.WsSizebox)
{
// Show window in normal state (if always maximized)
WAWindows.ShowWindow(window, (int)WAWindows.WindowShowStyle.ShowNormal);
//Need Maximazed
if (k != Keys.Down)
{
WAWindows.ShowWindow(window, (int)WAWindows.WindowShowStyle.ShowMaximized);
// Place Window on left or right
if (k != Keys.Up)
{
WAWindows.Rect rect, rectDesktop;
if (WAWindows.GetWindowRect(window, out rect) && WAWindows.GetWindowRect(WAWindows.GetDesktopWindow(), out rectDesktop))
{
WAWindows.SetWindowPos(window, WAWindows.HwndTop, (k == Keys.Left) ? Math.Min(rect.Left, 0) : rectDesktop.Right / 2,
rect.Top, Math.Min(rect.Width, rectDesktop.Right / 2 - Math.Min(rect.Left, 0)),
Math.Min(rect.Height, rectDesktop.Bottom), WAWindows.SwpShowwindow);
}
}
}
}
}
И последнее, в своей программе я ввел возможность установки - необходимо ли отображать значек в трее или нет, который помогает в закрытии программы, для этого нужно установить значение в соответствующей секции app.config.
<applicationSettings>
<VistaKeysExtender.Properties.Settings>
<setting name="ShowNotifyIcon" serializeAs="String">
<value>False</value>
</setting>
</VistaKeysExtender.Properties.Settings>
</applicationSettings>
Мне просто сам значек не нужен, программа крутиться всегда в фоне, а место в трее итак переполнено. Функциональные клавиши я описал вверху статьи. Вопросы и предложения готов выслушать и ответить на них. Надеюсь, что кому то будет так же полезна данная программа как и мне.
- Keys Extender (Win 7 Compatible) - binary
- Keys Extender (Win 7 Compatible) - binary (x64)
- Keys Extender (Win 7 Compatible) - source
- Article on CodeProject (EN)