- []
- [以前のリビジョン]
待つということ
シナリオ解析の停止
KAGシナリオの処理のページで、コンダクタの説明を行いました。文字描画の際には文字描画速度(wait)の分だけ、タグでは基本0の間隔でgetNextTagを呼んでいました。それを制御していたのがタイマです。
KAGシステムで、コンダクタが次々とタグを処理していっている状態を走行状態といいます。それに対してsタグ、lタグ、pタグが呼ばれたときになる状態を安定状態といいます。
sタグのハンドラは、スキップを止めたりして安定状態としてあるべき状態にしたのち、-1を返してます。-1を返されると、コンダクタはタイマを無効にします。つまり、次のタグを解析して実行しようとしなくなります。リンクなどによって再びシナリオを解析する段階になると、またタイマを有効にして解析していきます。
// kag3/templete/system/MainWindow.tjs
4892: s : function(elm)
4893: {
4894: // 実行停止
4895: stablePosibility = true;
4896: cancelSkip();
4897: if(!usingExtraConductor) incRecordLabel(true);
4898: inSleep = true;
4899: if(recordHistoryOfStore == 2) // 2 : 選択肢 ( @s タグ ) ごと
4900: setToRecordHistory();
4901: notifyStable();
4902: return -1;
4903: } incontextof this,// kag3/templete/system/Conductor.tjs
0103: // onTag を呼ぶ
0104: var step = onTag(obj);
0105: if(step === void)
0106: throw new Exception("onTag が void を返しました (" + obj.tagname + ")"
0107: "( おそらくタグハンドラの戻り値を返し忘れた )");
0108: step = int step; // step を数値に
0117: switch(step)
0118: {
0145: case -1: // シナリオ終了
0146: timer.interval = 0;
0147: timer.enabled = false;
0148: timerEnabled = false;
0149: onStop();
0150: inProcessing = false;
0151: reentered = false;
0152: return;
0153: }
0154: }
クリック待ち
sタグのように完全にシナリオを停止するのではなく、lタグやpタグのようなクリック待ちはどのようになっているでしょうか。
lタグはkag.showLineBreakメソッドを呼び出し、前半部分はスキップモードやオートモードでのlタグの振る舞いを記述しています。ここでは割愛させていただきます。重要なのは4068行目からのconductor.waitの部分と、4079行目で-2を返していることです。
// kag3/templete/system/MainWindow.tjs
4753: l : function(elm)
4754: {
4755: // 行クリック待ち
4756: return showLineBreak(elm);
4757: } incontextof this,
4035: function showLineBreak(elm)
4036: {
4037: // 現在のメッセージレイヤに行待ち記号を表示する
4038: stablePosibility = true;
4039: if(canIgnoreL())
4040: {
4041: // l タグの無視
4042: if(elm.canskip === void || !+elm.canskip)
4043: return (skipMode==3 || skipMode==4) ? 0 : -4;
4044: }
4045: if(autoMode)
4046: {
4047: // 自動読みすすみの場合
4048: return autoModeLineWait;
4049: }
4050: if(skipMode == 1) cancelSkip();
4051: if(skipMode == 4 && !skipKeyPressing()) cancelSkip();
4052: if(skipMode == 4) return -4;
4053: if(skipMode) return skipCancelKeyPressing()?-4:0;
4054: // スキップ中(スキップをキャンセルするようなキーがあればスキップ解除
4055: // のためのイベント処理の機会を与える)
4056:
4057: current.showLineBreakGlyph(lineBreak);
4058: storeClickGlyphState("line");
4059:
4060: if(!current.nodeVisible)
4061: {
4062: dm("警告 : 非表示になっている" +
4063: (currentPage ? "裏" : "表") + "メッセージレイヤ" + currentNum +
4064: "で行クリック待ちになりました");
4065: }
4066:
4067: // conductor を 'click' まで待ち状態に
4068: conductor.wait(%[
4069: click : function
4070: {
4071: clickWaiting = false;
4072: fore.base.cursor = cursorDefault;
4073: notifyRun();
4074: } incontextof this
4075: ]);
4076: clickWaiting = true;
4077: fore.base.cursor = cursorWaitingClick;
4078: notifyStable();
4079: return -2;
4080: }
タグハンドラで-2を返すと、タイマの間隔を0にします。タイマは間隔が0になると、動作を中断します。つまり、完全に停止したわけではないですが、休止状態になります。intervalを正数にすると再び動き出します。
// kag3/templete/system/Conductor.tjs
0115: else if(step < 0)
0116: {
0117: switch(step)
0118: {
0140: case -2: // ブレーク
0141: timer.interval = 0; // タイマは停止
0142: inProcessing = false;
0143: reentered = false;
0144: return;
conductor.waitメソッドは以下のようになっています。-2を返すだけでもコンダクタの中断を意味していますが、conductor.stopメソッドによりタイマを無効にしています。また、untilは%["click" => function{ ... }]のような形式の辞書配列です。そのuntilをconductor.waitUntilにコピーしています。
// kag3/templete/system/Conductor.tjs
0380: function wait(until)
0381: {
0382: // 待ち
0383: // until = trigger で用いるシグナル名とコールバック関数の
0384: // 辞書配列
0385: status = mWait;
0386: stop();
0387: (Dictionary.assign incontextof waitUntil)(until);
0388: }
0239: function stop()
0240: {
0241: // タイマ停止
0242: timer.enabled = false;
0243: timerEnabled = false;
0244: }
一方、実際にクリックされるとどういった処理がされるのでしょうか。クリックはもちろんのことエンターキーが押されるなど、内部的にクリックとみなされます。
ちょーかきかけ
// kag3/templete/system/MainWindow.tjs
3730: function onPrimaryClick()
3731: {
3732: // プライマリレイヤで「クリックの動作」がなにもフィルタリングされなかった
3733: // とき、プライマリレイヤから呼ばれる。
3734: clickCount ++;
3735: if(!callHook(leftClickHook))
3736: {
3737: if(messageLayerHiding)
3738: {
3739: showMessageLayerByUser(); // メッセージレイヤを表示する
3740: }
3741: else
3742: {
3743: var st = conductor.status;
3744: var runst = conductor.mRun;
3745: var stopst = conductor.mStop;
3746:
3747: if(st != stopst && autoMode)
3748: {
3749: // 自動読みすすみの場合
3750: cancelAutoMode();
3751: }
3752: else if(st != stopst && canCancelSkipByClick && skipMode && skipMode != 4)
3753: {
3754: // クリックによるスキップの解除が可能
3755: cancelSkip();
3756: }
3757: else
3758: {
3759: // この時点でフィルタリングされないメッセージは待ち状態のクリアなので
3760: // conductor に 'click' を送り解除を伝える。
3761:
3762: if(!conductor.trigger('click')) // 待ち状態でない場合は単に無視される
3763: {
3764: // ハンドラが見つからないなど、処理されなかった場合
3765: if(st == runst && clickSkipEnabled && skipMode == 0)
3766: {
3767: // クリックによるスキップが可能
3768: skipToClick();
3769: }
3770: }
3771: }
3772: }
3773: }
3774: }

