2010年1月21日星期四

Ruby版SendKey

VBScript中的SendKey是个很有用的方法,可以用代码实现一些简单的自动化操作。实际上,通过SendMessage发送WMKEYDOWN和WMKEYUP消息就可以实现同样的功能。而且这个办法可以向任意窗口发送消息,目标窗口并不需要具有焦点。

MSDN可以查到,WM_KEYDOWN和WM_KEYUP消息除了virtual-key code之外,还需要一个scan code。文档只说这个值根据不同的键盘会有所不同,但如何获得这个值却没有提。

好吧,这篇东西值得看的其实也就这一点点了,那就是:MapVirtualKey

以下程序是我用No$gba玩《恶魔城·苍月的十字架》时写来刷25号怪的,该作的魂系统实在太变态,不想点办法我会有一种被游戏玩了的感觉。还别说,有一种当年玩MUD的感觉。

require "Win32API"

module Win32
  module_function

  WM_KEYDOWN = 0x100
  WM_KEYUP = 0x101
  
  VK_SHIFT = 0x10
  VK_NUMPAD4 = 0x64
  VK_A = 0x41
  VK_D = 0x44
  VK_W = 0x57

  def sendMessage(hWnd, nMsg, wParam, lParam)
    f = Win32API.new('user32', 'SendMessage', 'LILL', 'L')
    f.call(hWnd, nMsg, wParam, lParam)
  end
  
  def findWindow(sClass, sTitle)
    f = Win32API.new('user32', 'FindWindow', 'PP', 'L')
    f.call(sClass, sTitle)
  end
  
  def mapVirtualKey(uCode, uMapType)
    f = Win32API.new('user32', 'MapVirtualKey', 'II', 'I')
    f.call(uCode, uMapType)
  end
  
  def sendKey(hWnd, aKeys)
    aKeys.each do |key_code|
      sendMessage(hWnd, WM_KEYDOWN, key_code, 1 + (mapVirtualKey(key_code, 0) << 16))
      sleep(0.1)
    end
    
    aKeys.reverse.each do |key_code|
      sendMessage(hWnd, WM_KEYUP, key_code, 0xc000_0001 + (mapVirtualKey(key_code, 0) << 16))
      sleep(0.1)
    end
  end
end


s = 'No$gba Emulator '
h = Win32.findWindow(nil, s)
while true
  4.times do |n|
    Win32.sendKey(h, [Win32::VK_SHIFT])
    sleep(0.5)
  end
  Win32.sendKey(h, [Win32::VK_A])
  sleep(0.1)
  3.times do |n|
    Win32.sendKey(h, [Win32::VK_SHIFT])
    sleep(0.5)
  end
  Win32.sendKey(h, [Win32::VK_D])
  sleep(0.1)
  Win32.sendKey(h, [Win32::VK_D])
  sleep(0.1)
  5.times do |n|
    Win32.sendKey(h, [Win32::VK_W, Win32::VK_NUMPAD4])
    sleep(0.5)
  end
end

2010年1月8日星期五

Windows 7 IPv6不完全折腾

按照网上很多人的说法,Windows 7下只需要开一个有管理员权限的控制台,执行类似如下两条命令即可:

netsh interface ipv6 isatap set router isatap.tsinghua.edu.cn
netsh interface ipv6 isatap set state enabled

然而很奇怪的是,ipconfig显示我已经有了一个2001开头的IPv6地址,ipv6.google.com却打不开。试了很多个isatap服务器都不行,正像只没头苍蝇一样在网上乱逛的时候,鬼使神差地敲了一句ping -6 ipv6.google.com。呃,居然有回复?!然后试着在浏览器里访问http://[2001:4860:c004::68],还真的可以打开……

C:\>nslookup www.kame.net
服务器:  google-public-dns-a.google.com
Address:  8.8.8.8

非权威应答:
名称:    www.kame.net
Addresses:  2001:200:0:8002:203:47ff:fea5:3085
          203.178.141.194


C:\>ping www.kame.net

正在 Ping www.kame.net [203.178.141.194] 具有 32 字节的数据:
来自 203.178.141.194 的回复: 字节=32 时间=111ms TTL=45
来自 203.178.141.194 的回复: 字节=32 时间=131ms TTL=45
来自 203.178.141.194 的回复: 字节=32 时间=99ms TTL=45
来自 203.178.141.194 的回复: 字节=32 时间=137ms TTL=45

203.178.141.194 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 99ms,最长 = 137ms,平均 = 119ms

C:\>nslookup ipv6.google.com
服务器:  google-public-dns-a.google.com
Address:  8.8.8.8

非权威应答:
名称:    ipv6.l.google.com
Address:  2001:4860:c004::68
Aliases:  ipv6.google.com


C:\>ping ipv6.google.com
Ping 请求找不到主机 ipv6.google.com。请检查该名称,然后重试。

C:\>ping -6 ipv6.google.com

