KEY_DOWNとCHANGEのThreadへの影響

「同一関数内でevent関数を使って同じオブジェクトに対してKeyboardEvent.KEY_DOWNとEvent.CHANGEをlistenすると、KEY_DOWNしか呼ばれない」という、そうめんをやってきた中で一番困る現象がある。
これの解決法は、KEY_DOWNとCHANGEをlistenするThreadを別々にすることぐらいしかないのだが、*1KEY_DOWNのハンドラとCHANGEのハンドラを別々にしてしまうと、内部変数を共有させたいときにいろいろ面倒になる。*2なんとかハンドラたちだけは同じThread内で扱えないかなーと考えていた。

ハンドラたちを含むThreadをメイン、そうでない方をサブとすると、サブからメインのハンドラを呼べばメインの該当ハンドラのアクセス子をinternalにして、nextをサブ側に書くだけで済む。

public class MainThread extends Thread
{
	private var sub : SubThread;

	public function MainThread()
	{
		sub = new SubThread(this);
	}

	protected override function run() : void
	{
		sub.start();
		waitEvents();
	}

	private function waitEvents() : void
	{
		event(nanika, Event.CHANGE, onChange);
	}

	private function onChange(e : Event) : void { ...; next(waitEvents); }
	internal function onKeyDown(e : KeyboardEvent) : void { ...; }
}
public class SubThread extends Thread
{
	private var main : MainThread;

	public function SubThread(main : MainThread)
	{
		this.main = main;
	}

	protected override function run() : void
	{
		event(nanika, KeyboardEvent.KEY_DOWN, onKeyDown);
	}

	private function onKeyDown(e : KeyboardEvent) : void
	{
		main.onKeyDown(e);
		next(run);
	}
}

だいたいこんな感じ。ここまでくるとSubThreadがずいぶん簡単な構造になっていることに気づく。そこでそれを抽象化してEventThreadというのをつくってみた。

public class EventThread extends Thread 
{
	private var targ : EventDispatcher;
	private var type : String;
	private var func : Function;
		
	public function EventThread(targ : EventDispatcher, type : String, func : Function) 
	{
		this.targ = targ;
		this.type = type;
		this.func = func;
	}
		
	protected override function run() : void
	{
		event(targ, type, onEvent);
	}
		
	private function onEvent(e : Event) : void
	{
		func.apply(null, [e]);
		next(run);
	}
		
	protected override function finalize() : void
	{
		targ = null;
		type = null;
		func = null;
	}
}

funcはメインのほうで作られるので、もはやMainThreadをメンバとして持つ必要がない。そして上の例のinternal MainThread.onKeyDownはprivateで良くなる。

だがnextは消えたままである。これが気持ち悪いかどうかは人によるが、nextの引数にEventThreadの待機用関数を指定できればいい、という考え方をすると、

public class EventThread2 extends Thread 
{
	private var targ : EventDispatcher;
	private var type : String;
	private var func : Function;
		
	public function EventThread2(targ : EventDispatcher, type : String, func : Function) 
	{
		this.targ = targ;
		this.type = type;
		this.func = func;
	}
	
	protected override function run() : void
	{
		waitEvents();
	}
	
	public function waitEvents() : void
	{
		event(targ, type, func);
	}
	
	protected override function finalize() : void
	{
		targ = null;
		type = null;
		func = null;
	}
}

として、onKeyDownの最後にnext(sub.waitEvents); を加えればよい。こっちのほうがコード量は小さいし、いいとは思う。*3

*1:前エントリのundoでも分けていた。

*2:共有する変数をinternalにしたり、コンストラクタでメインを渡してそこ経由でアクセスするようにしたり。

*3:最初FunctionThreadで実装しようかと思ったけれど、ぎりぎり無理だった