GeminiならOSを作れるはず - その２-

# はじめに
こんにちは！
前回、以下の記事で、OSの起動と文字列の表示ができました。
[GeminiならOSを作れるはず - その１-](https://qiita.com/yam_dev/items/b91e49dc9198969ad6b6)

今回は、キーボード入力ができるようにしてみます。

# 要件
- Docker で起動する
- プロンプトを表示する
- キーボード入力を受け付ける

# 完成イメージ

とりあえず文字を入力できればOK

![スクリーンショット 2024-06-23 22.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/28047f2b-e9ad-7d38-8b8b-a5f376cd6407.png)

# 準備

前回の続きになるので、
[GeminiならOSを作れるはず - その１-](https://qiita.com/yam_dev/items/b91e49dc9198969ad6b6)
をご確認ください。

# 実装
前回の続きですが、必要ファイルは全て記載しておきます。

Dockerfile
```dockerfile:Dockerfile
FROM alpine:latest

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

RUN apk update && apk add nasm qemu-system-x86_64 gcc make libc-dev 

ENV PATH="${PATH}:/usr/bin" 

WORKDIR /root/os

CMD ["qemu-system-x86_64", "-vga", "cirrus", "-vnc", ":0", "-k", "ja", "-drive", "format=raw,file=boot.bin", "-drive", "format=raw,file=floppy.img"]

```

boot.asm
```text:boot.asm
[bits 16]
[org 0x7c00]

; --- グローバル変数 ---
cursor_x dw 0  ; カーソルX座標
cursor_y dw 0  ; カーソルY座標
input_buffer db 256 dup(0)  ; 入力バッファ
input_buffer_len dw 0  ; 入力バッファの文字数

start:
    ; レジスタの初期化
    xor ax, ax
    mov es, ax

    ; 画面モードの設定 (80x25 テキストモード)
    mov ah, 0x00
    mov al, 0x03
    int 0x10

    ; プロンプトの表示
    call print_prompt

.loop:
    ; キーボード入力処理
    call handle_keyboard

    jmp .loop 

; --- プロンプト表示 ---
print_prompt:
    mov ah, 0x0e    ; ビデオサービス(テレタイプモード)
    mov bx, 0x0007 ; 文字色(白)
    mov bp, prompt_msg ; メッセージのアドレス
.print_prompt_loop:
    mov al, [bp]     ; 文字を取得
    cmp al, 0       ; 文字列の終端であれば終了
    je .print_prompt_end
    int 0x10        ; 文字を表示
    inc bp          ; 次の文字へ
    jmp .print_prompt_loop
.print_prompt_end:
    ret

; --- キーボード入力処理 ---
handle_keyboard:
    mov ah, 0x00    ; キーボード入力待ち
    int 0x16        ; キーボードBIOS割り込み

    ; スキャンコードをASCIIコードに変換
    mov bl, al      ; スキャンコードを bl に保存
    call scancode_to_ascii

    ; --- キー入力処理 ---
    cmp al, 0x0D  ; Enterキー?
    je .handle_enter
    cmp al, 0x08  ; Backspaceキー?
    je .handle_backspace
    jmp .handle_char

.handle_enter:
    ; コマンド実行処理 (ここではプロンプトを再表示するだけ)
    mov word [cursor_x], 0  ; カーソル位置を先頭に
    inc word [cursor_y]      ; 次の行へ
    mov word [input_buffer_len], 0  ; 入力バッファをクリア

    ; カーソル位置を更新
    mov ah, 0x02     ; カーソル位置設定
    mov bh, 0        ; ページ番号 (通常は0)
    mov dh, [cursor_y]  ; 行番号
    mov dl, [cursor_x]  ; 列番号
    int 0x10

    call print_prompt
    jmp .end_input

.handle_backspace:
    ; バッファから最後の文字を削除
    cmp word [input_buffer_len], 0  ; バッファが空なら何もしない
    je .end_input
    dec word [input_buffer_len]
    mov di, input_buffer
    add di, [input_buffer_len]
    mov byte [di], 0  ; バッファの最後を0でクリア

    ; カーソルを左に移動して文字を削除
    mov al, 0x08  ; Backspace
    int 0x10
    mov al, ' '   ; 空白文字
    int 0x10
    mov al, 0x08  ; Backspace
    int 0x10
    jmp .end_input

.handle_char:
    ; 入力バッファに文字を追加
    mov di, input_buffer
    add di, [input_buffer_len]
    mov byte [di], al
    inc word [input_buffer_len]

    ; 画面に文字を表示
    mov ah, 0x0e    ; テレタイプ出力
    mov bx, 0x0007  ; 属性 (白文字、黒背景)
    int 0x10

.end_input:
    ret


; --- スキャンコード - ASCIIコード 変換テーブル ---
scancode_to_ascii:
    ; 一旦そのまま返す
    mov al, bl
    ret

; --- プロンプトメッセージ ---
prompt_msg:
    db 'user@os> ', 0

; --- 残り部分を0で埋める ---
times 510-($-$$) db 0
dw 0xaa55
```

# 起動してみる

まずはDockerfileをビルド
```bash
docker build -t os-dev .
```

続いてバイナリ変換コマンドの実行

```bash
nasm -f bin boot.asm -o boot.bin
```

コンテナを起動

```
docker run -it -p 5900:5900 -v $(pwd):/root/os os-dev
```

RealVNC Viewer でlocalhost:5900にアクセス

![スクリーンショット 2024-06-23 22.43.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/20924f68-5cea-1e6f-c4c6-f53b5c88dc21.png)

OSが起動し、プロンプトが表示されました！
文字を入力して、Enterを押してみます。

![スクリーンショット 2024-06-23 22.45.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/1140c954-308d-c651-6109-c4bcd9e2eece.png)

入力できました！

![スクリーンショット 2024-06-23 22.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407770/28047f2b-e9ad-7d38-8b8b-a5f376cd6407.png)

まだ、シェルやファイルシステムが入ってないのでコマンドは反応しません。

次のステップをどうするか、Geminiに相談しながら考えます。

# まとめ
今回は、OSを起動し、キーボードからの入力ができるようにしてみました。
私はOS開発の知識が皆無なので、AIの助けが無いと、何もできません。

しかし、AIを活用することで、まずはここまで来れたのです、、そう考えると、凄いですね。

まだまだ準備運動のスタートラインレベルです。
これから少しずつ進めて、OSに軽量なAIを組み込むところまでは行きたいと思います！

みなさんも一緒に頑張りましょう😀