30日OS自作入門24日目(Win10)

はじめに

目次

ウィンドウの操作

ウィンドウの切り替え(1)(harib21a)

ウィンドウがいろいろ出せるようにはなったわけですが、一番上のウィンドウがアプリのものしか出せずにtask_aが見えないし、コンソールも見えずらいという状況です。それを解消するために、ウィンドウのレイヤーを入れ替えるコマンドを実装するようです。ここで、一瞬console.cをいじるかと思いましたが、console.cの内容でなく、HariMainの内容なのでbootpack.cですね(APIと勘違いしていた…)。

修正する箇所は、ほんと少なかったようです。

if (i == 256 + 0x57 && shtctl->top > 2) {   /* F11+下敷きが2枚以上 */
    sheet_updown(shtctl->sheets[1], shtctl->top - 1);   /* arg1:背景の一個上の下敷き、arg2:マウスの一個下の下敷き */

これだけのようで、下敷きの枚数を確認してF11コマンドを受け入れた後、マウスと背景を除いた下敷きを操作しているようです。

実行してみると

ウィンドウの切り替え(2)(harib21b)

今度は、クリックで対応させるようです。仕組みは、マウスと重なっているかつ、透明ではない下敷きを探して、もし見つかればF11 と同じ処理を行うといった仕組みのようです。

if ((mdec.btn & 0x01) != 0) {
    /* 左ボタンを押していたら、sht_winを動かす */
    /* 上の下じきから順番にマウスが指している下敷きを探す */
    for (j = shtctl->top - 1; j > 0; j--) {
        sht = shtctl->sheets[j];
        x = mx - sht->vx0;
        y = my - sht->vy0;
        if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) {
            if (sht->buf[y * sht->bxsize + x] != sht->col_inv) {
              sheet_updown(sht, shtctl->top - 1);
              break;
            }
        }
    }
}

実行すると

ウィンドウの移動(harib21c)

今回は背景とマウス以外の下敷きをすべて移動できるようにしようといった感じのようです。

その際に、通常モードとウィンドウ移動モードの2種類のモードがあると考え、左クリックでモード移行をしています。その際に、フラグとして用いているのはmmxであり、マウスが画面外に行かないのを利用してフラグに兼用しているようです。

実行してみると

ウィンドウをマウスで閉じる(harib21d)

「目の前に×ボタンがある…心が押せと叫んでいる!!!!」といったことに対応するようです(自分で考えておいて意味不明)

とりあえず、ウィンドウ移動のように×ボタンとマウスが重なっている場合に、クリックされたらウィンドウを閉じるようにするようです。
これだと、コンソールとtask_aは反応しないのですが、これはコンソールの強制終了と同じやり方でやっているから反応しないのだと思います。そもそもSHEET内のTASKはアプリケーションを制御するためのものだったはずなので…

実行すると

アプリケーションの入力切り替え(harib21e)

実行すると

入力ウィンドウをマウスで切り替える(harib21f)

修正したコードは以下のようで

if (sht != key_win) {   /* クリックに入力切り替えの紐づけ */
    cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x);
    key_win = sht;
    cursor_c = keywin_on(key_win, sht_win, cursor_c);
}

まず、選択前に点灯していたカーソルを消して、key_winにWindowの管理を渡し選択の青色を点灯させる処理

実行すると

タイマAPI(harib21g)

タイマ関連のコードは

            if (i >= 256) { /* キーボードデータ(タスクA経由) */
                reg[7] = i - 256;
                return 0;   /* 無限ループぬけ */
            }
        }
    } else if (edx == 16) { /* タイマの取得 */
        reg[7] = (int) timer_alloc();
    } else if (edx == 17) { /* タイマの送信データ設定 */
        timer_init((struct TIMER *) ebx, &task->fifo, eax + 256);
    } else if (edx == 18) { /* タイマの時間設定 */
        timer_settime((struct TIMER *) ebx, eax);
    } else if (edx == 19) { /* タイマの解放 */
        timer_free((struct TIMER *) ebx);
    }
    return 0;
}

a_naskは

_api_alloctimer:    ; int api_alloctimer(void);
    MOV     EDX,16
    INT     0x40
    RET

_api_inittimer:    ; void api_inittimer(int timer, int data);
    PUSH    EBX
    MOV     EDX,17
    MOV     EBX,[ESP+ 8]    ; timer
    MOV     EAX,[ESP+12]    ; data
    INT     0x40
    POP     EBX
    RET

_api_settimer:      ; void api_settimer(int timer, int time);
    PUSH    EBX
    MOV     EDX,18
    MOV     EBX,[ESP+ 8]    ; timer
    MOV     EAX,[ESP+12]    ; time
    INT     0x40
    POP     EBX
    RET

_api_freetimer:     ; void api_freetimer(int timer);
    PUSH    EBX
    MOV     EDX,19
    MOV     EBX,[ESP+ 8]    ; timer
    INT     0x40
    POP     EBX
    RET

noodle.cのコードは

void HariMain(void)
{
  char *buf, s[12];
  int win, timer, sec = 0, min = 0, hou = 0;
  api_initmalloc();
  buf = api_malloc(150 * 50);
  win = api_openwin(buf, 150, 50, -1, "noodle");
  timer = api_alloctimer();
  api_inittimer(timer, 128);
  for (;;) {
    sprintf(s, "%5d:%02d:%02d", hou, min, sec);
    api_boxfilwin(win, 28, 27, 115, 41, 7 /* 白 */);
    api_putstrwin(win, 28, 27, 0 /* 黒 */, 11, s);
    api_settimer(timer, 100); /* 1秒間 */
    if (api_getkey(1) != 128) {
      break;
    }
    sec++;
    if (sec == 60) {
      sec = 0;
      min++;
      if (min == 60) {
        min = 0;
        hou++;
      }
    }
  }
  api_end();
}

コードを見るほうがわかりやすいですね。
api_getkeyの512の制限を取っ払ったのは、キーデータ以外も受け取るようにしたからのようですね。api_getkeyというAPIFIFOバッファから流れてきたデータを拾って、条件分岐に従って分類しているわけだからできる芸当ですね。

実行すると

タイマのキャンセル(harib21h)

Cという表示が遅れて表示されてしまっていた不具合を直すようです。
不具合の原因は、タスクにタイマがデータを送っていたわけなのです。しかし、アプリが終了した際にタスクに送るはずだったデータがタスクがないために、コンソールに送られるという不具合が発生していたようです。

実行すると

メモ

・アプリケーションはコンソールの上で動いているので、コンソール上に操作が移っていないと使えない。
struct SHEET *sht = 0;はNULLポインタをしている

最後に

なんか、気力が出ずにから元気でやってしまった感があるので、今後コードを見直したいと思います。