При открытой игре не работает globalHook
Написал небольшой органайзер для админов одного из проектов GTA 5 RP.
Внутри программы есть функция "Режим последовательной работы".
Пример работы режима
Так вот.... Если работать сначало с приложением, а затем не закрывая AdminReports запустить GTA 5, то внутри GTA данный режим работать не будет, он попросту не реагирует, такое чувство, что GTA перекрывает это. Решается данная проблема перезапуском ADminReports.
Как то можно обойти перезапуск и сделать все по человечески?
Заранее спасибо.
Исходники всего проекта (Visual Studio 2019 C# WinForms): https://github.com/mihail727/AdminReports
Сам хук (Version 1): https://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C


Реализация внутри проекта:
MainForm (Конструктор):
actHook = new UserActivityHook();
actHook.KeyDown += new KeyEventHandler(GlobalKeyPress);
Event для глобал хук:
private async void GlobalKeyPress(object sender, KeyEventArgs e)
{
if (isCopyPast)
{
if (textRow == null)
{
ShowProgress("Ошибка данных");
return;
}
Clipboard.SetText(textRow[currentColumn]);
await Task.Run(() =>
{
Task.Delay(50);
SendKeys.Send("^V");
});
ShowProgress("Было скопировано и выведено: " + textRow[currentColumn]);
currentColumn++;
}
else
ShowProgress("Режим последовательной вставки не включен");
textRow - коллекция строк, которые как раз таки последовательно и выводятся по нажатию на Ctrl + V.
Спасибо за решение проблемы пользователю с ником aepot.
Изменения после которых все заработало:
- Конструктор MainForm:
_hotKey = new HotKey(Handle, Keys.V, HotKeyModifiers.Control);
_hotKey.HotKeyPressed += OnHotKeyPressed;
- Был переписан метод GlobalKeyPress ----> OnHotKeyPressed:
private async void OnHotKeyPressed(object sender, KeyEventArgs e)
{
if (isCopyPast)
{
if(textRow == null)
{
ShowProgress("Данные из строки не сохранены");
return;
}
Clipboard.SetText(textRow[CurrentColumn]);
await Task.Delay(50);
_hotKey.Enabled = false;
PressCtrlV();
_hotKey.Enabled = true;
ShowProgress("Было скопировано и выведено: " + textRow[CurrentColumn]);
CurrentColumn++;
}
else
ShowProgress("Режим последовательной вставки не включен");
}
- Естественно был убран предыдущий хук и добавлен новый предложенный пользователем aepot.
Ответы (1 шт):
Все-таки лучше такое делать через регистрацию горячих клавиш. Написал пример, который делает то что вам нужно с асинхронным обработчиком нажатия горячей комбинации.
Возможности решения
- юзер может задать любую комбинацию горячих клавиш в текстбоксе
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;
}
}