Google Maps を ThinkPad 加速度センサーで操作 というナイスなハックをやってみたわけですが、ちょっと技術的な部分を解説。
まず ThinkPad の加速度を読む部分は、Google で検索すると、
あたりのコードが見つかります。C で書くと、
if( !DeviceIoControl( hFile, 0x733fc, NULL, 0, // via IOCTL(0x733fc) (void *)&AccelerometerData, 0x24, &ulRead, NULL)) throw "Failed to DeviceIoControl"; X = AccelerometerData.x0 + OffsetX; Y = AccelerometerData.y0 + OffsetY;
という感じ。これを ActivePerl でやるには、Win32API::File を使って、
use Win32API::File; 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;
という具合にやればよし。ネイティブの createFile, DeviceIoControl をそのまま呼べるので簡単。
これでX軸、Y軸の加速度が取れたので、あとは Google Maps とどうやって組み合わせるか。調べてみたところ、Google Maps の JavaScript は v2.0 からローカルの HTML ドキュメントから API Key なしで実行できるようになったとのこと。
というわけで WinIE で ActiveX として Perl を実行してしまって、Google Maps の JS コードと融合すればOK。この ActiveX + Perl はかなり協力で、
<script language="PerlScript"> $window->document->write("hello"); </script>
のようにブラウザのオブジェクトをさわれるし、
<script language="PerlScript"> sub foo { alert("$_[0]") } </script> <script language="JavaScript"> foo("bar"); </script>
のように PerlScript で書いた関数を JavaScript から呼び出し、またその逆なんてのも OK。当然 ActivePerl だから、LWP でも Win32::OLE でも使い放題。
てなわけで GMaps との融合。通常の GMaps アプリ同様に js をロードして Map オブジェクトを配置。ポイントは、
window.setTimeout(loop, interval); } } function loop() { var pos = get_pos(0).split(/,/); var ax = (pos[0] - base[0]) / 20; var ay = (pos[1] - base[1]) / 20; x += ax * 0.0005; y -= ay * 0.0005; // opposite way map.panTo(new GLatLng(y, x)); window.setTimeout(loop, interval); }
という具合に setTimeout でループしながら、Perl で定義した get_pos を呼び出して XY 加速度を取得。その値に応じて map.panTo() で移動、といった具合。
Win32-Perl の機能がブラウザから使えることによって、オンラインアプリの Google Maps とローカルの融合ができる、というわけでこれはアツイなー、と思ったしだいです。