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