Все-таки лучше такое делать через регистрацию горячих клавиш. Написал пример, который делает то что вам нужно с асинхронным обработчиком нажатия горячей комбинации.
Возможности решения
- юзер может задать любую комбинацию горячих клавиш в текстбоксе
textBoxHotkey (в дизайнере установлен как ReadOnly).
- ввести любой текст во второй большой текстбокс
textBox1
- включить или отключит хоткей в
checkBox1
- если хоткей активен,
textBoxHotkey окрасится в зеленый, если ошибка регистрации клавиши - в красный, если неактивен - серый, если сейчас редактируется - белый.
- если хоткей активен, то при нажатии на хоткей, произойдет вставка из буфера обмена текста, который расположен в
textBox1
Потребуется энумератор клавиатурных модификаторов
HotKeyModifiers.cs
[Flags]
public enum HotKeyModifiers : int
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8
}
Далее Win32 API.
NativeMethods.cs
internal static class NativeMethods
{
[DllImport("user32.dll")]
public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll")]
public static extern uint MapVirtualKey(Keys uCode, uint uMapType);
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, HotKeyModifiers fsModifiers, Keys vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
}
Сам класс для работы с горячими клавишами
HotKey.cs
public class HotKey : IMessageFilter, IDisposable
{
private const int WM_HOTKEY = 0x0312;
public event KeyEventHandler HotKeyPressed;
private readonly int _id;
private bool _enabled;
public IntPtr Handle { get; }
public bool Registered { get; private set; }
public bool Enabled
{
get => _enabled;
set
{
if (_enabled != value)
{
_enabled = value;
if (_enabled)
Register();
else
Unregister();
}
}
}
public Keys Key { get; private set; }
public HotKeyModifiers Modifiers { get; private set; }
public HotKey(IntPtr handle, Keys key, HotKeyModifiers modifiers)
{
Handle = handle;
_id = GetHashCode();
Application.AddMessageFilter(this);
ChangeKeys(key, modifiers);
}
private void Register()
{
if (!Registered && Key != Keys.None && Modifiers != HotKeyModifiers.None)
Registered = NativeMethods.RegisterHotKey(Handle, _id, Modifiers, Key);
}
private void Unregister()
{
if (Registered)
{
NativeMethods.UnregisterHotKey(Handle, _id);
Registered = false;
}
}
public void ChangeKeys(Keys key, HotKeyModifiers modifiers)
{
if (Enabled) Unregister();
Key = key;
Modifiers = modifiers;
if (Enabled) Register();
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_HOTKEY && (int)m.WParam == _id)
{
KeyEventArgs args = new KeyEventArgs((IsButtonDown(m.LParam, HotKeyModifiers.Alt) ? Keys.Alt : Keys.None)
| (IsButtonDown(m.LParam, HotKeyModifiers.Control) ? Keys.Control : Keys.None)
| (IsButtonDown(m.LParam, HotKeyModifiers.Shift) ? Keys.Shift : Keys.None) | Key);
OnHotKeyPressed(args);
return true;
}
return false;
}
private bool IsButtonDown(IntPtr ptr, HotKeyModifiers modifiers) => Convert.ToBoolean(((long)ptr) & (long)modifiers);
private void OnHotKeyPressed(KeyEventArgs e) => HotKeyPressed?.Invoke(this, e);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
}
Unregister();
Application.RemoveMessageFilter(this);
_disposed = true;
}
}
~HotKey()
{
Dispose(false);
}
}
Enabled - включен/выключен
Registerd - зарегистрирован/не зарегистрирован
Класс для преобразования комбинации клавиш в строку и обратно
HotKeyConverter.cs
public static class HotKeyConverter
{
public static string Keys2String(Keys key, HotKeyModifiers modifiers)
{
string hotkey =
(modifiers.HasFlag(HotKeyModifiers.Control) ? "Ctrl+" : string.Empty) +
(modifiers.HasFlag(HotKeyModifiers.Alt) ? "Alt+" : string.Empty) +
(modifiers.HasFlag(HotKeyModifiers.Shift) ? "Shift+" : string.Empty);
if (hotkey.Length != 0 && (key < Keys.LShiftKey || key > Keys.RMenu) && key != Keys.LWin && key != Keys.RWin && key != Keys.ShiftKey && key != Keys.ControlKey && key != Keys.Menu) //exclude modifiers as keys
{
string keyCode = key.ToString();
if (key >= Keys.D0 && key <= Keys.D9) keyCode = keyCode.Substring(1);
else if (key == Keys.Oem3) keyCode = "~";
hotkey += keyCode;
}
if (hotkey.Length == 0) hotkey = "None";
return hotkey;
}
public static HotKeyModifiers GetModifier(string hotkey)
{
HotKeyModifiers result = HotKeyModifiers.None;
if (hotkey?.Length > 1 && hotkey.Contains("+"))
{
string modifiers = hotkey.Remove(hotkey.LastIndexOf('+')).Replace("Ctrl", "Control");
foreach (HotKeyModifiers m in Enum.GetValues(typeof(HotKeyModifiers)))
{
if (modifiers.Contains(m.ToString())) result |= m;
}
}
return result;
}
public static Keys GetKey(string hotkey)
{
if (hotkey?.Length > 1 && hotkey.Contains("+") && !hotkey.EndsWith("+"))
{
string key = hotkey.Split('+').Last().Replace("~", "Oem3");
if (key.Length == 1 && key[0] >= '0' && key[0] <= '9') key = 'D' + key;
return Enum.TryParse(key, out Keys result) ? result : Keys.None;
}
return Keys.None;
}
}
Ну и сама форма
Form1.cs
public partial class Form1 : Form
{
private HotKey _hotKey;
public Form1()
{
InitializeComponent();
}
private void textBoxHotkey_KeyDown(object sender, KeyEventArgs e)
{
Keys key = e.KeyCode;
HotKeyModifiers modifiers = e.Control ? HotKeyModifiers.Control : HotKeyModifiers.None;
modifiers |= e.Alt ? HotKeyModifiers.Alt : HotKeyModifiers.None;
modifiers |= e.Shift ? HotKeyModifiers.Shift : HotKeyModifiers.None;
if (sender is TextBox textBox && !(modifiers == HotKeyModifiers.None && (key == Keys.Enter || key == Keys.Escape)))
{
textBox.Text = HotKeyConverter.Keys2String(key, modifiers);
e.Handled = true;
}
}
private void textBoxHotkey_KeyUp(object sender, KeyEventArgs e)
{
HotKeyModifiers modifiers = e.Control ? HotKeyModifiers.Control : HotKeyModifiers.None;
modifiers |= e.Alt ? HotKeyModifiers.Alt : HotKeyModifiers.None;
modifiers |= e.Shift ? HotKeyModifiers.Shift : HotKeyModifiers.None;
if (sender is TextBox textBox && (textBox.Text.Length > 1 && textBox.Text.EndsWith("+") || textBox.Text.Length == 1))
{
textBox.Text = modifiers == HotKeyModifiers.None ? "None" : HotKeyConverter.Keys2String(e.KeyCode, modifiers);
e.Handled = true;
}
}
private void textBoxHotkey_Enter(object sender, EventArgs e)
{
_hotKey.Enabled = false;
textBoxHotkey.BackColor = SystemColors.Window;
}
private void textBoxHotkey_Leave(object sender, EventArgs e)
{
textBoxHotkey.BackColor = SystemColors.Control;
if (sender is TextBox textBox && textBox.Text != "None")
{
_hotKey.ChangeKeys(HotKeyConverter.GetKey(textBox.Text), HotKeyConverter.GetModifier(textBox.Text));
_hotKey.Enabled = checkBox1.Checked;
SetTextBoxColor();
}
}
private void SetTextBoxColor()
{
if (_hotKey.Enabled && textBoxHotkey.Text != "None")
{
textBoxHotkey.BackColor = _hotKey.Registered ? Color.LightGreen : Color.LightPink;
}
else
textBoxHotkey.BackColor = SystemColors.Control;
}
private void Form1_Load(object sender, EventArgs e)
{
_hotKey = new HotKey(Handle, Keys.None, HotKeyModifiers.None);
_hotKey.HotKeyPressed += OnHotKeyPressed;
}
private async void OnHotKeyPressed(object sender, KeyEventArgs e)
{
if (textBox1.Text.Length > 0)
{
Clipboard.SetText(textBox1.Text);
do
{
await Task.Delay(50);
}
while (ModifierKeys != Keys.None);
PressCtrlV();
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (sender is CheckBox checkBox)
{
_hotKey.Enabled = checkBox.Checked;
SetTextBoxColor();
}
}
private void PressCtrlV()
{
NativeMethods.keybd_event(Keys.ControlKey, (byte)NativeMethods.MapVirtualKey(Keys.ControlKey, 0), 0, 0);
NativeMethods.keybd_event(Keys.V, (byte)NativeMethods.MapVirtualKey(Keys.V, 0), 0, 0);
Thread.Sleep(100);
NativeMethods.keybd_event(Keys.V, (byte)NativeMethods.MapVirtualKey(Keys.V, 0), 0x02, 0);
NativeMethods.keybd_event(Keys.ControlKey, (byte)NativeMethods.MapVirtualKey(Keys.ControlKey, 0), 0x02, 0);
}
}
Пробуйте, тестируйте. Кстати, это не будет работать, если вы выбрали в качестве горячих клавиш Ctrl+V, чтобы заработало, нужно снимать HotKey с регистрации.
Например, можно обработчик доработать вот так
private async void OnHotKeyPressed(object sender, KeyEventArgs e)
{
if (textBox1.Text.Length > 0)
{
Clipboard.SetText(textBox1.Text);
do
{
await Task.Delay(50);
}
while (ModifierKeys != Keys.None);
_hotKey.Enabled = false;
PressCtrlV();
_hotKey.Enabled = true;
}
}
RegisterHotKey? Если да, то что именно вас не устраивает? Перестает срабатывать горячая клавиша (проверяли ли точкой останова)? Или игра не видит изменений в буфере обмена? – aepot Jun 11 '20 at 21:40Ctrl+1. А затем бы менял буфер обмена и эмулировал бы нажатиеCtrl+Vчерез Win32 APIkeybd_eventилиSendInput. В этом случае хотя-бы не пришлось бы париться с включением/отключением режима специальной вставки, потому что обычныйCtrl+Vпродолжит работать. – aepot Jun 11 '20 at 22:11Ctrl+Vнадо асинхронно, освободив UI поток.Clipboard.SetText(...); Task.Run(async () => { await Task.Delay(50); SendCtrlV(); });– aepot Jun 11 '20 at 22:26SendKeys.Send("^V").... Есть проблема теперь вставка срабатывает даже когда нажата только клавиша Ctrl – Supp Jun 13 '20 at 13:52if (isCopyPast)а где проверка на то, что именно сейчас нажато пользователем? – aepot Jun 13 '20 at 14:07