MacOS 環境 - 手書きオペレーティング システム - 39 - Caps キーの応答

大文字キーの応答

1 はじめに

前のセクションで、Shift キーの処理を実装することができました。

このセクションでは、Caps キーの処理方法について説明します。

このキーを押すと、システムに入力された文字の大文字と小文字が切り替わります。

システム起動後のデフォルト入力は大文字なので

このセクションを完了したら、システムのデフォルト文字を小文字に変更します。

Caps キーを押すと、システム文字が自動的に大文字に切り替わります。

Caps キーが押されると、キーボードからシステムに送信されるスキャン コードは 0x3a です。

キーがポップアップすると、キーボードから送信されるブレーク コードは 0xba です

したがって、対応する Caps キー イベントは

キーボード割り込みによって送信された 2 つの値をそれに応じて処理するだけです。

2.コード

現在のキーボードイベント配信ロジックは次のとおりです。

CMain を実行するメイン プロセスは、キー イベントが発生するたびにアクティブ化されます。

この処理では、キーボードデータキューからキーのスキャンコードまたはブレークコードを取り出して判定します。

現在の入力フォーカスがテキスト入力ボックスにある場合、キーに対応する文字がテキスト ボックスに表示されます。

入力フォーカスがコマンド ライン コンソールの場合、メイン プロセスはキーボード スキャン コードをコンソール プロセスの入力キューに入れます。

次に、自分自身を一時停止し、CPU の制御をコンソール プロセスに渡します。

実際、Shift、Caps などの一部の特殊なキーについては、キーのすべてのスキャン コードをコンソール プロセスに渡す必要はありません。

メイン プロセスはこれらのキーストロークを単独で処理できるため、コマンド ライン コンソール プロセスに渡す必要はありません。

そこで、キーが特殊キーかどうかを判断する関数を追加します。

int isSpecialKey(int data) {
    transferScanCode(data);

    if (data == 0x3a || data == 0xba || data == 0x2a || data == 0x36
       || data == 0xaa || data == 0xb6) {
        return 1;
    }

    return 0;
}

キーボードから送信された値がシフトキーのスキャンコードまたはブレークコードに該当する場合(0x2a、0x36、0xaa、0xb6)

または、Caps ボタンのスキャン コードまたはブレーク コード (0x3a、0xa) の場合、関数は 1 を返します。

キーストローク データの配布に問題があることが判明しました。

キーが押されると、キーボード割り込みが呼び出され、キーのスキャン コードがキーボード データ キャッシュ キューに送信されます。

キーボード データ キューにデータが受信されると、メイン プロセスがアクティブ化されます。

メイン プロセスはデータからキーボード データを取得し、現在の入力フォーカスが別のプロセスのウィンドウ内にあるかどうかを判断します。

入力フォーカスがコマンド ライン コンソールにある場合、メイン プロセスはキューから取得したキーボード データをコマンド ライン ウィンドウのプロセス キューに転送します。

それから首を吊るしてください

問題は

キーを押すと 2 つのデータが生成されます

1 つはボタンが押されたときに出力されるスキャン コードで、もう 1 つはボタンがポップアップした後に出力されるブレーク コードです。

したがって、キーイベントを処理するときは、スキャン コードとブレーク コードを同時に処理する必要があります。

しかし、上記の仕組みにより、ボタンが押されると、

メインプロセスはスキャンコードをターゲットプロセスに送信しただけでハングアップし、コードは送信されませんでした。

最後のキー押下のブレーク コードをターゲット プロセスに送信する前に、次のキー押下が発生するまで待つ必要があります。

したがって、ターゲットプロセスがキーボードデータを誤って解釈する可能性が高くなります。

システムを実行しようとして入力フォーカスをコマンド ラインに切り替えた場合

次に、キャップボタンをクリックしてから、他のボタンをクリックします

文字が正しく表示されない場合がありますが、この現象は上記の問題が原因です。

次に、すべてのキー処理を 1 つの機能に集中させます

