Обнаружение Ctrl+V с помощью RegisterHotKey, но не перехват его

Мне нужно определить, когда пользователь нажимает Ctrl+V (независимо от фокуса окна — мое приложение, скорее всего, будет свернуто), но я не должен останавливать фактическую операцию вставки.

Я пробовал несколько вещей: (я успешно привязываюсь к нажатиям клавиш с помощью RegisterHotKey)

У меня есть:

protected override void WndProc(ref Message m)
{
  if (m.Msg == 0x312)
    hotKey();
  base.WndProc(ref m);
}

и я пробовал следующее:

void hotKey()
{
  SendKeys.SendWait("^v"); //just puts 'v' instead of clipboard contents
}

и

void hotKey()
{
  SendKeys.SendWait(ClipBoard.GetText());
  /* This works, but since Ctrl is still down, it triggers
   * all the shortcut keys for the app, e.g. if the keyboard
   * contains 's' then instead of putting 's' in the app, it
   * calls Ctrl+S which makes the app think the user wants
   * to save.
   */
}

В настоящее время единственным рабочим решением, которое у меня есть, является привязка к чему-то другому, например. Ctrl+B, а затем вызовите SendKeys.SendWait("^v");, однако это не идеально.

Идеальным решением было бы, если бы мое окно не перехватывало нажатие клавиши, а просто реагировало.


person Ozzah    schedule 27.07.2011    source источник
comment
Можете уточнить свой вопрос? Мне трудно понять ваше намерение. Вы упомянули, что просто хотите остановить фактическую операцию вставки, но почему вы пытаетесь снова отправить Ctrl + V в своей первой реализации hotkey(). Правильно ли я предполагаю, что вы хотите перехватывать общесистемные операции вставки и сохранять значения буфера обмена в своем приложении?   -  person Ilian    schedule 27.07.2011
comment
Нет, я написал, что не должен останавливать фактическую операцию вставки. Я хочу обнаруживать общесистемные операции вставки и впоследствии заменять содержимое буфера обмена, чтобы пользователь мог нажимать Ctrl + V несколько раз и каждый раз, когда вставляется следующий элемент. Программа предназначена для ускорения (и предотвращения ошибок) лица, вводящего данные.   -  person Ozzah    schedule 27.07.2011
comment
В порядке. Я неправильно это понял. Для этого можно использовать хуки Windows. Смотрите мой ответ ниже.   -  person Ilian    schedule 27.07.2011


Ответы (1)


Вы можете сделать это, используя хуки, используя SetWindowsHookEx().

HHOOK WINAPI SetWindowsHookEx(
  __in  int idHook,
  __in  HOOKPROC lpfn,
  __in  HINSTANCE hMod,
  __in  DWORD dwThreadId
);

По сути, вы можете настроить низкоуровневый хук клавиатуры:

_hookHandle = SetWindowsHookEx(
    WH_KEYBOARD_LL,
    KbHookProc,                   // Your keyboard handler
    (IntPtr)0,
    0);                           // Set up system-wide hook.

для захвата общесистемных событий клавиатуры. Но это также позволяет вам передавать эти события клавиатуры другим приложениям. Для вашего конкретного случая вы можете определить KbHookProc как:

private static int KbHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0) // This means we can intercept the event.
    {
        var hookStruct = (KbLLHookStruct)Marshal.PtrToStructure(
                lParam,
                typeof(KbLLHookStruct));

        // Quick check if Ctrl key is down. 
        // See GetKeyState() doco for more info about the flags.
        bool ctrlDown = 
                GetKeyState(VK_LCONTROL) != 0 ||
                GetKeyState(VK_RCONTROL) != 0;

        if (ctrlDown && hookStruct.vkCode == 0x56) // Ctrl+V
        {
            // Replace this with your custom action.
            Clipboard.SetText("Hi");
        }
    }

    // Pass to other keyboard handlers. Makes the Ctrl+V pass through.
    return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
} 

Я написал быстрое и грязное приложение WinForms, чтобы проиллюстрировать это. Полный список кодов см. на странице http://pastebin.com/uCSvqwb4.

person Ilian    schedule 27.07.2011
comment
Я попытался преобразовать это для запуска в качестве консольного приложения, и оно просто не сработает. Вырежьте и вставьте в приложение Winforms, и оно отлично работает... Есть идеи, почему? - person codeputer; 24.02.2013
comment
Я думаю, что понял - ServiceWindowsHookEx требует цикла сообщений в потоке, который выполняет код - почти уверен, что у него нет цикла сообщений! - person codeputer; 24.02.2013