且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在控制台应用程序全局热键

更新时间:2023-02-17 19:59:57

你可以做的是建立在你的控制台应用程序隐藏的窗口,它是用来处理热键通知,并引发事件。

在code HERE说明了校长。 这里是在一个控制台应用程序处理消息,使用这个你应该能够提升的文章HotKeyManager在一个控制台应用程序运行。

下面更新到HotKeyManager创建运行于消息循环后台线程和处理窗口消息。

 使用系统;
使用System.Windows.Forms的;
使用System.Runtime.InteropServices;
使用的System.Threading;命名空间ConsoleHotKey
{
  公共静态类HotKeyManager
  {
    公共静态事件的EventHandler< HotKeyEventArgs>热键pressed;    公共静态INT RegisterHotKey(键键,KeyModifiers修饰符)
    {
      _windowReadyEvent.WaitOne();
      INT ID = System.Threading.Interlocked.Increment(REF _id);
      _wnd.Invoke(新RegisterHotKeyDelegate(RegisterHotKeyInternal),_hwnd,ID,(UINT)改性剂(UINT)键);
      返回ID;
    }    公共静态无效UnregisterHotKey(INT ID)
    {
      _wnd.Invoke(新UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal),_hwnd,身份证);
    }    委托无效RegisterHotKeyDelegate(IntPtr的HWND,INT ID,UINT改性剂,UINT键);
    委托无效UnRegisterHotKeyDelegate(IntPtr的HWND,INT ID);    私有静态无效RegisterHotKeyInternal(IntPtr的HWND,INT ID,UINT改性剂,UINT键)
    {
      RegisterHotKey(HWND,ID,改性剂,键);
    }    私有静态无效UnRegisterHotKeyInternal(IntPtr的HWND,INT ID)
    {
      UnregisterHotKey(_hwnd,身份证);
    }    私有静态无效OnHotKey pressed(HotKeyEventArgs E)
    {
      如果(HotKeyManager.HotKey pressed!= NULL)
      {
        HotKeyManager.HotKey pressed(NULL,E);
      }
    }    私有静态挥发消息窗_wnd;
    私有静态挥发的IntPtr _hwnd;
    私有静态的ManualResetEvent _windowReadyEvent =新的ManualResetEvent(假);
    静态HotKeyManager()
    {
      线程消息循环=新主题(委托()
        {
          Application.Run(新消息窗());
        });
      messageLoop.Name =MessageLoopThread;
      messageLoop.IsBackground = TRUE;
      messageLoop.Start();
    }    私有类消息窗:表单
    {
      公开消息窗()
      {
        _wnd =这一点;
        _hwnd = this.Handle;
        _windowReadyEvent.Set();
      }      保护覆盖无效的WndProc(参考消息M)
      {
        如果(m.Msg == WM_HOTKEY)
        {
          HotKeyEventArgs E =新HotKeyEventArgs(m.LParam);
          HotKeyManager.OnHotKey pressed(E);
        }        base.WndProc(REF米);
      }      保护覆盖无效SetVisibleCore(布尔值)
      {
        //确保窗口永远不会变得可见
        base.SetVisibleCore(假);
      }      私人const int的WM_HOTKEY = 0x312;
    }    函数[DllImport(USER32,SetLastError = TRUE)]
    私人静态外部布尔RegisterHotKey(IntPtr的的HWND,INT ID,UINT fsModifiers,UINT VK);    函数[DllImport(USER32,SetLastError = TRUE)]
    私人静态外部布尔UnregisterHotKey(IntPtr的的HWND,INT ID);    私有静态诠释_id = 0;
  }
  公共类HotKeyEventArgs:EventArgs的
  {
    公共只读按键按键;
    公共只读KeyModifiers剂;    公共HotKeyEventArgs(键键,KeyModifiers修饰符)
    {
      this.Key =键;
      this.Modifiers =改性剂;
    }    公共HotKeyEventArgs(IntPtr的hotKeyParam)
    {
      UINT参数=(UINT)hotKeyParam.ToInt64();
      键=(钥匙)((参数&安培;为0xffff0000)GT;> 16);
      修饰符=(KeyModifiers)(参数&安培; 0x0000ffff);
    }
  }  [国旗]
  公共枚举KeyModifiers
  {
    中高音= 1,
    对照= 2,
    移= 4,
    窗户= 8,
    NoRepeat = 0x4000的
  }
}

下面是一个使用HotKeyManager从控制台应用程序

的例子
 使用系统;
使用System.Windows.Forms的;命名空间ConsoleHotKey
{
  类节目
  {
    静态无效的主要(字串[] args)
    {
      HotKeyManager.RegisterHotKey(Keys.A,KeyModifiers.Alt);
      HotKeyManager.HotKey pressed + =新的EventHandler< HotKeyEventArgs>(HotKeyManager_HotKey pressed);
      到Console.ReadLine();
    }    静态无效HotKeyManager_HotKey pressed(对象发件人,HotKeyEventArgs E)
    {
      Console.WriteLine(打我!);
    }
  }
}