char  transferScanCode(int data) {
    if (data == 0x2a)  {//left shift key down
        key_shift |= 1;
    }

    if (data == 0x36) {
        //right shift key down 
        key_shift |= 2; 
    }

    if (data == 0xaa) {
        //left shift key up
        key_shift &= ~1;
    }

    if (data == 0xb6) {
       //right shift key up
        key_shift &= ~2;
    }

    //caps lock
    if (data == 0x3a) {
        if (caps_lock == 0) {
            caps_lock = 1;
        } else {
            caps_lock = 0;
        }
    }

    if (data == 0x2a || data == 0x36 || data == 0xaa || data == 0xb6 || 
        data >= 0x54 || data == 0x3a ) {
        return 0;
    }

    char c = 0;

    if (key_shift == 0 && data<0x54 && keytable[data] != 0) {
        c = keytable[data];
        if ('A' <= c && c <= 'Z' && caps_lock == 0) {
            c += 0x20;
        }

    } 
    else if (key_shift != 0 && data < 0x80 && keytable1[data] != 0){
        c = keytable1[data];
    }
    else  {
        c = 0;
    }

    return c;
}

Caps キーが押されていない場合は、まず文字を小文字に変換してからウィンドウ プロセスに返します。

押された場合は、大文字をウィンドウ プロセスに直接返します。

したがって、ウィンドウは文字を表示する前にこの関数を直接呼び出すことができます。

void CMain(void) {
    ...
    for(;;) {
    ....
    else if (key_to == 0) {
               if (transferScanCode(data) != 0 && cursor_x < 144) {
                   boxfill8(shtMsgBox->buf, shtMsgBox->bxsize, COL8_FFFFFF,cursor_x,
                   28, cursor_x + 7, 43);
                   sheet_refresh(shtctl, shtMsgBox, cursor_x, 28, cursor_x+8, 44);
                   char c = transferScanCode(data);
                   char buf[2] = {c, 0};
                   showString(shtctl,  shtMsgBox, cursor_x, 28, COL8_000000, buf);
                   cursor_x += 8;

                   stop_task_A = 1;

                   boxfill8(shtMsgBox->buf, shtMsgBox->bxsize, cursor_c, cursor_x,
                  28, cursor_x + 7, 43);
                  sheet_refresh(shtctl, shtMsgBox, cursor_x, 28, cursor_x+8, 44);
              } 
           } else if (isSpecialKey(data) == 0)  {

                 fifo8_put(&task_cons->fifo, data);
                 if (fifo8_status(&keyinfo) == 0) {             
                     task_sleep(task_a);
                 }
           }

       }
    ....
    }
    ...
}

上記のコードのロジックは、メインプロセスがキーボードデータを取得した後、

現在の入力角度ウィンドウを確認します。入力ウィンドウがコマンド ライン コンソールの場合は、現在のキーが特殊文字かどうかを確認します。

だったら配布する必要ないよ

そうでない場合は、キュー内のすべてのキーストローク データ、つまりスキャン コードとブレーク コードをターゲット ウィンドウのプロセスに配布してから、自分自身をサスペンドします。

そうすることで、前述した問題を防ぐことができます

コマンドラインコンソールウィンドウの文字表示

表示する文字を取得するには、transferScanCode を呼び出す必要もあります。

コードは次のように変更されます

void console_task(struct SHEET *sheet) {
....
    for(;;) {
    ....
    else {
             char c = transferScanCode(i);
             if (cursor_x < 240 && c!=0 ) {
                 boxfill8(sheet->buf, sheet->bxsize, 
                           COL8_000000, cursor_x,
                           28, cursor_x + 7, 43);
                 sheet_refresh(shtctl, sheet, cursor_x, 28, 
                 cursor_x+8, 44);

                 char s[2] = {c, 0};
                 showString(shtctl, sheet, cursor_x, 28, 
                 COL8_FFFFFF, s);
                 cursor_x += 8;
        }
    ....
    }
....
}

上記のコードをコンパイルした後、システムは大文字と小文字を切り替えることができます。

上記のコードを実行してCapsキーをクリックすると、確かに正常に大文字と小文字を切り替えることができます。

しかし、問題があります。Caps キーをクリックしても、その隣のインジケーター ライトが点灯しません。

インジケーター ライトを点灯するには、システムがキーボード ポートにデータを書き込む必要があります。

これを行うには、コードの複雑さをできるだけ減らすために、大量のコードが必要になります。

私はまだ気づいていませんが、興味のある学生は自分で試してみてください。

3. コンパイルして実行する

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/w776341482/article/details/128660752
おすすめ