| 1 | using System; |
|---|
| 2 | using System.Diagnostics; |
|---|
| 3 | using System.IO; |
|---|
| 4 | using System.Runtime.InteropServices; |
|---|
| 5 | using System.Windows.Forms; |
|---|
| 6 | using Microsoft.Win32.SafeHandles; |
|---|
| 7 | using WiimoteLib; |
|---|
| 8 | |
|---|
| 9 | namespace Misuzilla.Applications.AppleWirelessKeyboardHelper |
|---|
| 10 | { |
|---|
| 11 | internal class Helper : IDisposable |
|---|
| 12 | { |
|---|
| 13 | public event EventHandler<AppleKeyboardEventArgs> FnKeyCombinationDown; |
|---|
| 14 | public event EventHandler<AppleKeyboardEventArgs> KeyDown; |
|---|
| 15 | public event EventHandler<AppleKeyboardEventArgs> KeyUp; |
|---|
| 16 | public event EventHandler<KeyEventArgs> SpecialKeyDown; |
|---|
| 17 | |
|---|
| 18 | public event EventHandler Disconnected; |
|---|
| 19 | |
|---|
| 20 | public Boolean CurrentPowerButtonIsDown; |
|---|
| 21 | public AppleKeyboardKeys CurrentKeyState; |
|---|
| 22 | |
|---|
| 23 | private Stream _stream; |
|---|
| 24 | private Win32.HookHandle _hHook; |
|---|
| 25 | |
|---|
| 26 | private const UInt32 VIDApple = 0x5ac; |
|---|
| 27 | private const UInt32 PIDAppleWirelessKeyboardUS = 0x22c; |
|---|
| 28 | private const UInt32 PIDAppleWirelessKeyboardFR = 0x22d; |
|---|
| 29 | private const UInt32 PIDAppleWirelessKeyboardJIS = 0x22e; |
|---|
| 30 | |
|---|
| 31 | /// <summary> |
|---|
| 32 | /// |
|---|
| 33 | /// </summary> |
|---|
| 34 | internal Boolean Start() |
|---|
| 35 | { |
|---|
| 36 | if (_stream != null) |
|---|
| 37 | throw new InvalidOperationException("�w���p�[�͂��łɎ�s���ł��B"); |
|---|
| 38 | |
|---|
| 39 | Guid guid; |
|---|
| 40 | HIDImports.HidD_GetHidGuid(out guid); |
|---|
| 41 | |
|---|
| 42 | IntPtr hDevInfo = HIDImports.SetupDiGetClassDevs(ref guid, null, IntPtr.Zero, HIDImports.DIGCF_DEVICEINTERFACE); |
|---|
| 43 | HIDImports.SP_DEVICE_INTERFACE_DATA diData = new HIDImports.SP_DEVICE_INTERFACE_DATA(); |
|---|
| 44 | diData.cbSize = Marshal.SizeOf(diData); |
|---|
| 45 | |
|---|
| 46 | UInt32 index = 0; |
|---|
| 47 | while (HIDImports.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guid, index++, ref diData)) |
|---|
| 48 | { |
|---|
| 49 | HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA diDetail = new HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA(); |
|---|
| 50 | diDetail.cbSize = (IntPtr.Size == 8) ? (UInt32)8 : 5; // x64:8, x86:5 |
|---|
| 51 | |
|---|
| 52 | UInt32 size; |
|---|
| 53 | HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, IntPtr.Zero, 0, out size, IntPtr.Zero); |
|---|
| 54 | if (HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, ref diDetail, size, out size, IntPtr.Zero)) |
|---|
| 55 | { |
|---|
| 56 | Debug.WriteLine("Device: " + diDetail.DevicePath); Debug.Indent(); |
|---|
| 57 | SafeFileHandle mHandle = HIDImports.CreateFile(diDetail.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, HIDImports.EFileAttributes.Overlapped, IntPtr.Zero); |
|---|
| 58 | HIDImports.HIDD_ATTRIBUTES attrib = new HIDImports.HIDD_ATTRIBUTES(); |
|---|
| 59 | attrib.Size = Marshal.SizeOf(attrib); |
|---|
| 60 | |
|---|
| 61 | if (HIDImports.HidD_GetAttributes(mHandle.DangerousGetHandle(), ref attrib)) |
|---|
| 62 | { |
|---|
| 63 | Debug.WriteLine(String.Format("VendorID:{0:x}, ProductID:{1:x}, VersionNumber:{2:x}", attrib.VendorID, attrib.ProductID, attrib.VersionNumber)); |
|---|
| 64 | if (attrib.VendorID == VIDApple && |
|---|
| 65 | (attrib.ProductID == PIDAppleWirelessKeyboardUS || attrib.ProductID == PIDAppleWirelessKeyboardJIS || attrib.ProductID == PIDAppleWirelessKeyboardFR)) |
|---|
| 66 | { |
|---|
| 67 | _stream = new FileStream(mHandle, FileAccess.ReadWrite, 22, true); |
|---|
| 68 | //break; |
|---|
| 69 | } |
|---|
| 70 | else |
|---|
| 71 | { |
|---|
| 72 | mHandle.Close(); |
|---|
| 73 | } |
|---|
| 74 | } |
|---|
| 75 | Debug.Unindent(); |
|---|
| 76 | } |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | if (_stream != null) |
|---|
| 80 | { |
|---|
| 81 | Byte[] buffer = new Byte[22]; |
|---|
| 82 | _stream.BeginRead(buffer, 0, buffer.Length, SpecialKeyStateChanged, buffer); |
|---|
| 83 | return true; |
|---|
| 84 | } |
|---|
| 85 | else |
|---|
| 86 | { |
|---|
| 87 | // Not Connected |
|---|
| 88 | return false; |
|---|
| 89 | } |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | public Boolean Hook() |
|---|
| 93 | { |
|---|
| 94 | if (_hHook != null) |
|---|
| 95 | throw new InvalidOperationException("�t�b�N�͂��łɎ�s�������܂��B"); |
|---|
| 96 | |
|---|
| 97 | // hook |
|---|
| 98 | Win32.HookProcedure = KeyboardHookProc; |
|---|
| 99 | _hHook = Win32.SetWindowsHookEx(Win32.WH_KEYBOARD_LL, Win32.HookProcedure, Win32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0); |
|---|
| 100 | |
|---|
| 101 | return !_hHook.IsInvalid; |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | private void OnSpecialKeyDown() |
|---|
| 105 | { |
|---|
| 106 | if (SpecialKeyDown != null) |
|---|
| 107 | SpecialKeyDown(this, new KeyEventArgs(CurrentPowerButtonIsDown, CurrentKeyState)); |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | private void OnFnKeyCombinationDown(AppleKeyboardKeys appleKeyState, Keys key, Win32.KeyboardHookEventStruct keyEventStruct) |
|---|
| 111 | { |
|---|
| 112 | if (FnKeyCombinationDown != null) |
|---|
| 113 | FnKeyCombinationDown(this, new AppleKeyboardEventArgs(appleKeyState, key, keyEventStruct)); |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | private Boolean OnKeyDown(AppleKeyboardKeys appleKeyState, Keys key, Win32.KeyboardHookEventStruct keyEventStruct) |
|---|
| 117 | { |
|---|
| 118 | if (KeyDown != null) |
|---|
| 119 | { |
|---|
| 120 | AppleKeyboardEventArgs eArgs = new AppleKeyboardEventArgs(appleKeyState, key, keyEventStruct); |
|---|
| 121 | KeyDown(this, eArgs); |
|---|
| 122 | return eArgs.Handled; |
|---|
| 123 | } |
|---|
| 124 | else |
|---|
| 125 | { |
|---|
| 126 | return false; |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | private Boolean OnKeyUp(AppleKeyboardKeys appleKeyState, Keys key, Win32.KeyboardHookEventStruct keyEventStruct) |
|---|
| 131 | { |
|---|
| 132 | if (KeyUp != null) |
|---|
| 133 | { |
|---|
| 134 | AppleKeyboardEventArgs eArgs = new AppleKeyboardEventArgs(appleKeyState, key, keyEventStruct); |
|---|
| 135 | KeyUp(this, eArgs); |
|---|
| 136 | return eArgs.Handled; |
|---|
| 137 | } |
|---|
| 138 | else |
|---|
| 139 | { |
|---|
| 140 | return false; |
|---|
| 141 | } |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam) |
|---|
| 145 | { |
|---|
| 146 | Win32.KeyboardHookEventStruct keyEventStruct = (Win32.KeyboardHookEventStruct)Marshal.PtrToStructure(lParam, typeof(Win32.KeyboardHookEventStruct)); |
|---|
| 147 | //Debug.WriteLine(String.Format("{0}, {1}, {2}", nCode, wParam, lParam)); |
|---|
| 148 | Debug.WriteLine(keyEventStruct); |
|---|
| 149 | |
|---|
| 150 | switch ((Keys)keyEventStruct.wVk) |
|---|
| 151 | { |
|---|
| 152 | case Keys.LShiftKey: |
|---|
| 153 | case Keys.RShiftKey: |
|---|
| 154 | case Keys.LMenu: |
|---|
| 155 | case Keys.RMenu: |
|---|
| 156 | case Keys.LControlKey: |
|---|
| 157 | case Keys.RControlKey: |
|---|
| 158 | return Win32.CallNextHookEx(_hHook, nCode, wParam, lParam); |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | // ���������������͖������� if (keyEventStruct.dwExtraInfo != (IntPtr)0x37564) |
|---|
| 162 | { |
|---|
| 163 | Boolean handled = false; |
|---|
| 164 | switch ((Int32) wParam) |
|---|
| 165 | { |
|---|
| 166 | case Win32.WM_KEYUP: |
|---|
| 167 | handled = OnKeyUp(CurrentKeyState, Keys.None, keyEventStruct); |
|---|
| 168 | break; |
|---|
| 169 | case Win32.WM_KEYDOWN: |
|---|
| 170 | handled = OnKeyDown(CurrentKeyState, Keys.None, keyEventStruct); |
|---|
| 171 | break; |
|---|
| 172 | } |
|---|
| 173 | if (handled) |
|---|
| 174 | return (IntPtr) 1; |
|---|
| 175 | |
|---|
| 176 | if ((CurrentKeyState & AppleKeyboardKeys.Fn) == AppleKeyboardKeys.Fn) |
|---|
| 177 | { |
|---|
| 178 | if ((Int32) wParam == Win32.WM_KEYDOWN || (Int32) wParam == Win32.WM_SYSKEYDOWN) // KEYDOWN |
|---|
| 179 | OnFnKeyCombinationDown(CurrentKeyState, (Keys) keyEventStruct.wVk, keyEventStruct); |
|---|
| 180 | //else if ((Int32)wParam == Win32.WM_KEYUP || (Int32)wParam == Win32.WM_SYSKEYUP) // KEYUP |
|---|
| 181 | // OnFnKeyCombinationUp(CurrentKeyState, (Keys)keyEventStruct.wVk, keyEventStruct); |
|---|
| 182 | return (IntPtr) 1; |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | return Win32.CallNextHookEx(_hHook, nCode, wParam, lParam); |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | private void SpecialKeyStateChanged(IAsyncResult ar) |
|---|
| 189 | { |
|---|
| 190 | if (_stream == null || !ar.IsCompleted) |
|---|
| 191 | return; |
|---|
| 192 | |
|---|
| 193 | try |
|---|
| 194 | { |
|---|
| 195 | _stream.EndRead(ar); |
|---|
| 196 | } |
|---|
| 197 | catch (OperationCanceledException) { } |
|---|
| 198 | catch (IOException ioe) |
|---|
| 199 | { |
|---|
| 200 | // restart (reconnected) |
|---|
| 201 | Debug.WriteLine("Restart: " + ioe.Message); |
|---|
| 202 | if (Disconnected != null) |
|---|
| 203 | Disconnected(this, EventArgs.Empty); |
|---|
| 204 | return; |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | Byte[] buffer = ar.AsyncState as Byte[]; |
|---|
| 208 | foreach (Byte b in buffer) |
|---|
| 209 | Debug.Write(String.Format("{0:x2} ", b)); |
|---|
| 210 | |
|---|
| 211 | if (buffer[0] == 0x11) |
|---|
| 212 | { |
|---|
| 213 | Debug.Write((AppleKeyboardKeys) buffer[1]); |
|---|
| 214 | CurrentKeyState = (AppleKeyboardKeys) buffer[1]; |
|---|
| 215 | } |
|---|
| 216 | else if (buffer[0] == 0x13) |
|---|
| 217 | { |
|---|
| 218 | Debug.Write(buffer[1] == 1 ? "Power (Down)" : "Power (Up)"); |
|---|
| 219 | CurrentPowerButtonIsDown = (buffer[1] == 1); |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | OnSpecialKeyDown(); |
|---|
| 223 | |
|---|
| 224 | Debug.WriteLine(""); |
|---|
| 225 | |
|---|
| 226 | _stream.BeginRead(buffer, 0, buffer.Length, SpecialKeyStateChanged, buffer); |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | public void Unhook() |
|---|
| 230 | { |
|---|
| 231 | if (_hHook != null && !_hHook.IsInvalid) |
|---|
| 232 | { |
|---|
| 233 | _hHook.Dispose(); |
|---|
| 234 | } |
|---|
| 235 | _hHook = null; |
|---|
| 236 | } |
|---|
| 237 | |
|---|
| 238 | public void Shutdown() |
|---|
| 239 | { |
|---|
| 240 | if (_stream != null) |
|---|
| 241 | { |
|---|
| 242 | _stream.Close(); |
|---|
| 243 | _stream = null; |
|---|
| 244 | } |
|---|
| 245 | } |
|---|
| 246 | |
|---|
| 247 | #region IDisposable �����o |
|---|
| 248 | |
|---|
| 249 | public void Dispose() |
|---|
| 250 | { |
|---|
| 251 | Unhook(); |
|---|
| 252 | Shutdown(); |
|---|
| 253 | } |
|---|
| 254 | |
|---|
| 255 | #endregion |
|---|
| 256 | } |
|---|
| 257 | } |
|---|