em1keyの定義記述法メモ&変数と命令の絡み方メモ、第2回。

(過去:em1keyの定義記述法メモ&変数と命令の絡み方メモ。)
(過去:NICOLA(というか、同期シフト方式)にも「シフト残り現象」がある……のかもしれない。)
(原典: http://flatlib.main.jp/dench/vec/more/em1keyscript.txt )


 前回ほったらかしていた、いくつかの命令についてメモしてみることにします。
 「インプットした分だけアウトプットして、はじめて理解できる」の法則(?)に従い、ドキュメントに書かれていた記述を「自分流で理解しやすいように」書き換えただけの代物です^^;。
 今日のお題は「時刻管理と分岐」ですね。
 em1keyで使う時刻管理の方法は「リセットスイッチつきのストップウオッチ」ではなくて、「普通の時計と、時刻&押したキーを記録する筆記具」をイメージすると良さそう。
 分岐命令はたくさんあるのですが、そのうちのいくつかは「演算+基本分岐命令」なので……ひとまず【 IF_TRUE / IF_FALSE / IF DOWN / IF_UP 】の挙動を理解できるかどうかを確認して、それから他の分岐命令に手を出すほうが良さそうです。

  • SETHELP 0〜5
    • ヘルプ(設定ダイアログ)画面に表示するテキストを用意するコマンド。
    • SETHELP 0 はスクリプトのタイトルを格納する。
    • SETHELP 1〜5 は、設定ダイアログの1〜5行目に表示する文字列を格納する。
    • 「%d」などのフォーマットを使うと、順にVAR0〜VAR3の値を表示できる。
    • 以下はスクリプトの例。VAR0〜3を一旦スタック(VAR48以降)に退避している点に注意。
      • #VAR0〜4の保護
      • PUSHVAR 0 #VAR0をスタックに退避→スタックの中身は【VAR0】になる。
      • PUSHVAR 1 #VAR1をスタックに退避→スタックの中身は【VAR1,VAR0】になる。
      • PUSHVAR 2 #VAR2をスタックに退避→スタックの中身は【VAR2,VAR1,VAR0】になる。
      • PUSHVAR 3 #VAR3をスタックに退避→スタックの中身は【VAR3,VAR2,VAR1,VAR0】になる。
      • #【PUSHスタックはVAR0〜4の保護用に使用されているので、以下でスタックを使う場合は戻し忘れないように注意】
      • LOADVAR ※※※※※
      • STOREVAR 0 #元のVAR0は退避済みなので、ここで代入しても大丈夫。
      • LOADVAR ※※※※※
      • STOREVAR 1 #元のVAR1は退避済みなので、ここで代入しても大丈夫。
      • LOADVAR ※※※※※
      • STOREVAR 2 #元のVAR2は退避済みなので、ここで代入しても大丈夫。
      • LOADVAR ※※※※※
      • STOREVAR 3 #元のVAR3は退避済みなので、ここで代入しても大丈夫。
      • string 0 "VAR0=%d , VAR1=%d , VAR2=%d , VAR3=%d"
      • SETHELP 1 #ヘルプ画面の1行目にSTRING(0)を押し込む処理。
      • #VAR0〜4の復帰
      • POPVAR 3 #VAR3をスタックから復帰→スタックの中身は【VAR2,VAR1,VAR0】になる。
      • POPVAR 2 #VAR2をスタックから復帰→スタックの中身は【VAR1,VAR0】になる。
      • POPVAR 1 #VAR1をスタックから復帰→スタックの中身は【VAR0】になる。
      • POPVAR 0 #VAR0をスタックから復帰→スタックの中身は【空】になる。
    • この処理は、oyayubiwmで「ローマ字入力親指シフト入力の打鍵数差を表示するため」に使われているので、向こうのスクリプトを見るほうが良いかも。
  • SAVETIME 0(=VAR33)
    • タイマーの初期化……ではなくて、現在時刻を保存。引数は無視される。
    • SAVETIME 0で取得したVAR33を「どこかに退避」してからSAVETIME 0しなおすことにより、「前に取得した時刻を捨てることなく」VAR33に新しく時刻を代入できる……のかも?そうであれば、複数の時刻情報を保持できるのかもしれない。
    • この解釈が正しければ、親指シフトの同時打鍵ロジックを(タイムアウト処理のリアルタイム反映を除けば)厳密に再現できるし、既に必要性が出始めている「親指キー共用での【シフト残り】対策済み同時打鍵ロジック」を作成・検証するためにも使える。
    • 時刻情報を「複数」使う複雑なロジックの場合、へたをすると「IF_DIFFTIMEとSETDIFFTIMEを使わずに」、自前で比較処理を書くほうが良い可能性もある……のかも。
    • ちなみに、キーイベント発生時刻は毎回VAR38に上書き保管されるので、場合によってはここから拾うほうが処理的には楽かもしれない。
    • たとえば文字のイベントは毎回VAR38から拾って、シフトのイベントはSETTIME 0経由でVAR33に保管しておいて……という使い方も、あるいはありなのかもしれない。
    • あるいは「タイムアウト判定」だけをSETTIME 0に頼って、文字もシフトも時刻情報はVAR38経由で拾うとか。
  • SETDIFFTIME 0〜255(=VAR34(msec)/40、これは関数番号ではなく40ミリ秒単位系の値)
    • タイムアウトなどを判定するために使う値……なのだけれど、一定時刻ごとに特定の関数を呼び出す仕掛けは(em1keyには)なかったはずなので、「関数を呼び出した時点でタイムアウトか否かを判定するために使う」ことになるはず。
    • 指定値の単位系は「40ミリ秒」なので、目的とする数値を秒数で指定したい場合は「秒数を25倍した数」か「ミリ秒を40で割った数」で指定する。
    • 値はVAR34に保存されていて、こちらではミリ秒に変換した後の数字が保管されている。
    • SETDIFFTIME に指定する値を、そのつど定数で指定するか、あるいはVAR34を毎回書き換えることにより、複数のタイムアウト値を設定できる……と。
    • タイムアウトだけでなく、同時打鍵判定時間を指定するためにも使う。
    • SETVAR0〜3やIF_VSTATE0〜3と同じく、複数の処理をまとめた命令。
  • IF_DIFFTIME 0〜255(←これは関数番号ではなくラベル番号)
    • VAR33の値(≒SAVEATIMEで保存した時刻)にVAR34の値(≒SETDIFFTIMEで保存したミリ秒の値)を加算して、その結果である「過去の時間+差分時間」と「現在の時刻」を比較する……「現在の時刻」が大きければ、指定したラベル番号に跳ぶ。
    • 加算ではなく減算する……とかいう特異な処理をする場合は、この命令を使わず素直にステートを組み合わせて記述するしかない。
    • 現在の時刻は当然弄れないが、VAR33とVAR34は直前に自由に内容を差し替えておけるはず。
    • SETVAR0〜3やIF_VSTATE0〜3と同じく、複数の処理をまとめた命令。
  • IF_TRUE 0〜255(←これは関数番号ではなくラベル番号)
    • カレントレジスタがゼロ「ではない」ならば、同じ関数内の指定ラベルに飛ぶ。
    • TESTなんとか命令系と組み合わせたり、演算系命令と組み合わせると幸せになれる。
  • IF_FALSE 0〜255(←これは関数番号ではなくラベル番号)
    • カレントレジスタがゼロ「である」ならば、同じ関数内の指定ラベルに飛ぶ。
    • TESTなんとか命令系と組み合わせたり、演算系命令と組み合わせると幸せになれる。
  • IF_DOWN 0〜255(←これは関数番号ではなくラベル番号)
    • イベントドリブンな TABLE_DEFAULT関数群 と TABLE_EXT関数群 は、DEFAULT群とEXT群のどちらが呼ばれるのかはSETTABLEで指定できるのに対して、キーUp/Downに関しては「キーUpでもキーDownでも同じ関数が呼ばれる」設計なので、キーUpとキーDownを別々に処理したい入力法で使う場合には、関数内でこの命令を使って特定のラベルへと分岐する必要がある。
    • 他の関数を直接呼び出すわけではないので、それが必要な場合には分岐先で必要な関数を呼び出すこと。
  • IF_UP 0〜255(←これは関数番号ではなくラベル番号)
    • イベントドリブンな TABLE_DEFAULT関数群 と TABLE_EXT関数群 は、DEFAULT群とEXT群のどちらが呼ばれるのかはSETTABLEで指定できるのに対して、キーUp/Downに関しては「キーUpでもキーDownでも同じ関数が呼ばれる」設計なので、キーUpとキーDownを別々に処理したい入力法で使う場合には、関数内でこの命令を使って特定のラベルへと分岐する必要がある。
    • 他の関数を直接呼び出すわけではないので、それが必要な場合には分岐先で必要な関数を呼び出すこと。
  • IF_VSTATE0 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTVSTATE 0」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_VSTATE1 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTVSTATE 1」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_VSTATE2 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTVSTATE 2」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_VSTATE3 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTVSTATE 3」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_CTRL 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTGSTATE 0」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_SHIFT 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTGSTATE 1」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_RWIN 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTGSTATE 2」→「IF_TRUE」の省略形、カレントレジスタを汚さない。
  • IF_GSTATE3 0〜255(←これは関数番号ではなくラベル番号)
    • 「TESTGSTATE 3」→「IF_TRUE」の省略形、カレントレジスタを汚さない。


 うーん……はじめは

  • 「TABLE_DEFAULT」+「TABLE_EXT」=「TABLE_ALLMODE」

が成立するならば、

  • 「TABLE_DEFAULT_DOWN」+「TABLE_DEFAULT_UP」=「TABLE_DEFAULT」
  • 「TABLE_EXT_DOWN」+「TABLE_EXT_UP」=「TABLE_EXT」

があってもいいのかな……と思っていたのですが、よくよく考えてみると

  • 「ほにゃらら_DOWN」+「ほにゃらら_UP」=全く同じ内容にはならない

ので、結局は一つの関数内でDownとUpを(ラベルで分岐しつつ)処理するほうが、よほどシンプルになるんですね……なるほど。