Thinkpad で Pacman を Play

Thinkpad x60s が届き、だいたいセットアップが終わったのでさっそく遊びだしています。とりあえず、HDDセンサー付きのPCで一度やってみたかった miyagawaさんのGoogle Maps tilt をやってみました。これは楽しい。わずか数行のコードで Perlからマシンの傾き値が取れるのか。

なら、何か他にも遊んでおきたいな、ということで、古典的ゲーム「パックマン」をThinkpadを傾けて操作するっていうのをやってみることに。それなりにゲームできたので、動画。

JavaScriptで動くPacman を見つけてきて、元記事みたくActiveX でという作戦でもいけると思んだけど、同じだとつまんないので、Thinkpad の前後左右への傾きが上下左右キーを押したのと同じになるようにするコードを書く方向で検討開始。

Perl からキーボード操作をする方法を探そうと CPAN の Win32::* をあさってたら、Win32::GuiTest というものを発見。これは以下のように書くだけで

use Win32::GuiTest qw(:ALL);
SendKeys("{UP}{UP}{DOWN}{DOWN}hello");

キーボードから ↑↑↓↓hello と打ったのと同じことになるというもので、たぶん本来の用途は名前の通り普通のGUIアプリを操作してテストするもの。本件はこれがそのまま使えるなあと。そこで、以下のようなコードを実行した上で、ここで見つけたFlash版Pacman を開いて遊んでみたのが上の動画です。

# thanks miyagawa: http://blog.bulknews.net/mt/archives/002053.html
use strict;
use Time::HiRes qw(sleep);
use Win32API::File qw(:ALL);
use Win32::GuiTest qw(:ALL);

sub get_tilt {
    my @base;
    return sub {
        my $file = createFile("//./ShockMgr", "r ke") or die "Can't get ShockMgr device";
        DeviceIoControl($file, 0x733fc, [], 0, my($buf), 0x24, my($bytes), []);
        my @data = unpack "x4s*", $buf if $buf;
        
        @base = @data[3, 2] unless @base;
        return { 
            x => ($data[1] - $base[0]) / 20, 
            y => ($data[0] - $base[1]) / 20,
        };
    }
}

my $tilt = get_tilt();

while (1) {
    my $move = $tilt->();
    
    my $keys = '';
    if    ($move->{x} > 0) { $keys .= "{RIGHT}" x int abs $move->{x} }
    elsif ($move->{x} {x} }
    if    ($move->{y} > 0) { $keys .= "{DOWN}"  x int abs $move->{y} }
    elsif ($move->{y} {y} }
        
    warn $keys if $keys;
    SendKeys($keys) if $keys;
    
    sleep 0.1;
}

bulknews.typepad.com に Trackback 打つためにちょっと英語で書こうとしてみたものの、途中で挫折…。しかし、Win32::* いろいろ使えそうなものがあっておもしろいなあ。Win32::Clipboard とか Win32::Screenshot とか。