Я работаю над проектом под названием UAWKS (Неофициальная Поддержка Беспроводной клавиатуры Apple), который помогает пользователям Windows использовать bluetooth-клавиатуру Apple. Одна из главных целей UAWKS состоит в том, чтобы подкачать ключ Cmd (который ведет себя как Winkey в Windows) с Ctrl, позволяя пользователям сделать Cmd+C для копии, Cmd+T для новой вкладки, и т.д.
Это в настоящее время разрабатывается с помощью AutoHotkey, который работал вполне прилично под Windows XP. Однако на Vista и Windows 7, Cmd+L вызывает проблемы:
Кажется, что Win+L является специальной хордой, которая портит все остальное.
Я просмотрел исходный код AHK, и они пытаются решить эту проблему в SendKey()
в keyboard_mouse.cpp (около строки 883 в v1.0.48.05), но это не работает. Я описал свое собственное приложение захвата клавиатуры низкого уровня в C#, и я вижу ту же проблему.
Кто-либо еще столкнулся с этим? Существует ли обходное решение?
Я нашел способ сделать это на 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.
Я попытался прервать нажатие клавиши 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: / Извините, я больше не могу вам помочь.
Если вы можете обнаружить ключ Cmd + L , не могли бы вы просто заблокировать рабочую станцию, не беспокоясь о пересылке Winkey ] + L ? вы можете сделать это с помощью API LockWorkstation
(или rundll32.exe user32.dll, LockWorkStation
)