Поймать последовательность клавиш WinKey+D в Winforms
Я пытаюсь сделать так, чтобы мое приложение всегда было представлено на уровне рабочего стола. Это означает, что мое приложение должно игнорировать последовательности клавиш, такие как LWin+D или RWin+D . Я попытался заставить это работать таким образом:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (prefixSeen)
{
if (keyData == Keys.D)
{
MessageBox.Show("Got it!");
}
prefixSeen = false;
return true;
}
if (keyData == Keys.LWin)
{
prefixSeen = true;
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Но он ловит только кнопки RWin/LWin, без кнопки D.
Я также пытался создать свой собственный фильтр сообщений, но в нем я заблудился. Все эти сообщения и побитовые:
public class KeystrokMessageFilter : System.Windows.Forms.IMessageFilter
{
public KeystrokMessageFilter() { }
public bool PreFilterMessage(ref Message m)
{
if ((m.Msg == 256 /*0x0100*/))
{
switch (((int)m.WParam) | ((int)Control.ModifierKeys))
{
case (int)(Keys.Control | Keys.Alt | Keys.K):
MessageBox.Show("You pressed ctrl + alt + k");
break;
case (int)(Keys.Control | Keys.C): MessageBox.Show("ctrl+c");
break;
case (int)(Keys.Control | Keys.V): MessageBox.Show("ctrl+v");
break;
case (int)Keys.Up: MessageBox.Show("You pressed up");
break;
}
}
return false;
}
}
Application.AddMessageFilter(keyStrokeMessageFilter);
Итак, как мне сделать, чтобы мое приложение перехватывало / игнорировало R/LWin+D?
3 ответа
Этот код регистрирует низкоуровневый хук клавиатуры и прослушивает D
удерживайте нажатой клавишу Windows. Если это обнаружено, крючок просто игнорирует нажатие клавиши. В противном случае, он передает нажатие клавиши вперед.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace KbHook
{
public static class Program
{
const int HC_ACTION = 0;
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
static IntPtr HookHandle = IntPtr.Zero;
static Form1 Form1;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, KbHook lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[STAThread]
static void Main()
{
try
{
using (var proc = Process.GetCurrentProcess())
using (var curModule = proc.MainModule)
{
var moduleHandle = GetModuleHandle(curModule.ModuleName);
HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, IgnoreWin_D, moduleHandle, 0);
}
Form1 = new Form1();
Application.Run(Form1);
}
finally
{
UnhookWindowsHookEx(HookHandle);
}
}
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(Keys vKey);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
static IntPtr IgnoreWin_D(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode == HC_ACTION
&& IsWin_D(wParam, lParam))
return (IntPtr) 1; //just ignore the key press
return CallNextHookEx(HookHandle, nCode, wParam, lParam);
}
static bool IsWin_D(IntPtr wParam, IntPtr lParam)
{
if ((int) wParam != WM_KEYDOWN)
return false;
var keyInfo = (KbHookParam) Marshal.PtrToStructure(lParam, typeof (KbHookParam));
if (keyInfo.VkCode != (int) Keys.D) return false;
return GetAsyncKeyState(Keys.LWin) < 0
|| GetAsyncKeyState(Keys.RWin) < 0;
}
delegate IntPtr KbHook(int nCode, IntPtr wParam, [In] IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
struct KbHookParam
{
public readonly int VkCode;
public readonly int ScanCode;
public readonly int Flags;
public readonly int Time;
public readonly IntPtr Extra;
}
}
}
Смотрите также Как подключить Win + Tab с помощью LowLevelKeyboardHook
Я знаю, что это слишком старый вопрос. Но эй, недавно мне пришлось разработать приложение, которое будет оставаться на рабочем столе, как виджет (обратный отсчет времени для моего ежегодного bash компании).
Мне удалось сохранить окно в фоновом режиме (на рабочем столе winform) даже при нажатии клавиш WinKey+D или WinKey+M через низкоуровневую клавиатуру Windows. Я использовал код dss539 и просто улучшил его, чтобы сохранить приложение winforms на рабочем столе.
Хитрость заключается в том, чтобы установить свойство TopMost форм в значение true, когда вы сталкиваетесь с WinKey+D или WinKey+M, и установить его обратно в значение false для других ключей и передать дескриптор для обработки окон.
Ниже приведен пример кода.
В Program.cs - Main()
try
{
using (var proc = Process.GetCurrentProcess())
using (var curModule = proc.MainModule)
{
var moduleHandle = GetModuleHandle(curModule.ModuleName);
HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, IgnoreWin_DOrM, moduleHandle, 0);
}
frmForm1 = new frmIGS();
Application.Run(frmForm1);
}
finally
{
UnhookWindowsHookEx(HookHandle);
}
Затем напишите свой метод подключения клавиатуры:
static IntPtr IgnoreWin_DOrM(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode == HC_ACTION
&& (IsWin_D(wParam, lParam) || IsWin_M(wParam, lParam)))
{
frmForm1.SetTopMost = true;
}
else
{
//if (frmForm1.SetTopMost)
{
frmForm1.SetTopMost = false;
}
}
return CallNextHookEx(HookHandle, nCode, wParam, lParam);
}
static bool IsWin_D(IntPtr wParam, IntPtr lParam)
{
if ((int)wParam != WM_KEYDOWN)
return false;
var keyInfo = (KbHookParam)Marshal.PtrToStructure(lParam, typeof(KbHookParam));
if (keyInfo.VkCode != (int)Keys.D) return false;
return GetAsyncKeyState(Keys.LWin) < 0
|| GetAsyncKeyState(Keys.RWin) < 0;
}
static bool IsWin_M(IntPtr wParam, IntPtr lParam)
{
if ((int)wParam != WM_KEYDOWN)
return false;
var keyInfo = (KbHookParam)Marshal.PtrToStructure(lParam, typeof(KbHookParam));
if (keyInfo.VkCode != (int)Keys.M) return false;
return GetAsyncKeyState(Keys.LWin) < 0
|| GetAsyncKeyState(Keys.RWin) < 0;
}
Я выставил публичное свойство для формы, которое устанавливает самое верхнее свойство в своем коде!
private bool topMost = false;
public bool SetTopMost
{
get
{
return topMost;
}
set
{
this.TopMost = topMost = value;
}
}
Виола. Теперь мой код остается в фоновом режиме, независимо от сочетаний клавиш Windows. Но не останется поверх других приложений, позволяющих пользователю выполнять свою обычную работу! И это было требование!
Это хорошо работало в Windows 10:)
Попробуйте решение из Как определить, когда форма окна свернута? поймать событие до его срабатывания и обработать его; это должно позволить вам игнорировать это.