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

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

Chapter 14 「高解像度・キー入力」

今回やった内容

  • 高解像度化
  • キー入力を画面に反映する

環境

作業記録

 今まで320 x 200の画面で開発をしていたのですが、もっと高解像度にします!
 解像度変更は起動時に行い、アセンブリで書きます(久々のアセンブリだ…)。

; VBE存在確認
MOV     AX, 0x9000
MOV     ES, AX
MOV     DI, 0
MOV     AX, 0x4f00
INT     0x10
CMP     AX, 0x004f
JNE     scrn320

; VBEバージョン確認
MOV     AX, [ES:DI + 4]
CMP     AX, 0x0200
JB      scrn320

; 画面モード情報を取得する (指定した画面モードが使えない場合はjmp)
MOV     CX, VBEMODE
MOV     AX, 0x4f01
INT     0x10
CMP     AX, 0x004f
JNE     scrn320

; 画面モード情報を確認する (色数=8? パレットモード使える? 画面モードに0x4000足しても大丈夫?)
CMP     BYTE [ES:DI + 0x19], 8
JNE     scrn320
CMP     BYTE [ES:DI + 0x1b], 4
JNE     scrn320
MOV     AX, [ES:DI + 0x00]
AND     AX, 0x0080      ; bit7にフラグが立っているかどうか
JZ      scrn320

; 画面モード切り替え!
newwindowmode:
        ORG     0xc200
        MOV     BX, VBEMODE + 0x4000   ; VBEの1024x768x8bitカラー
        MOV     AX, 0x4f02
        INT     0x10
        MOV     BYTE[VMODE], 8      ; 画面の設定をメモする
        MOV     AX, [ES:DI + 0x12]
        MOV     WORD[SCRNX], AX
        MOV     AX, [ES:DI + 0x14]
        MOV     WORD[SCRNY], AX
        MOV     EAX, [ES:DI + 0x28]
        MOV     DWORD[VRAM], EAX
        JMP     keystatus

; 解像度を320x200にする
scrn320:
        ORG     0xc200
        MOV     AL, 0x13    ; 320x200x8bitカラー
        MOV     AH, 0x00
        INT     0x10
        MOV     BYTE[VMODE], 8      ; 画面の設定をメモする
        MOV     WORD[SCRNX], 320
        MOV     WORD[SCRNY], 200
        MOV     DWORD[VRAM], 0x000a0000

keystatus:
        MOV     AH, 0x02    ; キーボードの設定をBIOSから教えてもらう
        INT     0x16
        MOV     [LEDS], AL

 高解像にするためにはVBE「VESA BIOS extention (VESA BIOS拡張 : VBE) 」を使う必要があるのですが、もしVBEが使えなかった場合も考えて処理を書いています。

 VBEが使えるかは「存在確認」「バージョン確認」「画面モード情報確認」の3ステップによって確認しています。もしどれか1つでも引っかかった場合には今までのように320 x 200の解像度で起動するようにし、全ての確認をパスした場合にはVBEを使って高解像度に設定するようにしています。

 …ということで高解像度になったHariboteOSくんがこちらです。

 画面が広すぎる…!解像度がか変わっただけですが、これだけでかなり進化したような感じがします。


 高解像度化の次はキー入力です。今まではキー入力を割り込みデータそのままで画面に表示していたのですが、これからは対応表に基づいて表示するようにします。対応表中の「0」は定義されていないキーです。

// 飛んできたデータとキー文字の対応表
char keytable[0x54] = {
    0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0,
    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S',
    'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V',
    'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1',
    '2', '3', '0', '0'
};

 キー文字がちゃんと表示できるようになったので、ウィンドウ内に入力された文字を16文字まで表示できるようなフォームを作成してみます。入力されるたびに cursor_x という変数を変化させることでフォームみたいな動きを再現しています。

while(1){
    io_cli();

    if(fifo32_status(&osfifo) == 0){
        io_stihlt();
    }
    else{
        int data = fifo32_get(&osfifo);
        io_sti();

        if(256 <= data && data <= 511){       // キーボード
            msprintf(s, "%x", data - 256);
            putstr8_ref(sheet_back, 0, 20, COL8_FFFFFF, COL8_008484, s, 2);

            // ウィンドウへの入力
            extern char keytable[0x54];
            if(data < 256 + 0x54 && keytable[data - 256] != 0 && cursor_x < 144){  // 通常文字
                s[0] = keytable[data - 256];
                s[1] = 0;
                putstr8_ref(sheet_window, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);
               cursor_x += 8;
            }
            if(data == 256 + 0x0e && cursor_x > 8){   // BackSpace
                putstr8_ref(sheet_window, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
                cursor_x -= 8;
            }

            // カーソル位置更新して再描画
            boxfill8(sheet_window->buf, sheet_window->buf_width, cursor_color, cursor_x, 28, cursor_x + 7, 43);
            sheet_refresh(sheet_window, cursor_x, 28, cursor_x + 8, 44);
        }
    }
}

 これを実行してみると…

 ちゃんとキー入力が正しく画面に表示され、しかも文字列の入力が可能になっています…!OS感がかなり増しました…

まとめ

 高解像度化とキー入力の実装をしました。13日目から14日目にかけての進化具合が圧倒的すぎる…。