WPF 및 를 사용하여 CTRL+SHIFT+(LETTER)라고 하는 글로벌 단축키를 등록하려면 어떻게 해야 합니까?NET 3.5?
WPF를 사용하여 C#에 애플리케이션을 구축하고 있습니다.어떻게 하면 몇 가지 키에 바인딩할 수 있습니까?
또, Windows 키에 바인드 하려면 어떻게 해야 하나요?
이것은 완전히 효과가 있는 해결책입니다. 도움이 되길 바랍니다.
사용방법:
_hotKey = new HotKey(Key.F9, KeyModifier.Shift | KeyModifier.Win, OnHotKeyHandler);
...
private void OnHotKeyHandler(HotKey hotKey)
{
SystemHelper.SetScreenSaverRunning();
}
클래스:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Mime;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace UnManaged
{
public class HotKey : IDisposable
{
private static Dictionary<int, HotKey> _dictHotKeyToCalBackProc;
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, UInt32 fsModifiers, UInt32 vlc);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public const int WmHotKey = 0x0312;
private bool _disposed = false;
public Key Key { get; private set; }
public KeyModifier KeyModifiers { get; private set; }
public Action<HotKey> Action { get; private set; }
public int Id { get; set; }
// ******************************************************************
public HotKey(Key k, KeyModifier keyModifiers, Action<HotKey> action, bool register = true)
{
Key = k;
KeyModifiers = keyModifiers;
Action = action;
if (register)
{
Register();
}
}
// ******************************************************************
public bool Register()
{
int virtualKeyCode = KeyInterop.VirtualKeyFromKey(Key);
Id = virtualKeyCode + ((int)KeyModifiers * 0x10000);
bool result = RegisterHotKey(IntPtr.Zero, Id, (UInt32)KeyModifiers, (UInt32)virtualKeyCode);
if (_dictHotKeyToCalBackProc == null)
{
_dictHotKeyToCalBackProc = new Dictionary<int, HotKey>();
ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);
}
_dictHotKeyToCalBackProc.Add(Id, this);
Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode);
return result;
}
// ******************************************************************
public void Unregister()
{
HotKey hotKey;
if (_dictHotKeyToCalBackProc.TryGetValue(Id, out hotKey))
{
UnregisterHotKey(IntPtr.Zero, Id);
}
}
// ******************************************************************
private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled)
{
if (!handled)
{
if (msg.message == WmHotKey)
{
HotKey hotKey;
if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey))
{
if (hotKey.Action != null)
{
hotKey.Action.Invoke(hotKey);
}
handled = true;
}
}
}
}
// ******************************************************************
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// ******************************************************************
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be _disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be _disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this._disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
Unregister();
}
// Note disposing has been done.
_disposed = true;
}
}
}
// ******************************************************************
[Flags]
public enum KeyModifier
{
None = 0x0000,
Alt = 0x0001,
Ctrl = 0x0002,
NoRepeat = 0x4000,
Shift = 0x0004,
Win = 0x0008
}
// ******************************************************************
}
여기서 "글로벌"이 의미하는 바는 잘 모르겠습니다만, 다음과 같습니다(어플리케이션레벨의 명령어, 예를 들어 + + 를 사용하여 어디에서나 기동할 수 있는 Save All을 의미합니다).
글로벌 검색UIElement예를 들어, 이 바인딩이 필요한 모든 컨트롤의 부모인 최상위 창을 선택합니다.WPF 이벤트의 "버블링"으로 인해 하위 요소의 이벤트는 제어 트리의 루트까지 버블링됩니다.
자, 우선은
- Key-Combo를 명령어로 바인드하다
InputBinding이것처럼. - 그런 다음 명령을 핸들러에 연결할 수 있습니다(예: 에 의해 호출되는 코드).
SaveAll)를 경유하여CommandBinding.
Key의 경우 올바른 Key 열거 멤버를 사용합니다.
public WindowMain()
{
InitializeComponent();
// Bind Key
var ib = new InputBinding(
MyAppCommands.SaveAll,
new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control));
this.InputBindings.Add(ib);
// Bind handler
var cb = new CommandBinding( MyAppCommands.SaveAll);
cb.Executed += new ExecutedRoutedEventHandler( HandlerThatSavesEverthing );
this.CommandBindings.Add (cb );
}
private void HandlerThatSavesEverthing (object obSender, ExecutedRoutedEventArgs e)
{
// Do the Save All thing here.
}
OS 레벨의 숏컷을 등록하는 것은 결코 좋은 일이 아닙니다.사용자는 OS를 조작하는 것을 원하지 않습니다.
즉, 애플리케이션 내에서만 단축키를 사용할 수 있는 경우(즉, WPF 앱에 포커스가 있는 경우)에는, WPF에서는 보다 심플하고 사용하기 쉬운 방법이 있습니다.
App.xaml.cs의 경우:
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(Window), Window.PreviewKeyUpEvent, new KeyEventHandler(OnWindowKeyUp));
}
private void OnWindowKeyUp(object source, KeyEventArgs e))
{
//Do whatever you like with e.Key and Keyboard.Modifiers
}
그렇게 간단하다.
Win32와 WPF를 혼재시키는 경우는, 다음과 같이 실시합니다.
using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Threading;
using System.Windows;
using System.Windows.Input;
namespace GlobalKeyboardHook
{
public class KeyboardHandler : IDisposable
{
public const int WM_HOTKEY = 0x0312;
public const int VIRTUALKEYCODE_FOR_CAPS_LOCK = 0x14;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private readonly Window _mainWindow;
WindowInteropHelper _host;
public KeyboardHandler(Window mainWindow)
{
_mainWindow = mainWindow;
_host = new WindowInteropHelper(_mainWindow);
SetupHotKey(_host.Handle);
ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
}
void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
{
if (msg.message == WM_HOTKEY)
{
//Handle hot key kere
}
}
private void SetupHotKey(IntPtr handle)
{
RegisterHotKey(handle, GetType().GetHashCode(), 0, VIRTUALKEYCODE_FOR_CAPS_LOCK);
}
public void Dispose()
{
UnregisterHotKey(_host.Handle, GetType().GetHashCode());
}
}
}
등록하는 단축키의 가상 키 코드는, http://msdn.microsoft.com/en-us/library/ms927178.aspx 에서 입수할 수 있습니다.
더 나은 방법이 있을지도 모르지만, 지금까지 제가 알아낸 건 이것뿐입니다.
건배!
이는 이미 제시된 답변과 비슷하지만 조금 더 명확하다고 생각합니다.
using System;
using System.Windows.Forms;
namespace GlobalHotkeyExampleForm
{
public partial class ExampleForm : Form
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public ExampleForm()
{
InitializeComponent();
int id = 0; // The id of the hotkey.
RegisterHotKey(this.Handle, id, (int)KeyModifier.Shift, Keys.A.GetHashCode()); // Register Shift + A as global hotkey.
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x0312)
{
/* Note that the three lines below are not needed if you only want to register one hotkey.
* The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); // The key of the hotkey that was pressed.
KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
MessageBox.Show("Hotkey has been pressed!");
// do something
}
}
private void ExampleForm_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0); // Unregister hotkey with id 0 before closing the form. You might want to call this more than once with different id values if you are planning to register more than one hotkey.
}
}
}
fluxbytes.com에서 찾았습니다.
NHotKey 패키지를 사용하면 단축키를 글로벌하게 만들 수 있습니다.
- https://github.com/thomaslevesque/NHotkey
- https://thomaslevesque.com/2014/02/05/wpf-declare-global-hotkeys-in-xaml-with-nhotkey/ (링크가 끊어진 경우 web.archive.org 사용)
즉, XAML의 경우 필요한 것은,
<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}" />
타고
<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}"
HotkeyManager.RegisterGlobalHotkey="True" />
WPF에 대해서는 확실하지 않지만 도움이 될 수 있습니다.Register에 기재되어 있는 솔루션을 사용했습니다.C# Windows Forms 응용 프로그램에서 C# 폼을 기동하기 위해 C# Windows Forms 응용 프로그램에서 C# 폼을 할당하는 단축키(user32)를 사용하면 Windows Vista에서도 정상적으로 동작합니다.도움이 되고 행운을 빌어요!
codeproject.com의 WPF 프로젝트에서 Global Hotkeys를 찾았습니다.비교적 최신이므로 시스템에 대한 참조가 필요하지 않습니다.창문들."사용자의" 응용 프로그램이 활성 창이 아닌 경우에도 단축키가 눌린 것에 대해 "글로벌하게" 반응하도록 구성 및 작동합니다.
개코원숭이의 솔루션은 여러 개의 창이 있을 수 있기 때문에 가장 효과적입니다.키 입력의 반복을 처리하기 위해 PreviewKeyUpEvent 대신 PreviewKeyDownEvent를 사용하도록 수정했습니다.
캡처 툴이나 오디오 레코딩 앱 등을 쓰는 것이 아니라면 OS 레벨 등록은 권장하지 않습니다.창이 초점이 맞지 않을 때 기능에 접근할 수 있기 때문입니다.
단, 등록핫키가 필요한 경우가 있습니다.대부분의 경우 시스템 전체의 단축키를 사용하지 않을 수 있습니다.결국 다음과 같은 코드를 사용하게 되었습니다.
using System.Windows;
using System.Windows.Interop;
namespace WpfApp
{
public partial class MainWindow : Window
{
const int WM_KEYUP = 0x0101;
const int VK_RETURN = 0x0D;
const int VK_LEFT = 0x25;
public MainWindow()
{
this.InitializeComponent();
ComponentDispatcher.ThreadPreprocessMessage +=
ComponentDispatcher_ThreadPreprocessMessage;
}
void ComponentDispatcher_ThreadPreprocessMessage(
ref MSG msg, ref bool handled)
{
if (msg.message == WM_KEYUP)
{
if ((int)msg.wParam == VK_RETURN)
MessageBox.Show("RETURN was pressed");
if ((int)msg.wParam == VK_LEFT)
MessageBox.Show("LEFT was pressed");
}
}
}
}
RegisterHotKey()하는 것은가 있습니다.- HWND 사용)가입니다(HWND 사용).- HWND 사용.PresentationSource.FromVisual()「HwndSource」(HwndSource)입니다.
,, 객, 객에 대한 답변도 합니다.WM_HOTKEY메시지 - WPF 창의 WndProc에 액세스할 수 있는 방법이 있는지 잘 모르겠습니다(Windows Forms 창에서 할 수 있습니다).
언급URL : https://stackoverflow.com/questions/48935/how-can-i-register-a-global-hot-key-to-say-ctrlshiftletter-using-wpf-and-ne
'programing' 카테고리의 다른 글
| Azure AD의 "Request API permissions"에서 "Application permissions"가 비활성화되어 있는 이유는 무엇입니까? (0) | 2023.04.20 |
|---|---|
| {x: Null} 대투명? (0) | 2023.04.20 |
| app.config config 섹션에서 키 값 쌍을 사전으로 읽는 중 (0) | 2023.04.20 |
| Azure Blob과 Page Blob의 차이점 (0) | 2023.04.20 |
| 입력 필드의 기본값 설정 (0) | 2023.04.20 |