2009/11/22
作者:KEFEI
http://youkefei.spaces.live.com/blog/cns!E6EFAFB6F926AF7F!2192.entry?&_c02_owner=1
五个月前写过一篇BLOG:-=[ New Wide Monitor + DualWeb ]=-,是一个关于把两个浏览器窗口排列在桌面上,每个窗口占一半桌面的小程序。那个程序有不少局限,比如只能用于Firefox,不够通用,C++代码让一般人很难编译等。Windows 7有个挺好用的功能就是使用键盘的Win Key+方向键来控制窗口的排列,比如Win Key + ← / Win Key + →正好可以把窗口排列到桌面的左半边或者右半边,Win Key + ↑最大化窗口,Win Key + ↓最小化窗口等。我虽然在办公室用Windows 7,但是在家还是固守我的Windows XP 64-bit,所以想写一个程序把Windows 7的这个新功能带到Windows XP上。这样不光对于浏览器,对于任何窗口都可以让它们在桌面上左右排列了。
开始的时候还是想用Visual C++写,又觉得没啥挑战性,也着实没啥意思,后来脑子里忽然跳出了据说能惊天地,泣鬼神的AutoHotKey。我以前没怎么用过AutoHotKey,只是在公司见到同事用,就去了解了一些。AutoHotKey本身是个很小的程序,但是它支持自己的一套脚本语言,让它的功能变得很强大。用它的脚本写出来的程序,只有想不到,没有做不到的。
于是下午先研究了一下它的脚本系统,发现是个不算十分严谨,但是功能很多的脚本语言。脑子里固有的C++的严谨语法,有时反而成了绊脚石。不过好在都是编程语言,大同小异,研究了两三个小时后,就开始动手写了。先实验性写了一个只支持一个显示器的程序。这个程序很简单,但是我打算支持任意多显示器,窗口在桌面放置的位置就不是简单的左半边和右半边了,而是每个显示器都有左右半边。另外,还要考虑到多显示器的系统,用户有时可能会暂时禁用一个显示器,所以程序要实时判断系统里有几个同时启用的显示器。结果就是程序长度涨了一倍,不过也不是很长,仅仅200行而已。
这个程序取名WinDocker,用AutoHotKey加载就行了,这里是脚本源代码:WinDocker.0.1.ahk
#NoEnv
/*
Mutiple Monitor Window Dock Positions:
[ Monitor 1 ][ Monitor 2 ] ...
+-------+-------++-------+-------+
| | || | |
| 0 | 1 || 0 | 1 | ...
| | || | |
| | |+-------+-------+
+-------+-------+
And the multiple monitors may not have same resolution
*/
/*
FUNCTION : getActiveWindowPosition(ByRef state, ByRef monID, ByRef monPart)
REMARK : get active windows state and position
PARAMETERS :
state : 1 - window is maxmized, -1 - window is minimized, 0 - window is restored
monID : which monitor is window center in
monPart : which part is window center in
*/
getActiveWindowPosition(ByRef state, ByRef monID, ByRef monPart)
{
WinGet, state, MinMax, A
if(state = 1 or state = -1)
{
monID := -1
monPart := -1
return
}
;else state = 0, means window is in Restored state
SysGet, monCount, MonitorCount
SysGet, workArea1, MonitorWorkArea, 1
if(monCount > 1)
{
monIndex := 1
loop % monCount - 1
{
monIndex ++
SysGet, workArea%monIndex%, MonitorWorkArea, %monIndex%
}
}
;get active window position
WinGetPos, x, y, w, h, A
centerX := x + w/2
;window center is out of the left edge
if(centerX < 0)
{
monID := 1
monPart := 0
return
}
;window center is out of the right edge
if(centerX >= workArea%monCount%Right)
{
monID := monCount
monPart := 1
return
}
monIndex := 0
loop % monCount
{
monIndex ++
centerWorkArea%monIndex% := (workArea%monIndex%Left + workArea%monIndex%Right)/2
if(centerX >= workArea%monIndex%Left and centerX < centerWorkArea%monIndex%)
{
monID := monIndex
monPart := 0
break
}
if(centerX >= centerWorkArea%monIndex% and centerX < workArea%monIndex%Right)
{
monID := monIndex
monPart := 1
break
}
}
}
/*
FUNCTION : dockActiveWindow(position)
REMARK : dock active window to dock position
PARAMETERS :
moniter : dock to which monitor
part : 0 - left part, 1 - right part
*/
dockActiveWindow(monID, monPart)
{
SysGet, monCount, MonitorCount
SysGet, workArea1, MonitorWorkArea, 1
if(monCount > 1)
{
monIndex := 1
loop % monCount - 1
{
monIndex ++
SysGet, workArea%monIndex%, MonitorWorkArea, %monIndex%
}
}
if(monID > monCount)
{
monID := monCount
monPart := 1
}
if(monID < 1)
{
monID := 1
monPart := 0
}
if(monPart > 1)
monPart := 1
if(monPart < 0)
monPart := 0
if(monPart = 0) ;left
{
WinMove,A,,workArea%monID%Left,0,(workArea%monID%Right - workArea%monID%Left)/2, workArea%monID%Bottom
x := workArea%monID%Left
w := (workArea%monID%Right - workArea%monID%Left)/2
return
}
if(monPart = 1) ;right
{
WinMove,A,,(workArea%monID%Right + workArea%monID%Left)/2,0,(workArea%monID%Right - workArea%monID%Left)/2, workArea%monID%Bottom
x := workArea%monID%Left
w := (workArea%monID%Right - workArea%monID%Left)/2
return
}
}
;HOT-KEY:
#LEFT:: ;WIN+LEFT
state := 0
monID := 1
monPart := 0
getActiveWindowPosition(state, monID, monPart)
if(state = 1 or state = -1)
WinRestore, A
;get position again after window is restored
getActiveWindowPosition(state, monID, monPart)
if(monPart = 0)
dockActiveWindow(monID - 1, 1)
if(monPart = 1)
dockActiveWindow(monID, 0)
return
#RIGHT:: ;WIN+RIGHT
state := 0
monID := 1
monPart := 0
getActiveWindowPosition(state, monID, monPart)
if(state = 1 or state = -1)
WinRestore, A
;get position again after window is restored
getActiveWindowPosition(state, monID, monPart)
if(monPart = 0)
dockActiveWindow(monID, 1)
if(monPart = 1)
dockActiveWindow(monID + 1, 0)
return
#UP:: ;WIN+UP
WinMaximize, A
return
#DOWN:: ;WIN+DOWN
WinRestore, A
return
至于怎么玩AutoHotKey,自己Google一下。实在懒的Google的,这里有个200K的exe执行文件,嵌入了WinDocker的脚本,下载运行就可以。缺点是你就不能自己修改脚本了。
这里段演示: