Ich bin eine Anwendung in C# mit WPF erstellen. Wie kann ich an einige Schlüssel binden?Wie kann ich einen globalen Hotkey registrieren, um CTRL + SHIFT + (LETTER) mit WPF und .NET 3.5 zu sagen?
Auch, wie kann ich an die Windows key binden?
Ich bin eine Anwendung in C# mit WPF erstellen. Wie kann ich an einige Schlüssel binden?Wie kann ich einen globalen Hotkey registrieren, um CTRL + SHIFT + (LETTER) mit WPF und .NET 3.5 zu sagen?
Auch, wie kann ich an die Windows key binden?
Ich bin mir nicht sicher, was Sie hier mit "global" meinen, aber hier geht es (ich nehme an, Sie meinen einen Befehl auf der Anwendungsebene, zum Beispiel Alle speichern, die von überall ausgelöst werden können von Ctrl +Umschalt +S.)
finden Sie das globale UIElement
Ihrer Wahl, zum Beispiel die Top-Level-Fenster, das die Eltern aller Kontrollen ist, wo Sie diese Bindung benötigen. Aufgrund des "Bubbling" von WPF-Ereignissen werden Ereignisse bei untergeordneten Elementen bis zum Stamm der Kontrollstruktur durchgeblasen.
Nun, müssen Sie zuerst
InputBinding
wie dieseSaveAll
aufgerufen wird) über eine CommandBinding
.Für die Windows- Key, verwenden Sie das richtige Key aufgezählt Mitglied, Key.LWin
oder Key.RWin
public WindowMain()
{
InitializeComponent();
// Bind Key
InputBinding ib = new InputBinding(
MyAppCommands.SaveAll,
new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control));
this.InputBindings.Add(ib);
// Bind handler
CommandBinding 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.
}
Siehe hier für eine mehr MVVM styled http://stackoverflow.com/questions/19697106/create-key-binding-in-wpf – anhoppe
es ist nicht wirklich global (Anwendungsebene). Wenn Sie ein neues Fenster von Ihrem MainWindow öffnen und dort den Hotkey drücken, würde es nicht funktionieren. – Dork
Auch dies ist nicht "global" aus einer Windows-Perspektive. Wenn deine App nicht im Fokus ist, funktioniert das nicht. – user99999991
Ich bin mir nicht sicher über WPF, aber das kann helfen. Ich habe die in RegisterHotKey (user32) (für mich natürlich modifizierten) Lösung verwendet, um eine C# Windows Forms-Anwendung eine CTRL-KEY-Kombination in Windows zuzuweisen, um ein C# -Formular zu erstellen, und es funktionierte wunderbar (sogar unter Windows Vista). Ich hoffe es hilft und viel Glück!
Dies funktioniert nicht mit WPF. –
Scheint nicht mit der Windows-Taste überhaupt zu funktionieren. Nun, es unterstützt den Windows-Schlüssel, aber alle Hotkeys sind für Windows selbst reserviert. – erodewald
RegisterHotKey()
vorgeschlagen von John könnte funktionieren - der einzige Haken ist, dass es eine HWND erfordert (mit PresentationSource.FromVisual()
, und das Ergebnis auf eine HwndSource Casting).
Sie müssen jedoch auch auf die Nachricht WM_HOTKEY
antworten - ich bin nicht sicher, ob es eine Möglichkeit gibt, Zugriff auf das WndProc eines WPF-Fensters zu bekommen oder nicht (was für Windows Forms-Fenster möglich ist) .
Ein Mitarbeiter einer Probe, wie schrieb eine Low-Level erstellen Tastaturhaken, der mit WPF verwendet wird.
http://blogs.vertigo.com/personal/ralph/Blog/Lists/Posts/Post.aspx?ID=8
Der Link ist kaputt. Weißt du, dass der Artikel verschoben wurde? –
Google ist dein Freund, du hast die Suchbegriffe als Teil des Links, also klicke bitte hier ... http://blogs.vertigo.com/personal/ralph/Blog/Lists/Posts/Post.aspx ? ID = 8 – Gorgsenegger
@Gorgsenegger Die Verbindung ist unterbrochen. –
Wenn Sie vorhaben, Win32 und WPF zu mischen, hier ist, wie ich es tat:
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());
}
}
}
Sie können den virtuellen Tastencode für den Hotkey Sie erhalten hier registrieren: http://msdn.microsoft.com/en-us/library/ms927178.aspx
Vielleicht gibt es einen besseren Weg, aber das ist, was ich bisher habe.
Prost!
Ich nehme an, Sie erzeugen dort ein Speicherleck ... –
Wie produzieren Sie ein Speicherleck von diesem Code? Sein IDisposable – user99999991
'ComponentDispatcher.ThreadPreprocessMessage + = ComponentDispatcher_ThreadPreprocessMessage;' Diese Zeile sollte von UI Thread aufgerufen werden, andernfalls empfangen Sie keine Nachrichten. –
Obwohl RegisterHotKey manchmal genau das ist, was Sie wollen, möchten Sie wahrscheinlich in den meisten Fällen keine systemweiten Hotkeys verwenden. Ich wurde unter Verwendung von Code wie folgt auf:
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"); } } } }
Dies ist eine voll funktionierende Lösung, hoffe, es hilft ...
Verbrauch:
_hotKey = new HotKey(Key.F9, KeyModifier.Shift | KeyModifier.Win, OnHotKeyHandler);
...
private void OnHotKeyHandler(HotKey hotKey)
{
SystemHelper.SetScreenSaverRunning();
}
Klasse:
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
}
// ******************************************************************
}
Ich weiß, es ist eine Weile her, aber wenn ich meine PrintScreen-Taste registriert, funktioniert die eigentliche "PrintScreen" -Methode nicht mehr. "handled = true" hat auch nicht funktioniert. Irgendwelche Vorschläge? – ErwinOkken
@ErwinOkken, ich bin mir nicht sicher, richtig zu verstehen. Ein HotKey ist global für Ihre Sitzung (~ global für Ihren Computer). Wenn Sie "PrintScreen" registrieren, sollte diese Taste in Ihrem Programm verwendet werden, wenn Sie sie drücken. Schließen Sie Ihr Programm sollte "PrintScreen" als normal laufen lassen (bevor Sie Ihr Programm ausführen). Meinst du, dass du "PrintScreen" nicht in deinem Programm handhaben (registrieren) kannst? –
Sorry, wenn ich unklar war. Die PrintScreen-Funktion sollte nicht ihre ursprüngliche Funktion verlieren: Speichern Sie das Bild in der Zwischenablage. Wenn oder nachdem das passiert, muss ich es haken. – ErwinOkken
Ich habe das Projekt Global Hotkeys in WPF auf codeproject.com gefunden, das den Job für mich erledigt. Es ist relativ neu, benötigt keinen Verweis auf System.Windows.Forms und funktioniert "global" in Bezug auf das Drücken auf den Hotkey, selbst wenn "Ihre" Anwendung nicht das aktive Fenster ist.
Das Registrieren von Verknüpfungen auf Betriebssystemebene ist fast nie eine gute Sache: Benutzer möchten nicht, dass Sie sich mit ihrem Betriebssystem anlegen.
Das heißt, gibt es eine viel einfachere und benutzerfreundliche Art und Weise dies in WPF zu tun, wenn Sie in der Anwendung mit dem Hotkey arbeiten (dh solange Ihre WPF-Anwendung den Fokus hat) ok sind:
In 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
}
Es ist so einfach
Müssen Sie die Registrierung manuell aufheben? – Joel
Es wird automatisch entfernt, wenn Sie die App schließen, andernfalls müssen Sie die Registrierung innerhalb der Lebensdauer der App aufheben. –
+1 für die Einfachheit und um darauf hinzuweisen, dass Verknüpfungen auf Betriebssystemebene schlecht sind. Einverstanden. – Joel
Pavian-Lösung funktioniert am besten, weil Sie mehrere Fenster haben. Ich habe es optimiert, so dass es das PreviewKeyDownEvent anstelle des PreviewKeyUpEvent verwendet, um Wiederholungen in Tastenanschlägen zu behandeln.
Ich würde von der Registrierung auf Betriebssystemebene abraten, es sei denn, Sie schreiben etwas wie ein Snipping-Tool oder eine Audioaufnahme-App, da Sie auf Funktionen zugreifen können, wenn das Fenster nicht fokussiert ist.
Diese auf die Antworten ähnlich ist bereits gegeben, aber ich es ein bisschen sauberer finden:
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.
}
}
}
ich es auf fluxbytes.com gefunden habe.
Von der Win32-Funktion "RegisterHotKey" (http://msdn.microsoft.com/en-us/library/ms646309.aspx) Dokumentation: "Tastaturkürzel, die den WINDOWS-Schlüssel enthalten, sind für den Betrieb reserviert System." –
@Iankemp: Bis sie vom Betriebssystem verwendet werden, können Sie sie in Ihren Apps verwenden. Ja, deshalb gab MS Win + N und Win + Shift + N an OneNote ;-) –