正在 Ping ipv6.l.google.com [2001:4860:c004::68] 具有 32 字节的数据:
来自 2001:4860:c004::68 的回复: 时间=401ms
来自 2001:4860:c004::68 的回复: 时间=400ms
来自 2001:4860:c004::68 的回复: 时间=401ms
来自 2001:4860:c004::68 的回复: 时间=401ms

2001:4860:c004::68 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 400ms,最长 = 401ms,平均 = 400ms

nslookup能够获得IPv6地址,而且排在IPv4地址的前面,似乎DNS并没有什么问题。然而无论是ping还是浏览器,却都对IPv6地址视若无睹,就好像IPv6根本没有启用一样。

接下来抱着试一试的心情,我又往hosts文件里添加了几个IPv6地址,比如:2001:4860:c004::68 www.google.com

居然,好了?嗯,ping没问题了,浏览器也能正常打开。看起来还是DNS解析的问题,网络应用程序默认情况下无法取得IPv6地址。

可问题究竟出在哪?在网上翻了很久,仍然不明所以。我甚至开始怀疑,是不是自己网络环境的原因(我用没有独立IP的小区宽带,家里还有一个路由器,相当于是内网中的内网),但试着在Ubuntu里装上miredo,同样用Google DNS,同一个ISATAP服务器,一切正常。

看来,只能是Windows 7的设置有问题了。虽然解决办法到现在也没找到,不过至少hosts可用,先将就吧……

用上IPv6之后,我常用的绝大部分网络程序都没出什么问题,只有Privoxy。跑到官网上看了看,最新版的3.0.15是可以支持IPv6的,只是mingw32编译的Windows版还不行,需要修改代码。Socket编程我碰都没碰过,这可不是我擅长的领域,所以试着用Cygwin编译了一个Privoxy,能用。虽然没有GUI,不过那个窗口也没大用,继续将就……

2010年1月4日星期一

初尝黑苹果

最近手上多出来一块160G的硬盘,拿来干什么都太小,突然想起来还有黑苹果这种东西,正好对传说中Windows的GUI+Linux的Console很有兴趣,于是装上试了试。

手上没有刻录机,安装过程参考了远景论坛的这张帖子,基本没有遇到太大的问题,不过一些小地方还是耗费了不少精神。

Boot Think 2.3.18在OS X中安装至MBR无法引导,Chameleon 2.0 RC4虽然可以安装,但是有部分KEXT又会无法加载。最后索性多分了一个区装上Windows XP,把Boot Think放在Windows分区上。反正现在用的Windows 7也有部分软件表现不良,就当备用吧。

驱动方面方面,我用了如下这些KEXT:AppleNForceATA、ElliottForceLegacyRTC、fakesmc、NullCPUPowerManagement、OpenHaltRestart、PlatformUUID、VoodooHDA。

DSDT.aml虽然可以解决很多问题,可是需要针对不同主板不同BIOS版本进行修改,而网上的文档很杂乱,那个ACPI Patcher又很不好用,再加上找到ElliottForceLegacyRTC这个KEXT解决了BIOS Checksum Error的问题,所以我还是放弃了。

显卡驱动一开始用的是NVEnabler,可是总觉得中文小字体的表现很糟糕,颜色很淡又很模糊。找了一个EFI Studio生成显卡的EFI String,写入Boot Think的Darwin目录下的com.apple.Boot.plist(如果是com.apple.Boot__.plist,则改名之),感觉似乎稍好了些。

Update:关于中文字体颜色太淡的问题我已经放弃了。喜欢折腾的人去看看这个文件:/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreText.framework/Resources/DefaultFontFallbacks.plist,这是设置默认字体的地方,跟Linux的fontconfig差不多。另外还有:defaults -currentHost write -globalDomain AppleFontSmoothing -int 1,取值1、2、3分别代表渲染度由淡至浓。

AMD的CPU还需要用Marvin's AMD Utility生成CPUID的补丁,引导至单用户模式(参数-s)打上补丁才能用iTunes和QuickTime。点菜单栏上的“关于本机”强制注销的问题,装上AppleSMBIOS和AppleSMBIOSEFI两个KEXT可以解决。

XCode 3.1.4在10.6下貌似有问题,装完以后/usr/bin下并没有gcc等东西,重下一个XCode 3.2之后问题解决。不过System Tools在AMD CPU的机器上不能装,会五国。(装上了也没关系,-x引导安全模式,运行/Developer/Applications/Performance Tools/CHUD下的CHUD Remover即可。)

安装部分大致就是这样,虽然启动有些慢(怀疑是AppleNForceATA的问题,可找不到可以替换的KEXT),不过已经完全可用了。感觉黑苹果的破解程度还是颇高,即使当成日常使用的系统,也完全没有问题。

至于使用感受,下次有精神再说吧……

Update:关于Boot Think无法引导Grub2(Ubuntu等)的问题,用任意一个十六进制编辑器打开Darwin/rc/grubloader2,搜索“menu.lst”,全部替换为“grub.cfg”即可。