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
/* WINDOCKER - Version 0.1 - www.kornlabs.com */ #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的脚本,下载运行就可以。缺点是你就不能自己修改脚本了。
这里段演示:
http://www.tudou.com/v/8SG7OOYnWlo/v.swf