8

ユーザーがキーボードのように見えるようにカスタマイズするためのキーボードレイアウトを生成する必要がある場合、どうすればよいですか?

たとえば、次のようなものです。

ここに画像の説明を入力してください

フランス語、スウェーデン語、英語、カナダ語などは、レイアウトが異なります。これは大変な作業ですか、それともある種の組み込みの.NETリージョナルクラスを使用するだけの問題ですか?

4

2 に答える 2

11

キーを押すと、「スキャンコード」をWindowsオペレーティングシステムに報告するハードウェアイベントが生成されます。Caps Lock次に、このスキャンコードは、スキャンコードと他のキーボード状態要素(状態、Shift//キー状態、AltおよびCtrl保留中のデッドキーストローク)に基づいて「仮想キーコード」に変換されます。変換されたVK値は、KeyDownイベントなどによって報告されたものです。

スキャンコードからVKコードへの変換は、現在の入力ロケールに依存します。簡単に言うと、入力ロケールは、スキャンコードと仮想キーコードの間のマッピングを定義します。キーボード入力の詳細については、MSDNのドキュメントを参照してください。

このルックアッププロセスを逆にすることで、各仮想キーコードに対応するスキャンコードを決定できます(もちろん、同じスキャンコードは、shift / ctrl / alt状態などのために複数のVKコードにマップされます)。Win32 APIはMapVirtualKeyEx、オプションを使用して、このマッピングを実行する機能を提供しMAPVK_VK_TO_VSC_EXます。これを使用して、特定のVKコードを生成するスキャンコードを判別できます。

残念ながら、これはプログラムで実行できる範囲です。キーボードの物理的なレイアウトや各スキャンコードのキーの位置を特定する方法はありません。ただし、ほとんどの物理キーボードは同じ方法で配線されているため、(たとえば)左上のキーは、ほとんどの物理キーボードデザインで同じスキャンコードを持ちます。この想定される規則を使用して、基本的な物理キーボードレイアウト(101キー、102キーなど)に応じて、スキャンコードに対応する物理的な場所を推測できます。保証はされていませんが、かなり安全な推測です。

次のコードは、私が書いたより大きなキーボード処理ライブラリからの抜粋です(私はそれをオープンソース化するつもりでしたが、時間がありませんでした)。this._virtualKeyScanCodesこのメソッドは、指定された入力ロケールのVKコードによってインデックス付けされた配列()を初期化します(に格納されthis._inputLanguage、として宣言されます。配列を使用して、たとえば-if the scanSystem.Windows.Forms.InputLanguageを調べることにより、VKコードに対応するスキャンコードを判別できます。this._virtualKeyScanCodes[VK_NUMPAD0]コードがゼロの場合、そのVKは現在の入力ロケールのキーボードでは使用できません。ゼロ以外の場合は、物理キーを推測できるスキャンコードです。

残念ながら、デッドキーの領域に入ると、問題はこれよりも少し複雑になります(たとえば、アクセント付き文字を生成する複数のキーの組み合わせ)。これは非常に複雑すぎて今は説明できませんが、これをさらに詳しく調べたい場合は、MichaelS.Kaplanが一連の詳細なブログ投稿を作成しました。幸運を!

private void Initialize()
{
    this._virtualKeyScanCodes = new uint[MaxVirtualKeys];

    // Scroll through the Scan Code (SC) values and get the Virtual Key (VK)
    // values in it. Then, store the SC in each valid VK so it can act as both a 
    // flag that the VK is valid, and it can store the SC value.
    for (uint scanCode = 0x01; scanCode <= 0xff; scanCode++)
    {
        uint virtualKeyCode = NativeMethods.MapVirtualKeyEx(
            scanCode, 
            NativeMethods.MAPVK_VSC_TO_VK, 
            this._inputLanguage.Handle);
        if (virtualKeyCode != 0)
        {
            this._virtualKeyScanCodes[virtualKeyCode] = scanCode;
        }
    }

    // Add the special keys that do not get added from the code above
    for (KeysEx ke = KeysEx.VK_NUMPAD0; ke <= KeysEx.VK_NUMPAD9; ke++)
    {
        this._virtualKeyScanCodes[(uint)ke] = NativeMethods.MapVirtualKeyEx(
            (uint)ke, 
            NativeMethods.MAPVK_VK_TO_VSC, 
            this._inputLanguage.Handle);
    }

    this._virtualKeyScanCodes[(uint)KeysEx.VK_DECIMAL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_DECIMAL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_DIVIDE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_DIVIDE, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_CANCEL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_CANCEL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);

    this._virtualKeyScanCodes[(uint)KeysEx.VK_LSHIFT] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RSHIFT] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LCONTROL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RCONTROL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LMENU] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RMENU] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LWIN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RWIN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_PAUSE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_UP] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_UP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_DOWN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_DOWN, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_MUTE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_MUTE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);

    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_NEXT_TRACK] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_NEXT_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PREV_TRACK] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_PREV_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PLAY_PAUSE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_PLAY_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_STOP] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_STOP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);

    this._stateController = new KeyboardStateController();
    this._baseVirtualKeyTable = new VirtualKeyTable(this);
}

編集:あなたの質問に似ているこの質問も参照してください。

于 2011-01-27T23:14:46.533 に答える
3

キーボードレイアウトを含む組み込みの.NETクラスはありません。キーボードレイアウトは、オペレーティングシステム(通常はWindows)の機能です。.NETが関与するまでに、押されたキーはハードウェアイベントからソフトウェアイベントに変換されています。これが実際に動作していることを確認したい場合は、キーがそれらの間を移動した2つのキーボードレイアウトを見つけてください。イベントにイベントハンドラーを使用してダミーアプリをセットアップしKey_Down、イベント引数が同じであることに注意してください。-キーを押した場合-は、そのキーの場所に関係なく、キーを押しました-

于 2011-01-27T21:58:58.437 に答える