API関数のRegisterHotKeyおよびUnregisterHotKeyを使用することで、ウィンドウハンドルに関連づけられたホットキーを設定・解除する事ができる。 ホットキーを指定する際は、キーコードと修飾キー(ALT, CTRL, SHIFT)及び、ホットキーのIDを指定する必要がある。 ホットキーのIDは、0x0000~0xBFFFの範囲でアプリケーションに一意な値を設定する必要がある。

登録したホットキーが実際に押されたときにはWM_HOTKEYメッセージが送られてくるので、これに対してフォームをアクティブにする記述をすれば、ホットキーが押された時点でフォームをアクティブにすることができる。 複数のホットキーから目的のものを識別するためには、lParamの値を比較する必要がある。

なお、RegisterHotKeyで指定するキーコード・修飾キーの値は、Keys列挙体の値を使うことができるが、修飾キーとして使えるWindowsロゴキーに該当するメンバがないので、個別に定数などを用意する必要がある。 さらに、システムや他のアプリケーションで既に使用されている場合は、そのホットキーを登録をすることはできない(RegisterHotKeyの呼び出しに失敗する)。

以下の例では、Ctrl+Spaceでフォームをアクティブにし、Win+Enter通知音(SystemSounds.Beep)を鳴らすようにホットキーの割り当てを行っている。

using System;
using System.ComponentModel;
using System.Media;
using System.Runtime.InteropServices;
using System.Windows.Forms;

/// <summary>ホットキーの登録・解除を行うためのクラス</summary>
class HotKey {
  [DllImport("user32", SetLastError = true)]
  private static extern int RegisterHotKey(IntPtr hWnd,
                                           int id,
                                           int fsModifier,
                                           int vk);

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

  public HotKey(IntPtr hWnd, int id, Keys key)
  {
    this.hWnd = hWnd;
    this.id = id;

    // Keys列挙体の値をWin32仮想キーコードと修飾キーに分離
    int keycode = (int)(key & Keys.KeyCode);
    int modifiers = (int)(key & Keys.Modifiers) >> 16;

    this.lParam = new IntPtr(modifiers | keycode << 16);

    if (RegisterHotKey(hWnd, id, modifiers, keycode) == 0)
      // ホットキーの登録に失敗
      throw new Win32Exception(Marshal.GetLastWin32Error());
  }

  public void Unregister()
  {
    if (hWnd == IntPtr.Zero)
      return;

    if (UnregisterHotKey(hWnd, id) == 0)
      // ホットキーの解除に失敗
      throw new Win32Exception(Marshal.GetLastWin32Error());

    hWnd = IntPtr.Zero;
  }

  public IntPtr LParam {
    get { return lParam; }
  }

  private IntPtr hWnd; // ホットキーの入力メッセージを受信するウィンドウのhWnd
  private readonly int id; // ホットキーのID(0x0000〜0xBFFF)
  private readonly IntPtr lParam; // WndProcメソッドで押下されたホットキーを識別するためのlParam値
}

public class Form1 : Form {
  static void Main()
  {
    Application.Run(new Form1());
  }

  private HotKey hotkeyActivate;
  private HotKey hotkeyNotify;

  protected override void OnLoad(EventArgs e)
  {
    const Keys modifierWinKey = (Keys)0x00080000; // Windowsロゴキー

    // Ctrl+SpaceをID 0のホットキーとして登録
    hotkeyActivate = new HotKey(this.Handle, 0, Keys.Control | Keys.Space);

    // Win+EnterをID 1のホットキーとして登録
    hotkeyNotify = new HotKey(this.Handle, 1, modifierWinKey | Keys.Enter);
  }

  protected override void OnClosing(CancelEventArgs e)
  {
    // 登録しているホットキーを解除
    hotkeyActivate.Unregister();
    hotkeyNotify.Unregister();
  }

