このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
次に、メッセージを読み出し、
RFBDisplay 実装クラスに転送するクラスを作る。
このクラスは各種ハンドシェイクの後に実行される
主処理として、RFBHandler を実装することにする。
========== MessageDispatcher.java ==========
package jp.loafer.rfb.server;
import java.io.IOException;
import jp.loafer.rfb.RFBContext;
import jp.loafer.rfb.RFBHandler;
import jp.loafer.rfb.io.RFBInputStream;
import jp.loafer.rfb.io.RFBOutputStream;
import jp.loafer.rfb.message.ClientInitMessage;
import jp.loafer.rfb.message.PixelFormat;
import jp.loafer.rfb.message.ServerInitMessage;
import jp.loafer.rfb.message.client.*;
/**
* クライアントメッセージを読み取って転送するクラス。
* @author kes
*/
public class MessageDispatcher implements RFBHandler {
/**
* {@link MessageDispatcher} のインスタンスを作成。
* @param display 仮想画面。
*/
public MessageDispatcher(RFBDisplay display) {
if (display == null) throw new NullPointerException();
this.display = display;
}
/**
* @see RFBHandler#execute(RFBContext, RFBInputStream, RFBOutputStream)
*/
public void execute(RFBContext context, RFBInputStream in,
RFBOutputStream out) throws IOException {
// 初期化メッセージを交換
{
// ClientInit
/* ClientInitMessage client = */
in.readMessage(context, ClientInitMessage.class);
// TODO: 共有接続のフラグによって挙動を変える
// ServerInit
int width = display.getWidth();
int height = display.getHeight();
PixelFormat format = display.getDefaultPixelFormat();
String name = display.getName();
ServerInitMessage message
= new ServerInitMessage(width, height, format, name);
out.writeMessage(context, message);
out.flush();
}
// 画面を初期化
display.initialize(context, out);
// メッセージループへ
for (;;) {
// メッセージを受け取り
ClientMessage message = getMessage(context, in);
// 送り出す
dispatchMessage(message);
}
}
// ストリームよりクライアントメッセージを読み出す
protected ClientMessage getMessage(
RFBContext context, RFBInputStream in) throws IOException {
// 1 バイト先読み
in.mark(1);
int type = in.readU8();
in.reset();
Class<? extends ClientMessage> messageClass;
switch (type) {
case ClientMessage.SET_PIXEL_FORMAT:
messageClass = SetPixelFormatMessage.class;
break;
case ClientMessage.FIX_COLOR_MAP_ENTRIES:
messageClass = FixColorMapEntriesMessage.class;
break;
case ClientMessage.SET_ENCODINGS:
messageClass = SetEncodingsMessage.class;
break;
case ClientMessage.FRAMEBUFFER_UPDATE_REQUEST:
messageClass = FramebufferUpdateRequestMessage.class;
break;
case ClientMessage.KEY_EVENT:
messageClass = KeyEventMessage.class;
break;
case ClientMessage.POINTER_EVENT:
messageClass = PointerEventMessage.class;
break;
case ClientMessage.CLIENT_CUT_TEXT:
messageClass = ClientCutTextMessage.class;
break;
default:
throw new IOException("unknown client message.");
}
return in.readMessage(context, messageClass);
}
// クライアントメッセージを処理し、振り分ける
protected void dispatchMessage(ClientMessage message) throws IOException {
switch (message.getType()) {
case ClientMessage.SET_PIXEL_FORMAT:
{
SetPixelFormatMessage m = (SetPixelFormatMessage)message;
display.handleSetPixelFormat(m);
}
break;
case ClientMessage.FIX_COLOR_MAP_ENTRIES:
{
FixColorMapEntriesMessage m
= (FixColorMapEntriesMessage)message;
display.handleFixColorMapEntries(m);
}
break;
case ClientMessage.SET_ENCODINGS:
{
SetEncodingsMessage m = (SetEncodingsMessage)message;
display.handleSetEncodings(m);
}
break;
case ClientMessage.FRAMEBUFFER_UPDATE_REQUEST:
{
FramebufferUpdateRequestMessage m
= (FramebufferUpdateRequestMessage)message;
display.handleFramebufferUpdateRequest(m);
}
break;
case ClientMessage.KEY_EVENT:
{
KeyEventMessage m = (KeyEventMessage)message;
display.handleKeyEvent(m);
}
break;
case ClientMessage.POINTER_EVENT:
{
PointerEventMessage m = (PointerEventMessage)message;
display.handlePointerEvent(m);
}
break;
case ClientMessage.CLIENT_CUT_TEXT:
{
ClientCutTextMessage m = (ClientCutTextMessage)message;
display.handleClientCutText(m);
}
break;
default:
// 未知のメッセージはそのまま渡す
display.handleCustomMessage(message);
}
}
private RFBDisplay display;
}
========== end of MessageDispatcher.java ==========
MessageDispatcher クラスの execute メソッドは、
無限ループとなっているため戻ってこない。
といっても、例外を発生させれば脱出は可能だ。
その代わり、読み取ったメッセージは、
コンストラクタで受け取った RFBDisplay に転送される。
このクラスを利用すると、処理の流れを手続き型から、
イベント駆動型に変更する事ができるというわけだ。