最終更新日 : 2003/11/23
お土産に「簡易マスタサーバ(サンプル)」を追加

ヘビにしなちく


shinatiku with python :: clipwatch :: swget :: peeper.dll :: omake

このページは?

Pythonを使ってしなちくと遊ぼうというのが趣旨。

Pythonって?

オブジェクト指向スクリプト言語・・・というと国内ではRubyしか連想されませんが、海外では結構メジャー。

まず、何をすればいいの?

Pythonでプログラミングが組める環境を作ります。

  1. ここからPython 2.3.2をダウンロードしてインストール。
  2. ここからPython 2.3用のwin32allをダウンロードしてインストール。
  3. ここからPython 2.3用のctypesをダウンロードしてインストール。
  4. コマンドプロンプトを開いてPythonと打ってみる。Pythonが起動され対話モードになったら、取りあえずCTRL-Zで抜けます。コマンドまたはファイル名が見つからないと言われたらPython 2.3をインストールしたディレクトリにパスを通します。

準備完了です。

Pythonでプログラムが組めないのですが・・・

メモ帳とかエディタとか立ち上げて、

print "Hello, World"
						

と、入力して、ファイル名にhello.pyとつけて保存。コマンドプロンプトを開いてPython hello.pyとすると実行されます。

ファイルの拡張子をpyにすることと、実行するには「Python ファイル名」とすることが分かったところで、 ここのチュートリアルを一通りやるとバッチリ。

しなちくに喋らせたいんですけど

これを名前を付けて保存します。ファイル名はsipc.pyとして下さい。sipc.pyはsipc.dllのPython版みたいなものです。取りあえずはコレを使えばしなちくを操作出来ると思って下さい。

では、最初の一歩です。

import sipc

s = sipc.sipc()
s.connect('hello')
s.send('say "Hello, World"')
s.disconnect()
						

上のソースコードを打ち込んで適当に名前を付けて(拡張子はpyです)保存。で、早速実行して見て下さい(sipc.pyは同じディレクトリにおいてください)。しなちくが起動していれば"Hello, World"と喋ります。

※注意 sipc.dllは不要です。というか、同一ディレクトリにsipc.dllがあると動かなくなってしまいます。

しなちくを動かしたり出来ないの?

ここからが、ちょっとプログラマっぽい話になってきます。少し寄り道してウィンドウズの話をします。ウィンドウズでは目に見えるほとんどのモノがウィンドウです。如何にもウィンドウっぽいエクスプローラーはもちろんのこと、メニューやボタン、スクロールバーもみんなウィンドウです(ウィンドウの集合だからWindowsということで・・・)。更に言うと、しなちくも、うさもウィンドウです。で、プログラムからウィンドウを操作するにはウィンドウハンドルというものを使います。車のハンドルとかのハンドルのことです。ハンドルで車を運転するのと同じように、ウィンドウハンドルでしなちくも操作出来るのです。

ウィンドウハンドルってどこにあるの?

Windowsが管理しています。なのでWindowsにしなちくのウィンドウハンドルを貰えばいいです。ここで「しなちくの」というのが問題になってきます。どうやって指定してあげれば良いのでしょうか?、実はウィンドウには個別の型(ウィンドウクラス)があって、それでしなちくを特定出来ます。(一般的には確実な方法ではないのですが、今回は相手がしなちく限定なので良しとしましょう)

早くしなちくを動かせ!

そろそろ退屈しそうなので、手段の話はとっとと切り上げて目的に移ります。まず、ウィンドウクラスですが、しなちくは'Texture0'、うさは'Texture1'です。これは覚えておいてください。では、次のコードを見てみましょう。

import win32con
import ctypes

# Win32API Shortcut
FindWindow = windll.user32.FindWindowA

hShina = FindWindow('Texture0', 0)
hUsa = FindWindow('Texture1', 0)

このFindWindowがその名の通り、ウィンドウハンドルを見つけて来ます。ウィンドウハンドルが手には入ったらこっちのものです。早速動かしたいところですが、まず、画面のどこにいるのか知っておいた方がよいので、その方法から。上のコードに続いて次のコードも入力します。

class Rectangle(Structure):
	_fields_ = [("left", c_int), ("top", c_int), ("right", c_int), ("bottom", c_int)]

rect = Rectangle()
windll.user32.GetWindowRect(hShina, byref(rect))
print 'しなちくは座標(%d,%d)にいます。' % (rect.left, rect.top)

なんだかよく分からないのが色々出てきましたが、Rectangleは左上と右下を持つデータ型で、GetWindowRectにしなちくのウィンドウハンドルとRectangle型の変数を渡すとしなちくの左上と右下の座標が返ってくるのです。この辺は誰が書いても大差が無いのでそのまんま真似して使ってください。

いよいよ移動です。ここでは、うさに画面左上に行って貰いましょう。