  // ホットキーの入力メッセージを処理する
  protected override void WndProc(ref Message m)
  {
    const int WM_HOTKEY = 0x312;

    if (m.Msg == WM_HOTKEY && m.LParam == hotkeyActivate.LParam) {
      // フォームをアクティブにする
      Activate();
    }
    else if (m.Msg == WM_HOTKEY && m.LParam == hotkeyNotify.LParam) {
      // 通知音を鳴らす
      SystemSounds.Beep.Play();
    }
    else {
      base.WndProc(ref m);
    }
  }
}
Imports System
Imports System.ComponentModel
Imports System.Media
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

''' <summary>ホットキーの登録・解除を行うためのクラス</summary>
Class HotKey
  <DllImport("user32", SetLastError := True)> _
  Private Shared Function RegisterHotKey(ByVal hWnd As IntPtr, _
                                         ByVal id As Integer, _
                                         ByVal fsModifier As Integer, _
                                         ByVal vk As Integer) As Integer
  End Function

  <DllImport("user32", SetLastError := True)> _
  Private Shared Function UnregisterHotKey(ByVal hWnd As IntPtr, _
                                           ByVal id As Integer) As Integer
  End Function

  Public Sub New(ByVal hWnd As IntPtr, ByVal id As Integer, ByVal key As Keys)
    Me.hWnd = hWnd
    Me.id = id

    ' Keys列挙体の値をWin32仮想キーコードと修飾キーに分離
    Dim keycode As Integer = CInt(key And Keys.KeyCode)
    Dim modifiers As Integer = CInt(key And Keys.Modifiers) >> 16

    Me._lParam = New IntPtr(modifiers Or keycode << 16)

    If RegisterHotKey(hWnd, id, modifiers, keycode) = 0 Then
      ' ホットキーの登録に失敗
      Throw New Win32Exception(Marshal.GetLastWin32Error())
    End If
  End Sub

  Public Sub Unregister()
    If hWnd = IntPtr.Zero Then Return

    If UnregisterHotKey(hWnd, id) = 0 Then
      ' ホットキーの解除に失敗
      Throw New Win32Exception(Marshal.GetLastWin32Error())
    End If

    hWnd = IntPtr.Zero
  End Sub

  Public ReadOnly Property LParam As IntPtr
    Get
      Return _lParam
    End Get
  End Property

  Private hWnd As IntPtr ' ホットキーの入力メッセージを受信するウィンドウのhWnd
  Private ReadOnly id As Integer ' ホットキーのID(0x0000〜0xBFFF)
  Private ReadOnly _lParam As IntPtr ' WndProcメソッドで押下されたホットキーを識別するためのlParam値
End Class

Public Class Form1
  Inherits Form

  Public Shared Sub Main()
    Application.Run(New Form1())
  End Sub

  Private hotkeyActivate As HotKey
  Private hotkeyNotify As HotKey

  Protected Overrides Sub OnLoad(ByVal e As EventArgs)
    Const modifierWinKey As Keys = CType(&h00080000, Keys) ' Windowsロゴキー

    ' Ctrl+SpaceをID 0のホットキーとして登録
    hotkeyActivate = New HotKey(Me.Handle, 0, Keys.Control Or Keys.Space)

    ' Win+EnterをID 1のホットキーとして登録
    hotkeyNotify = New HotKey(Me.Handle, 1, modifierWinKey Or Keys.Enter)
  End Sub

  Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)
    ' 登録しているホットキーを解除
    hotkeyActivate.Unregister()
    hotkeyNotify.Unregister()
  End Sub

  ' ホットキーの入力メッセージを処理する
  Protected Overrides Sub WndProc(ByRef m As Message)
    Const WM_HOTKEY As Integer = &H312

    If m.Msg = WM_HOTKEY AndAlso m.LParam = hotkeyActivate.LParam Then
      ' フォームをアクティブにする
      Me.Activate()
    Else If m.Msg = WM_HOTKEY AndAlso m.LParam = hotkeyNotify.LParam Then
      ' 通知音を鳴らす
      SystemSounds.Beep.Play()
    Else
      MyBase.WndProc(m)
    End If
  End Sub
End Class