漢字キーを無効化するプログラム

はじめに

パソコンゲームやってると「漢字」キーを押して操作不能になって困るんです、 なんてことありませんか?「ESC」キーに近すぎ!漢字キーは使わないし無効にできたらいいよね。 っていうことで・・・ここでは漢字キーの無効化だけをできるだけ簡単に紹介します。

対象読者

  • ウィンドウズを操作するプログラムを書いてみたい方
  • Visual Studioがインストールされていること
  • ノートパッドが使えること

プログラムを書きながら、コンピュータの仕組みを知るのは楽しいものです。 コンピュータ好き、ゲーム好き、自分でツールを作ってみたい、 そんな方の参考になれば幸いです。

サンプルコード

それでは、早速サンプルコードを見てください。 ファイルはたったの一つだけ!

sample.cpp

#include <windows.h>
#include <stdio.h>

HHOOK hook; // キーボードフックハンドラー

LRESULT CALLBACK proc(int code, WPARAM wp, LPARAM lp)
{
    KBDLLHOOKSTRUCT *info; // キーボード情報へのポインタ
    int vk;                // バーチャルキーコード

    // 無効フックを除外
    if( code < 0 )
        return CallNextHookEx(hook, code, wp, lp);

    // パラメータを解析
    info = (KBDLLHOOKSTRUCT*)lp;
    vk = (*info).vkCode;

    // 漢字キーを無効にする
    if( (vk==0xF3||vk==0xF4) && wp==WM_KEYDOWN ) {
        putchar('*');  // コメ印を表示
        return 1;      // フックチェーンを破棄
    }

    // フックチェーンの継続
    return CallNextHookEx(hook, code, wp, lp);
}