windll.user32.SetWindowPos(hUsa, 0, 0, 0, 0, 0, SWP_NOZORER|SWP_NOSIZE)
# 以下、パラメータの説明
# SetWindowPos(ウィンドウハンドル,Z オーダーを決めるためのウィンドウハンドル(今回は気にしないでください),X座標,Y座標,幅,高さ,パラメータの有効無効)
						

これで、うさは画面の左上に移動したはずです。では、移動に使ったSetWindowPosについて見てみましょう。まず注目するのは一番最後のパラメータです。SWP_NOZORDER(Zオーダーは変更しない)、SWP_NOSIZE(ウィンドウサイズは変更しない)が指定されています。このため、2番目、5番目、6番目のパラメータは無視されることになります。なので何を書いても良いので、0としました。有効なのは3番目、4番目で移動先の座標をしていします。左上なので0,0となっています。

サンプルを用意しましたので参考にしてみてください。うさが画面上を回転後、うさ耳になります。

結局、しなちくは動かしませんでした(汗)。

クリックしたときに反応させるようにしたい

SHookの仕組みについて色々書いてます。取りあえず動かしたい人は、ばっさりと飛ばしてサンプルを動かしてみてください。

ここまで、しなちくに行動させるタイミングはプログラム側で持っていましたが、マウスクリックなどの場合は違ってきます。マウスをクリックしたときに動くと言っても、「何時」というのはマウスを握っている人しか分かりません。プログラムとしてはそのときが来るのをずっと待っていなければならないです。

ここでひとつ考えてみます。たとえば、しなちくをクリックしたときに「痛いよ〜」と喋らせるにはどうすればよいでしょうか?具体的なプログラムはさておき、イメージ的にはマウスがクリックされたフラグみたいなのがあって、それがオフの間は何もせずに、オンになったら「say "<c,0>痛いよ〜"」をしなちくへ送ればいいですね。問題はこれを実現する方法です。これもやはりウィンドウズの仕組みが深く関わってきます。

まずは、ウィンドウズがどのようにこれを実現しているかですが、ウィンドウズ用のアプリケーションは大雑把に言うと巨大なループ処理で出来ています。ループの中ではメッセージキューがあって、そこからメッセージを取り出して処理しています。急に知らない単語が飛び出してきましたが、ひとつずつ見ていきます。メッセージは「マウスが移動した」「左ボタンを押された」「ウィンドウサイズが変更された」というような出来事毎に番号が振られていて、それに付加情報(マウスだと座標とか)を併せたものです。取りあえずウィンドウズ上で操作をしたら、その操作に対応する番号が発生するとだけ押さえておいてください。さて、発生したメッセージはどこに行くかというと、メッセージキューに入れられます。キューというのはちょっと特殊な配列のようなもので、入れるときは配列の後ろへ、取り出すときは先頭からというものです。取り出したメッセージはキューから無くなります。マウスを移動して左ボタンをクリックしたとすると、メッセージキューにはマウス移動(WM_MOUSEMOVE)、左ボタンダウン(WM_LBUTTONDOWN)、左ボタンアップ(WM_LBUTTONUP)というメッセージが入ります。ループ処理では入れられた順に処理し、キューが空になると何もすることがない状態になります。

まとめると、まず、自分のアプリケーションにメッセージキューを処理する巨大なループをつくって、しなちくがクリックされたら、メッセージキューにメッセージを入れてもらえればよいわけです。その仕掛けがSHookなのです。

1からプログラムを組もうとすると大変なので簡易ライブラリを用意しました。

sipc.pyはお馴染みですね。winstruct.py、window.py当面、ブラックボックスにしておいてください(Win32APIがわんさか出てきます・・・)。ここではshook.pyとその使い方のサンプルであるshook_test.pyを見てみてください。あと、shipc.py、winstruct.py、window.py、shook.pyと作成するプログラムは一緒にディレクトリに入れる必要があります。

shook_test.pyも少し長くなっているので、もっと単純な例で解説をしますと、

# win32con.WM_LBUTTONDOWNなどの定数を使うのに必要
import win32con
# shook.pyを読み込む
from shook import *

# shookに渡す文字列は他とぶつからなければ何でもよい
sh = shook('任意の文字列')

# メッセージループから呼ばれる関数
def shina_event(hwnd, msg, wparam, lparam):
	# メッセージキューから取り出したメッセージが左ボタンダウンだったら
	if msg == win32con.WM_LBUTTONDOWN:
		sh.say('<c,0>痛いよ〜')
		# プログラム終了
		sh.quit()
	return 0

# texture0(しなちく)へのメッセージを関数shina_eventで処理する
sh.register('texture', '0', shina_event)
# メッセージループ開始
sh.run()
						

上のソースを名前を付けて保存し実行すると、しなちくが左クリックされるのを待ちます。左クリックするとしなちくが喋って終了。(もちろんしなちくが起動してないと動かないです)


お土産


管理人 : mei