Возможны ли низкоуровневые зацепки клавиатуры / SendInput с Winkey + L? (блокировка рабочей станции перехватывается в Vista и выше) - PullRequest
6 голосов
/ 25 мая 2010

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

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

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

Похоже, что Win + L - это особый аккорд, который все портит.

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

Кто-нибудь еще сталкивался с этим? Есть ли обходной путь?

Ответы [ 3 ]

2 голосов
/ 25 мая 2010

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

Последняя часть головоломки состоит в том, чтобы имитировать KeyKp 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Фреймворк.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.

0 голосов
/ 25 мая 2010

Я пытался прервать ключ 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 голосов
/ 25 мая 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...