2014-12-06 1 views
1

Я создаю приложение, которое помещает значок на системный лоток, который меняет внешний вид на основе состояния ключа Caps Lock. Проблема, с которой я сталкиваюсь, заключается в том, что крючок работает корректно только после нажатия клавиши, отличной от Caps Lock, так как эта клавиша переворачивает проверку после прохода крючка, что неправильно отображает значок неправильного состояния.Обнаружение определенного ключа в низкоуровневом клавиатурном крючке

Мне нужен способ определить, когда нажата кнопка Caps Lock внутри крючка, чтобы перевернуть обнаруженное состояние.

private static NotifyIcon notifyIcon = new NotifyIcon(); 
private static bool CapsPressed = Control.IsKeyLocked(Keys.CapsLock); 
static Icon 
    AppIcon = CapsIndicator.Properties.Resources.AppIcon, 
    OnIcon = CapsIndicator.Properties.Resources.OnIcon, 
    OffIcon = CapsIndicator.Properties.Resources.OffIcon; 

static void UpdateIcon() { 
    notifyIcon.Icon = CapsPressed ? OnIcon : OffIcon; 
} 

// Hook initializing & other stuff here 

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { 
    if (nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN) { 
     CapsPressed = Control.IsKeyLocked(Keys.CapsLock); 
     UpdateIcon(); 
    } 
    return CallNextHookEx(_hookID, nCode, wParam, lParam); 
} 

ответ

1

Решение не очень прямолинейно, но ключевой код можно обнаружить с помощью lParam аргумент указателя. Вы можете сделать это, обратившись к 32-разрядному целому числу он, указывая на с Marshal.ReadInt32, то, что вам нужно, чтобы бросить его в Keys типа, и, наконец, сравнить это значение с Keys.CapsLock (или любым другим ключом, который вы любите):

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { 
    if (nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN) { 
     int vkCode = Marshal.ReadInt32(lParam); 

     CapsPressed = Control.IsKeyLocked(Keys.CapsLock); 
     // Flip the detected value if CapsLock is pressed 
     if ((Keys) vkCode == Keys.CapsLock) CapsPressed = !CapsPressed; 

     UpdateIcon(); 
    } 
    return CallNextHookEx(_hookID, nCode, wParam, lParam); 
} 
+0

Это имеет тенденцию работать, это не технически правильно. Другие крючки могут не допустить использования ключа. Низкие коэффициенты, а не ноль. Использование методов BeginInvoke() или SynchronizationContext.Current.Post() - отличные способы запуска кода позже. –

+0

@HansPassant В моем случае приложение не имеет открытой формы, пока не вызывается из контекстного меню значка в трее. Единственный способ поймать ключи - это глобальный ловец. – SeinopSys

+0

Вот почему я упомянул SynchronizationContext. –

Смежные вопросы