自作OSに挑戦する日記 24日目

 「30日でできる!OS自作入門」を読んで分かったことや、とりあえず書いておきたいことなどを書いていきます。
 この本はChapterが1から30まであるので、各チャプター毎に1記事書いていきます。

Chapter 24 「ウィンドウ操作」

今回やった内容

  • ウィンドウ関連
  • タイマAPI

環境

作業記録

実装回!!!

ウィンドウ関連

ウィンドウ切り替え1

 Shift + CTRL で一番下にあるウィンドウを最前面表示するようにします。これに合わせてアプリ強制終了コマンドを Shift + BackSpace にしました。

/* bootpack.c */

// 一番下のウィンドウを一番上に引っ張り上げる (ctrl + shift)
if(data == 256 + 0x1d && key_shift){
    sheet_updown(sheet_ctl->sheets[1], sheet_ctl->top - 1);
}

ウィンドウ切り替え2 & 移動

 マウス左クリック時に登録されているウィンドウを上から見ていき、マウスの座標と重なっているものがあればそのウィンドウを最前面表示するようにします。
 加えて、ウィンドウのタイトル部分をクリックしていた場合はウィンドウ移動モードに移行し、マウスの動きに合わせてウィンドウ座標を変更するようにします。

/* bootpack.c */

// 左クリック
if((mdec.btn & 0x01) != 0){
    if(win_move_x < 0){
    // 上からウィンドウを見ていく…
    for(int sheet_idx = sheet_ctl->top - 1; sheet_idx > 0; -- sheet_idx){
        struct SHEET *sheet = sheet_ctl->sheets[sheet_idx];
        select_sheet = sheet;
        int x = mouse_x - sheet->vram_x;
        int y = mouse_y - sheet->vram_y;

        // ウィンドウをクリックした
        if(0 <= x && x < sheet->buf_width && 0 <= y && y < sheet->buf_height){
            if(sheet->buf[sheet->buf_width * y + x] != sheet->col_inv){
            // ウィンドウを上に持ち上げる
            sheet_updown(sheet, sheet_ctl->top - 1);
        }
    }
}

 ちゃんと動きます〜!

ウィンドウをマウスで閉じる

 ウィンドウ右上にある「×」ボタン(の表示)をクリックすることでアプリを強制終了できるようにします。強制終了コマンドと同じように EIP を強制的に書き換えることで end_app を実行するようにします。

/* bootpack.c */

// ウィンドウを閉じる(=強制終了)
if(sheet->buf_width - 21 <= x && x < sheet->buf_width - 5 && 5 <= y && y < 19){
    if((sheet->flags & 0x10) != 0){
        struct CONSOLE *console = (struct CONSOLE *)*((int *) 0xfec);
        console_putstr(console, "\nExit\n");
        io_cli();
        task_console->tss.eax = (int) &(task_console->tss.esp0);
        task_console->tss.eip = (int) end_app;
        io_sti();
    }
}

キー入力対象ウィンドウを切り替える

 今までは Tab を押すことでミニ入力ウィンドウとコンソールを行ったり来たりしていたのですが、使い心地が悪くなってきたので(アプリも実行できるようになったので…)別の方法で入力対象ウィンドウを切り替えれるようにします。

 key_to 変数で01を管理するのではなくkey_to_window 変数に入力対象ウィンドウ(シート)を持っておいて、この変数を元にに切り替えなどができるようにします。   ウィンドウクリックまたは Tab を入力することで key_window_on / key_window_off を呼び出すようにします。この関数内で入力切り替え処理やタイトル更新処理を行わせます。

/* bootpack.c */

// 指定ウィンドウを入力モードにする
int key_window_on(struct SHEET *key_to_window, struct SHEET *sheet_window, int cursor_color, int cursor_x){
    // タイトル更新
    change_window_title(key_to_window, 1);

    // カーソル制御
    if(key_to_window == sheet_window){
        cursor_color = COL8_000000;
    }else{
        if((key_to_window->flags & 0x20) != 0){
            fifo32_put(&key_to_window->task->fifo, 3);
        }
    }

    return cursor_color;
}

// 指定ウィンドウを入力モード解除する
int key_window_off(struct SHEET *key_to_window, struct SHEET *sheet_window, int cursor_color, int cursor_x){
    // タイトル更新
    change_window_title(key_to_window, 0);

    // カーソル制御
    if(key_to_window == sheet_window){
        cursor_color = -1;
        boxfill8(sheet_window->buf, sheet_window->buf_width, COL8_FFFFFF, cursor_x, 28, cursor_x + 7, 43);
    }else{
        if((key_to_window->flags & 0x20) != 0){
            fifo32_put(&key_to_window->task->fifo, 2);
        }
    }

    return cursor_color;
}

タイマAPI

 アプリからもタイマを使えるようにします。…基本的な実装は既にOS側で行われているので、APIはOS内の関数を代わりに読んであげる程度の動きしかしません。
 また、TIMER構造体に flags_auto_cancel を持たせることで取り残されたタイマを自動終了させれるようにします。これでアプリがタイマを取り消さずに終了してしまった場合でもOSに影響が出ません。安心。

/* api.c */

if(edx == 16){      // タイマ取得
    reg[7] = (int) timer_alloc();
    ((struct TIMER *) reg[7])->flags_auto_cancel = 1;
    return 0;
}

if(edx == 17){      // タイマ初期化
    timer_init((struct TIMER *) ebx, &task->fifo, eax + 256);
    return 0;
}

if(edx == 18){      // タイマ時間設定
    timer_set((struct TIMER *) ebx, eax);
    return 0;
}

if(edx == 19){
    timer_free((struct TIMER *) ebx);
    return 0;
}

 …ということで完成した24日目がこちらです。

 タイマやウィンドウ操作などちゃんと動いています!

まとめ

 前回に引き続き実装回でした。 実装回は楽に進めることが出来ますが、そろそろ新しい機能を実装したい気持ちが…!