Does anyone know how to use the RegisterHotKey/UnregisterHotKey API calls in a console application? I assume that setting up/removing the hotkey is the same, but how do I get the call back when the key was pressed?

Every example I see is for Winforms, and uses protected override void WndProc(ref Message m){...}, which isn't available to me.


update: what I have is below, but the event is never hit. I thought it could be because when you load ConsoleShell it does block further execution, but even if I put SetupHotkey into a different thread nothing happens. Any thoughts?
class Program
{
    static void Main(string[] args)
    {
        new Hud().Init(args);
    }
}

class Hud
{
    int keyHookId;


    public void Init(string[] args)
    {
        SetupHotkey();
        InitPowershell(args);
        Cleanup();
    }

    private void Cleanup()
    {
        HotKeyManager.UnregisterHotKey(keyHookId);
    }

    private void SetupHotkey()
    {
        keyHookId = HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Control);
        HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
    }

    void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
    {
        //never executed
        System.IO.File.WriteAllText("c:\\keyPressed.txt", "Hotkey pressed");
    }

    private static void InitPowershell(string[] args)
    {
        var config = RunspaceConfiguration.Create();
        ConsoleShell.Start(config, "", "", args);
    }
}

What you can do is Create a hidden window in your Console application which is used to handle the hotkey notification and raise an event.

The code HERE demonstrates the principal. HERE is an article on handling messages in a Console application, using this you should be able to enhance HotKeyManager to run in a Console Application.

The following update to the HotKeyManager creates a background thread which runs the message loop and handles the windows messages.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;

namespace ConsoleHotKey
{
  public static class HotKeyManager
  {
    public static event EventHandler<HotKeyEventArgs> HotKeyPressed;

    public static int RegisterHotKey(Keys key, KeyModifiers modifiers)
    {
      _windowReadyEvent.WaitOne();
      int id = System.Threading.Interlocked.Increment(ref _id);
      _wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
      return id;
    }

    public static void UnregisterHotKey(int id)
    {
      _wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
    }

    delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
    delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);

    private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key)
    {      
      RegisterHotKey(hwnd, id, modifiers, key);      
    }

    private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id)
    {
      UnregisterHotKey(_hwnd, id);
    }    

    private static void OnHotKeyPressed(HotKeyEventArgs e)
    {
      if (HotKeyManager.HotKeyPressed != null)
      {
        HotKeyManager.HotKeyPressed(null, e);
      }
    }

    private static volatile MessageWindow _wnd;
    private static volatile IntPtr _hwnd;
    private static ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);
    static HotKeyManager()
    {
      Thread messageLoop = new Thread(delegate()
        {
          Application.Run(new MessageWindow());
        });
      messageLoop.Name = "MessageLoopThread";
      messageLoop.IsBackground = true;
      messageLoop.Start();      
    }

    private class MessageWindow : Form
    {
      public MessageWindow()
      {
        _wnd = this;
        _hwnd = this.Handle;
        _windowReadyEvent.Set();
      }

      protected override void WndProc(ref Message m)
      {
        if (m.Msg == WM_HOTKEY)
        {
          HotKeyEventArgs e = new HotKeyEventArgs(m.LParam);
          HotKeyManager.OnHotKeyPressed(e);
        }

        base.WndProc(ref m);
      }

      protected override void SetVisibleCore(bool value)
      {
        // Ensure the window never becomes visible
        base.SetVisibleCore(false);
      }

      private const int WM_HOTKEY = 0x312;
    }

    [DllImport("user32", SetLastError=true)]
    private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

    [DllImport("user32", SetLastError = true)]
    private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    private static int _id = 0;
  }


  public class HotKeyEventArgs : EventArgs
  {
    public readonly Keys Key;
    public readonly KeyModifiers Modifiers;

    public HotKeyEventArgs(Keys key, KeyModifiers modifiers)
    {
      this.Key = key;
      this.Modifiers = modifiers;
    }

    public HotKeyEventArgs(IntPtr hotKeyParam)
    {
      uint param = (uint)hotKeyParam.ToInt64();
      Key = (Keys)((param & 0xffff0000) >> 16);
      Modifiers = (KeyModifiers)(param & 0x0000ffff);
    }
  }

  [Flags]
  public enum KeyModifiers
  {
    Alt = 1,
    Control = 2,
    Shift = 4,
    Windows = 8,
    NoRepeat = 0x4000
  }
}

Here is an example of using HotKeyManager from a Console application

using System;
using System.Windows.Forms;

namespace ConsoleHotKey
{
  class Program
  {
    static void Main(string[] args)
    {
      HotKeyManager.RegisterHotKey(Keys.A, KeyModifiers.Alt);
      HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
      Console.ReadLine();      
    }

    static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
    {
      Console.WriteLine("Hit me!");
    }
  }
}