single.php

C#[VIA]で設定したレイヤーを可視化するアプリの作ってみた(その4)

対応するキーボードのキーマップを変更する[VIA]には編集したキーの配置をまとめて管理する[レイヤー]機能があります。利用すると1つのキーに複数の役割を設定できるので便利ですが、今回は修飾キーと同時押しの対応を改良してみました。

VIAのレイヤー機能

対応するキーボードのキーマップを変更する[VIA]には編集したキーの配置をまとめて管理する[レイヤー]機能があります。

例えば、通常のキーボードの[A]キーは、アルファベットの “a” が入力されますが[Shift]キーと同時に使うと “A” が入力できます。

また、Windowsの場合[Ctrl]キーと同時に使うと[すべて選択]機能を呼び出す際にも利用できます。

こんな感じで[レイヤー]を使うと1つのキーに複数の機能を割り振ることが可能になります。

Amazonでも対応したキーボードや関連デバイスが販売されていて、私が購入した「EPOMAKER EK21 VIA ガスケット テンキー ゲーミングキーボード ワイヤレスメカニカルテンキー」でも便利に使っています。

このレイヤー機能を使えば、20個のキーであれば最大80個までキーが登録できます。

非常に便利なんですが、キートップの印刷が変わる訳ではないので、残りの60個の機能と配置場所は覚える必要があります。

キーマップを画面に表示

先回、[VIA]を使ってレイヤーを切り替える操作と、アプリに伝えるためのキー操作の設定を行いました。

簡単に説明すると、[Fn]キーを押している間は、レイヤーを移動する機能とキーを短押しすると[F20]と言った特殊なキーを送信します。

詳しい設定方法などは、別記事をご覧ください。

タスクトレイに常駐するWindowsアプリにしたので、C#のWinFormプロジェクトで[KeyLayerView]として作成しました。

修飾キーとの組み合わせを設定

先回[Shift]や[Ctrl]などの修飾キーと対応しましたが、キーの同時押しのタイミングで上手く動作しなくなったので、少し取得方法を変更して改良しました。

先回改良した修飾キーとの組み合わせ検出では不十分だった部分があって、検出出来ない場合があったので、左右の[Shift]や[Ctrl]キーも含めて対応するように改良しました。

なので[Shift]や[Alt]など修飾キーと呼ばれるキーとの組み合わせを可能にしてみました。

Win32 APIのGetKeyState関数を呼び出して利用する[Win32VirtualKey]クラスにキー定数を追加します。

const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;

private bool _shiftDown;
private bool _ctrlDown;
private bool _altDown;
private bool _winDown;

public class Win32VirtualKey
{
    public const int VK_SHIFT = 0x10;
    public const int VK_LSHIFT = 0xA0;
    public const int VK_RSHIFT = 0xA1;
    
    public const int VK_CONTROL = 0x11;
    public const int VK_LCONTROL = 0xA2;
    public const int VK_RCONTROL = 0xA3;

    public const int VK_MENU = 0x12;
    public const int VK_LMENU = 0xA4;
    public const int VK_RMENU = 0xA5;

    public const int VK_LWIN = 0x5B;
    public const int VK_RWIN = 0x5C;
}

private static bool IsModifierKey(int vkCode)
{
    return vkCode is
        Win32VirtualKey.VK_SHIFT or
        Win32VirtualKey.VK_LSHIFT or
        Win32VirtualKey.VK_RSHIFT or
        Win32VirtualKey.VK_CONTROL or
        Win32VirtualKey.VK_LCONTROL or
        Win32VirtualKey.VK_RCONTROL or
        Win32VirtualKey.VK_MENU or
        Win32VirtualKey.VK_LMENU or
        Win32VirtualKey.VK_RMENU or
        Win32VirtualKey.VK_LWIN or
        Win32VirtualKey.VK_RWIN;
}

public bool ShiftDown => _shiftDown;
public bool CtrlDown => _ctrlDown;
public bool AltDown => _altDown;
public bool WinDown => _winDown;

public bool IsKeyDown(int vk)
{
    return (GetKeyState(vk) & 0x8000) != 0;
}

[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);

修飾キーの状態を取得する部分は、次の様に修正しました。

IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0)
    {
        int vkCode = Marshal.ReadInt32(lParam);
        bool isDown = wParam == (IntPtr)WM_KEYDOWN;
        bool isUp = wParam == (IntPtr)WM_KEYUP;

        // 修飾キー状態更新
        UpdateModifierState(vkCode, isDown, isUp);

        // 通常キーのみ通知
        if (isDown && !IsModifierKey(vkCode))
        {
            VirtualKeyPressed?.Invoke(vkCode);
        }
    }

    return CallNextHookEx(_hookId, nCode, wParam, lParam);
}

private void UpdateModifierState(int vkCode, bool isDown, bool isUp)
{
    bool state = isDown && !isUp;

    switch (vkCode)
    {
        case Win32VirtualKey.VK_LSHIFT:
        case Win32VirtualKey.VK_RSHIFT:
            _shiftDown = state;
            break;

        case Win32VirtualKey.VK_LCONTROL:
        case Win32VirtualKey.VK_RCONTROL:
            _ctrlDown = state;
            break;

        case Win32VirtualKey.VK_LMENU:
        case Win32VirtualKey.VK_RMENU:
            _altDown = state;
            break;

        case Win32VirtualKey.VK_LWIN:
        case Win32VirtualKey.VK_RWIN:
            _winDown = state;
            break;
    }
}

キーイベントでは、次のコードで取得を行います

private void OnVirtualKeyPressed(int vkCode)
{
    if (!QmkKeyMap.VkToQmk.TryGetValue(vkCode, out var baseKey))
        return;

    if(_keyboardHook == null)
        return;

    // 修飾キー判定
    bool shift = _keyboardHook.ShiftDown;
    bool ctrl = _keyboardHook.CtrlDown;
    bool alt = _keyboardHook.AltDown;
    bool win = _keyboardHook.WinDown;

    // QMKキー文字列を組み立て
    string qmkKey = BuildQmkKey(baseKey, shift, ctrl, alt, win);

    if (!_layerMap.TryGetValue(qmkKey, out var imageFile))
        return;

    if (_currentLayerKey == qmkKey && _form!.Visible)
    {
        _form.Hide();
        _currentLayerKey = null;
        return;
    }

    if (!ImageCache.TryGet(imageFile, out var image))
        return;

    _currentLayerKey = qmkKey;
    _form!.ShowImage(image);
}

後は[Shift]+[F20]キーを押すとモニターの左下に画像が表示されます。(もう一度押すと、非表示になります)

キーボードに無い[F13]~[F24]を使う場合に[Shift]や[Alt]、[Ctrl]キーを組み合わせることで2~4倍のキー数に増やすことが可能です。

まとめ

対応するキーボードのキーマップを変更する[VIA]には編集したキーの配置をまとめて管理する[レイヤー]機能に対応した画像を画面に表示するアプリの作成を行ってみました。

先回、[Shift]や[Ctrl]キーと組み合わせた場合のキー取得が可能になるように追加した部分が、タイミングによっては取得できない場合があったので改良を行いました。

キーイベントで修飾キーとの組み合わせの状態まで取得したい人の参考になれば幸いです。

スポンサーリンク

最後までご覧いただき、ありがとうございます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です