Клавиатура низкого уровня Hooks/SendInput с возможным Winkey+L? (локаут рабочей станции прерывается в Vista и выше),

Я работаю над проектом под названием UAWKS (Неофициальная Поддержка Беспроводной клавиатуры Apple), который помогает пользователям Windows использовать bluetooth-клавиатуру Apple. Одна из главных целей UAWKS состоит в том, чтобы подкачать ключ Cmd (который ведет себя как Winkey в Windows) с Ctrl, позволяя пользователям сделать Cmd+C для копии, Cmd+T для новой вкладки, и т.д.

Это в настоящее время разрабатывается с помощью AutoHotkey, который работал вполне прилично под Windows XP. Однако на Vista и Windows 7, Cmd+L вызывает проблемы:

  • Независимо от рычагов клавиатуры низкого уровня Win+L всегда прерывается Windows и обычно блокирует рабочую станцию...
  • Можно отключить блокировку рабочей станции с этим взломом реестра, но нажатие Win+L все еще не может быть повышением AHK
  • Нажатие Win+L покидает Winkey в состоянии Keydown до следующего (дополнительного) Winkey. Моделирование события Keyup, кажется, не работает также!

Кажется, что Win+L является специальной хордой, которая портит все остальное.

Я просмотрел исходный код AHK, и они пытаются решить эту проблему в SendKey() в keyboard_mouse.cpp (около строки 883 в v1.0.48.05), но это не работает. Я описал свое собственное приложение захвата клавиатуры низкого уровня в C#, и я вижу ту же проблему.

Кто-либо еще столкнулся с этим? Существует ли обходное решение?

6
задан Syscall 18 February 2018 в 20:09
поделиться

3 ответа

Я нашел способ сделать это на C #. Возможная последовательность нажатия клавиш Win + L включает четыре состояния (Нет, Win , Win + L ], L ). При достижении состояния Win + L установите флаг («winLSet» ниже). Когда все клавиши были отпущены, мы проверяем наличие этого флага и имитируем нажатие, если он установлен.

Последняя часть головоломки - смоделировать KeyUp WinKey перед Ctrl - L (без KeyDown). Я пробовал аналогичные подходы в AutoHotkey, и он никогда не работал, но, похоже, здесь он отлично работает.

Код ниже. См. Пояснительные примечания внизу, если вы планируете использовать этот код.

public partial class MainWindow : Window
{
    LowLevelKeyboardHook hook;

    bool winKeyDown;
    bool lKeyDown;
    bool winLSet;

    public MainWindow()
    {
        InitializeComponent();

        hook = new LowLevelKeyboardHook();

        hook.KeyDown += OnKeyDown;
        hook.KeyUp += OnKeyUp;
    }

    void OnKeyDown(object sender, LowLevelKeyEventArgs e)
    {
        e.EventHandled = true;

        switch (e.Key)
        {
            case Key.L:
                lKeyDown = true;
                UpdateWinLState();
                e.EventHandled = winKeyDown;
                break;

            case Key.LWin:
                winKeyDown = true;
                UpdateWinLState();
                InputSimulator.SimulateKeyDown(VirtualKeyCode.LCONTROL);
                break;

            case Key.LeftCtrl:
                InputSimulator.SimulateKeyDown(VirtualKeyCode.LWIN);
                break;

            default:
                e.EventHandled = false;
                break;
        }
    }

    void OnKeyUp(object sender, LowLevelKeyEventArgs e)
    {
        e.EventHandled = true;

        switch (e.Key)
        {
            case Key.L:
                lKeyDown = false;
                UpdateWinLState();
                e.EventHandled = winKeyDown;
                break;

            case Key.LWin:
                winKeyDown = false;
                UpdateWinLState();
                InputSimulator.SimulateKeyUp(VirtualKeyCode.LCONTROL);
                break;

            case Key.LeftCtrl:
                InputSimulator.SimulateKeyUp(VirtualKeyCode.LWIN);
                break;

            default:
                e.EventHandled = false;
                break;
        }
    }

    void UpdateWinLState()
    {
        if (winKeyDown && lKeyDown)
        {
            winLSet = true;
        }
        else if (!winKeyDown && !lKeyDown && winLSet)
        {
            winLSet = false;

            InputSimulator.SimulateKeyUp(VirtualKeyCode.LWIN);

            InputSimulator.SimulateModifiedKeyStroke(
                VirtualKeyCode.LCONTROL,
                (VirtualKeyCode)'L');
        }
    }
}

Для потомков: обратите внимание, что этот код использует InputSimulator и LowLevelKeyboardHook, которые не из .NET Framework. LowLevelKeyboardHook - это класс, который я написал недавно, который предоставляет глобальные события KeyDown и KeyUp как события C #. Есть похожие примеры здесь , здесь , и их можно найти здесь .

Также обратите внимание, что я использую System.Windows.Input.Key, а не System.Windows.Forms.Keys, что может сбить с толку некоторых людей. System.Windows.Input.Key - это новое перечисление ключей в .NET 3.0 и выше, а System.Windows.Forms.Keys - это старое перечисление из Windows Forms.

2
ответ дан 17 December 2019 в 20:29
поделиться

Я попытался прервать нажатие клавиши Windows с помощью библиотеки Windows Input Simulator . Это мой обратный вызов:

private static unsafe IntPtr HookCallback( int nCode, IntPtr wParam, IntPtr lParam )
{
    if( nCode >= 0 && ( wParam == (IntPtr)WM_KEYDOWN ) )
    {
        var replacementKey = (KBDLLHOOKSTRUCT*)lParam;
        if( replacementKey->vkCode == (int)VirtualKeyCode.LWIN )
        {
            InputSimulator.SimulateKeyDown( VirtualKeyCode.SHIFT );
            return (IntPtr)1;
        }
    }
    return CallNextHookEx( m_HookID, nCode, wParam, lParam );
}

Используя этот хук, моя левая клавиша Windows действует как клавиша Shift (как реализовано и ожидается) в Win XP.
Нажатие WinKey + l возвращает только L .

РЕДАКТИРОВАТЬ : Однако я могу подтвердить ваше наблюдение, что этот код больше не работает под Windows 7: / Извините, я больше не могу вам помочь.

0
ответ дан 17 December 2019 в 20:29
поделиться

Если вы можете обнаружить ключ Cmd + L , не могли бы вы просто заблокировать рабочую станцию, не беспокоясь о пересылке Winkey ] + L ? вы можете сделать это с помощью API LockWorkstation (или rundll32.exe user32.dll, LockWorkStation )

0
ответ дан 17 December 2019 в 20:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: