Windows のグローバル ホットキーで問題が発生しました。私と私の友人は、User32.dll からの RegisterHotkey 関数呼び出しを介して登録された Windows グローバル ホットキーを使用するプログラムを (C# で) 開発しています。
私のコンピューターではすべて正常に動作しますが、ホットキーが登録されている友人の PC では、キーを 1 回押して MOD_NOREPEAT フラグを指定しても、常に 2 回呼び出されます。2 つの同じホットキーを登録しようとしましたが、できません (指定されたホットキーの組み合わせに対して 1 つの登録呼び出しのみが許可され、2 つ目の同じ組み合わせは RegisterHotkey 関数によって拒否されます)。
ここにコードがあります。既に登録されているホットキーの単純なラッパーを作成しました (コードから登録済みの組み合わせを管理するため):
public class HotkeyStructure
{
/// <summary>
/// Id of registered hotkey structure
/// </summary>
public int HotkeyId { get; private set; }
/// <summary>
/// Hotkey modifiers (eg SHIFT + ALT etc)
/// </summary>
public int HotkeyModifiers { get; private set; }
/// <summary>
/// Virtual key code (all alphanumeric keys)
/// </summary>
public int VirtualKeyCode { get; private set; }
/// <summary>
/// Action executed when hotkey detected
/// </summary>
public Action OnHotkeyAction { get; set; }
public HotkeyStructure(Modifiers hotkeyModifiers, VirtualKeyCode virtualKeyCode, int hotkeyId)
{
this.HotkeyModifiers = (int)hotkeyModifiers;
this.VirtualKeyCode = (int)virtualKeyCode;
this.HotkeyId = hotkeyId;
}
}
登録されたハンドラーを管理しているクラスのコードは次のとおりです。
[Flags]
public enum Modifiers : int
{
NONE = 0,
MOD_ALT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_NOREPEAT = 0x4000,
MOD_SHIFT = 0x0004,
MOD_WIN = 0x0008
}
public sealed class HotkeyApi
{
//Constant which detects hotkey message
private const int WM_HOTKEY = 0x0312;
//processhandle pointer
IntPtr processHandle;
//process handle object
private HwndSource source;
//static list of all registered hotkeys
private static List<HotkeyStructure> _registeredHotkeys = new List<HotkeyStructure>();
//external library function import
[DllImport("User32.dll")]
private static extern bool RegisterHotKey(IntPtr handle, int hotkeyId, int modifiers, int virtualKey);
[DllImport("User32.dll")]
private static extern bool UnregisterHotKey(IntPtr handle, int hotkeyId);
public HotkeyApi(HwndSource source)
{
this.processHandle = source.Handle;
this.source = source;
//attaching hook to system message sources
this.source.AddHook(WndProc);
}
//message handler
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_HOTKEY)
{
HotkeyStructure structure = _registeredHotkeys.SingleOrDefault(h => h.HotkeyId == wParam.ToInt32());
if (structure != null)
{
structure.OnHotkeyAction();
}
}
return IntPtr.Zero;
}
/// <summary>
/// Registers HotkeyStructure with custom Action passed in parameter (action can be changed during execution via public field in returned HotkeyStructure
/// </summary>
/// <param name="hotkeyModifiers">Which key should be pressed with other key to fire an event (option NONE causes disability for selected keycode)</param>
/// <param name="keycode">Keycode which should be pressed with modifier</param>
/// <param name="eventHadler">Action which will be fired with registered hotkey</param>
/// <returns>null if register action failed (eg. registering new hotkey which is the same as one which already exist) otherwise new HotkeyStructure</returns>
public HotkeyStructure RegisterHotkey(Modifiers hotkeyModifiers, VirtualKeyCode keycode, Action eventHadler)
{
int id = _registeredHotkeys.Count + 1;
bool result = RegisterHotKey(processHandle, id, (int)hotkeyModifiers, (int)keycode);
if (result)
{
HotkeyStructure structure = new HotkeyStructure(hotkeyModifiers, keycode, id);
structure.OnHotkeyAction = eventHadler;
_registeredHotkeys.Add(structure);
return structure;
}
else
{
return null;
}
}
/// <summary>
/// Removes hotkey from the list
/// </summary>
/// <param name="hotkeyId">Id of hotkey structure (obj.HotkeyId)</param>
/// <returns>true if succeeds otherwise false</returns>
public bool UnregisterHotkey(int hotkeyId)
{
if (UnregisterHotKey(processHandle, hotkeyId))
{
var str = _registeredHotkeys.SingleOrDefault(h => h.HotkeyId == hotkeyId);
if (str != null)
{
_registeredHotkeys.Remove(str);
return true;
}
}
return false;
} }
このコードは App.xaml.cs の OnLoadCompleted メソッドで呼び出されます。
var source = PresentationSource.FromVisual(App.Current.MainWindow) as HwndSource;
Hotkeys = new HotkeyApi(source);
この問題の原因は何ですか?
(言語ミスの可能性があります。)