void main(void)
{
    // キーボードをフックする
    hook = SetWindowsHookEx(WH_KEYBOARD_LL, proc, 0, 0);

    // メッセージループを開始
    MSG msg;
    while( GetMessage(&msg, NULL, 0, 0) ) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

キー入力を無効にするには、「グローバルフック」という手法が必要になります。 グローバルフックで検索をかければ、様々なWEBページで紹介されていることがわかります。 それほどよく知られた手法なのですが、その多くはDLLプログラムとメインプログラムの 2つのファイルを必要とする手法です。 また、動作記述がDLL内部で行われていたりと、複雑な記述がほとんどです。 ウィンドウスアプリケーションの仕様上で仕方ないことなのです。

しかし、コンソールアプリケーションに限定すれば、DLLが必要ありません。 つまり一つのファイルで済みます。記述するのはメイン関数と動作記述部の2つの関数だけです。 私が知りうる限り、最も簡単なグローバルフックのサンプルになるのではないでしょうか。

作業手順

とても簡単!説明も楽チン!

スト2コマンドプロンプトの作業状況を示します。 入力は4カ所だけ。入力する部分を赤色で囲ってありますので参考にしてください。

Developer Command Prompt for VS 2022

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.5.1
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
C:\Program Files\Microsoft Visual Studio\2022\Community>cd C:\Users\You\Desktop\work↵

C:\Users\You\Desktop\work>cl sample.cpp user32.lib↵
Microsoft(R) C/C++ Optimizing Compiler Version 19.35.32215 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

sample.cpp
Microsoft (R) Incremental Linker Version 14.35.32215.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:sample.exe
sample.obj
user32.lib

C:\Users\You\Desktop\work>sample↵
********^C
C:\Users\You\Desktop\work>

エンターの入力「↵」マークは表示されません。 「\」は、環境によって円マーク「¥」またはバックスラッシュ「\」で表示されています。 いずれも¥キーで入力できるはずです。

プログラムの開発には、GUIで作られた統合環境(IDE)が強力で効率的です。 しかし、作業手順の説明は複雑になりがちで、設定を間違うと沼にはまります。 ここでは、コマンドプロンプトで作業します。 コマンドを手で入力する必要がありますが、とても簡単なのでチャレンジしてみてください。

手順1.作業フォルダを作ります

デスクトップでマウスを右クリックし、「新規作成」次に「フォルダ」を選びます。 新しいフォルダーの名前を「work」に変更してください。

手順2.ソースファイルを作ります

ノートパッドを開き、リスト1をコピペします。 次に、名前をつけて保存をします。

  • フォルダは先ほど作ったデスクトップ上のworkを指定。
  • 文字コードANSIで指定。
  • ここではファイル名を「sample.cpp」とします。
手順3.コマンドプロンプトを開きます

ここでは、2022年度版のコミュニティーエディションを使っています。 コミュニティーエディションは規約を守ることで無償で使うことができます。

スタートメニューから「Visual Studio 2022」内の 「Deveropper Command Prompt for VS 2022」を開きます。 開かれた窓をクリックして次からのコマンド入力の準備が整います。

手順4.作業フォルダに移動

コマンド cd C:\Users\You\Desktop\work を入力し、作業フォルダに移動します。

例ではユーザー名「You」のデスクトップにフォルダ「work」を作っています。 Youの部分は、環境によって変わりますのであなたの環境に合わせて置き換えてください。

手順5.ビルド

ビルドとは実行ファイルを作成することです。 コマンド cl sample.cpp user32.lib を入力します。 cl は実行ファイルを作成するコマンドで、コンパイルとリンクの略だと思われます。 user32.lib は、今回のビルドに必要なファイルでライブラリと呼ばれています。 うまくいけば実行ファイル sample.exe が作成されているはずです。 なお sample.obj は、中間ファイルという作業ファイルの一つで削除しても問題ありません。

手順6.実行

コマンド sample を入力します(sample.exeでもよい)。 実行中に漢字キーを押すと「*」マークが表示されるはずです。 ノートパッドなどを開いて漢字の入力を試してみてください。 漢字の入力ができなければ成功です。

手順7.終了

コマンドプロンプトを選んでから、^Cを入力します。 組み合わせキー入力で、Ctrlキーを押したままCキーを押すことを示します。

お疲れさまでした!

うまくいかないときは

  • ファイルの文字コードANSIですか?UTF-8になってませんか?
  • VisulaStudio開発用のプロンプトで作業してますか?
  • WindowsやVisualStudioは標準的にインストールされていますか?

用語

イベントとかプロシージャとかフックとかとかとか

ウィンドウズは、アプリケーションをメッセージという仕組みを使って制御しています。 特定のメッセージが発生した時をイベント(event)と呼びます。 イベント発生時に実行する動作を一般的にプロシージャ(procedure)といい、 ユーザーが定義する場合、定められた形式のコールバック関数で記述する必要があります。 コールバック関数を登録しておくことをフック(hook)するといいます。

ローカルフックとグローバルフック

一般的なウィンドウズアプリケーションは自身へのイベントだけしか取得できません。 自身へのイベントの取得を単にフック、区別するならローカルフック(local hook)と呼びます。 これに対して、自分以外のアプリケーションのイベントやシステム全体に渡るイベントにフックする事を グローバルフック(global hook)と呼びます。 グローバルフックを使うことで、他のアプリケーションに送られるイベントを先取りできるようになります。 プログラマが記述したプロシージャによって、他のアプリケーションへの入力を阻害したり、 用意した別の処理を行わせたりすることができるようになるのです。

一般的なウィンドウズアプリケーションでは、グローバルフックを実現するためにDLLを用意します。 DLLをロードするとDLLインスタンスが得られ、 DLLインスタンスを使うことで、システム全体のメッセージをフックできるようになります。 そして、ここで紹介したようにコンソールアプリケーションでは、DLLなしで同様な動作ができるのです。

キーボードの入力メッセージをフック

ここでは「低レベルのキーボード入力」と呼ばれるイベントをグローバルフックしています。 フックは SetWindowsHookEx 関数によって行われ、ID は WH_KEYBOARD_LL を使います。 IDを変えることで、例えばマウスの動作など様々なメッセージに対応できます。 戻り値(HHOOK hook)はメイン関数とコールバック関数で必要なため、グローバル変数にしました。

コールバック関数は、LowLevelKeyboardProc に示された仕様に厳密に従います。 システムで管理されていますので、その点はユーザーの自由に作れる関数と異なります。 関数名は自由なので短く proc としています。

参考ページ:

最後に

蛇足だけど・・・ グローバルフックは、システムを監視する基本的な仕組みで、ハッキングにも使われます。 例えば、キー入力の監視は、パスワードを盗んだりすることに利用できちゃいそうです。 もしかしたら、マルウエア監視にひっかかるかもしれませんね。 でも自分で作ったプログラムなら無視して大丈夫。

また、オンラインゲームなどはチートを防ぐために、 このような自動化に類似したプログラムが動作しているかどうかを監視してるかもしれません。 ずるしちゃダメですよ(笑)。

おことわり

  • 本記事によって起きたいかなる損害に対し、筆者は責任を負うことはできません。
  • ご自身の趣味の範囲を超えた責任のあるプログラムへの利用はご遠慮ください。
  • このコードには実行時に起こりうるシグナルやエラーを処理していません。
  • このコードには本来行うべき終了時の処理が記述されていません。

執筆者備考

2024/01/07 初稿。下書きから1年もかかったw

権利表示

Copyright (C) 2023,2024 upsndownsjp, All Right Reserved.