1. Index: Source/OpenTK/Input/KeyboardDevice.cs
  2. ===================================================================
  3. --- Source/OpenTK/Input/KeyboardDevice.cs   (revision 3125)
  4. +++ Source/OpenTK/Input/KeyboardDevice.cs   (working copy)
  5. @@ -22,6 +22,7 @@
  6.      {
  7.          //private IKeyboard keyboard;
  8.          private bool[] keys = new bool[Enum.GetValues(typeof(Key)).Length];
  9. +        private bool[] scancodes = new bool[256];
  10.          private string description;
  11.          private int numKeys, numFKeys, numLeds;
  12.          private IntPtr devID;
  13. @@ -44,24 +45,16 @@
  14.          public bool this[Key key]
  15.          {
  16.              get { return keys[(int)key]; }
  17. -            internal set
  18. -            {
  19. -                if (keys[(int)key] != value || KeyRepeat)
  20. -                {
  21. -                    keys[(int)key] = value;
  22. +        }
  23.  
  24. -                    if (value && KeyDown != null)
  25. -                    {
  26. -                        args.Key = key;
  27. -                        KeyDown(this, args);
  28. -                    }
  29. -                    else if (!value && KeyUp != null)
  30. -                    {
  31. -                        args.Key = key;
  32. -                        KeyUp(this, args);
  33. -                    }
  34. -                }
  35. -            }
  36. +        /// <summary>
  37. +        /// Gets a value indicating the status of the specified Key.
  38. +        /// </summary>
  39. +        /// <param name="scancode">The scancode to check.</param>
  40. +        /// <returns>True if the scancode is pressed, false otherwise.</returns>
  41. +        public bool this[uint scancode]
  42. +        {
  43. +            get { return scancodes[scancode]; }
  44.          }
  45.  
  46.          /// <summary>
  47. @@ -197,12 +190,34 @@
  48.          internal void ClearKeys()
  49.          {
  50.              for (int i = 0; i < keys.Length; i++)
  51. -                if (this[(Key)i])       // Make sure KeyUp events are *not* raised for keys that are up, even if key repeat is on.
  52. -                    this[(Key)i] = false;
  53. +                keys[i] = false;
  54. +            for (uint i = 0; i < scancodes.Length; i++)
  55. +                scancodes[i] = false;
  56.          }
  57.  
  58.          #endregion
  59.  
  60. +        internal void SetKey(Key key, uint scancode, bool state)
  61. +        {
  62. +            if (keys[(int)key] != state || KeyRepeat)
  63. +            {
  64. +                keys[(int)key] = scancodes[scancode] = state;
  65. +
  66. +                if (state && KeyDown != null)
  67. +                {
  68. +                    args.Key = key;
  69. +                    args.ScanCode = scancode;
  70. +                    KeyDown(this, args);
  71. +                }
  72. +                else if (!state && KeyUp != null)
  73. +                {
  74. +                    args.Key = key;
  75. +                    args.ScanCode = scancode;
  76. +                    KeyUp(this, args);
  77. +                }
  78. +            }
  79. +        }
  80. +
  81.          #endregion
  82.      }
  83.  }
  84. \ No newline at end of file
  85. Index: Source/OpenTK/Input/KeyboardKeyEventArgs.cs
  86. ===================================================================
  87. --- Source/OpenTK/Input/KeyboardKeyEventArgs.cs (revision 3125)
  88. +++ Source/OpenTK/Input/KeyboardKeyEventArgs.cs (working copy)
  89. @@ -46,6 +46,7 @@
  90.          #region Fields
  91.  
  92.          Key key;
  93. +        uint scancode;
  94.  
  95.          #endregion
  96.  
  97. @@ -63,6 +64,7 @@
  98.          public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
  99.          {
  100.              Key = args.Key;
  101. +            ScanCode = args.ScanCode;
  102.          }
  103.  
  104.          #endregion
  105. @@ -77,6 +79,14 @@
  106.              get { return key; }
  107.              internal set { key = value; }
  108.          }
  109. +        /// <summary>
  110. +        /// Gets the scancode which generated this event.
  111. +        /// </summary>
  112. +        public uint ScanCode
  113. +        {
  114. +            get { return scancode; }
  115. +            internal set { scancode = value; }
  116. +        }
  117.  
  118.          #endregion
  119.      }
  120. Index: Source/OpenTK/Input/KeyboardState.cs
  121. ===================================================================
  122. --- Source/OpenTK/Input/KeyboardState.cs    (revision 3125)
  123. +++ Source/OpenTK/Input/KeyboardState.cs    (working copy)
  124. @@ -43,6 +43,7 @@
  125.          const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize;
  126.          // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh...
  127.          unsafe fixed int Keys[NumInts];
  128. +        unsafe fixed int Codes[256];
  129.          bool is_connected;
  130.  
  131.          #endregion
  132. @@ -58,16 +59,20 @@
  133.          public bool this[Key key]
  134.          {
  135.              get { return IsKeyDown(key); }
  136. -            internal set
  137. -            {
  138. -                if (value)
  139. -                    EnableBit((int)key);
  140. -                else
  141. -                    DisableBit((int)key);
  142. -            }
  143.          }
  144.  
  145.          /// <summary>
  146. +        /// Gets a <see cref="System.Boolean"/> indicating whether the specified
  147. +        /// <see cref="OpenTK.Input.Key"/> is pressed.
  148. +        /// </summary>
  149. +        /// <param name="key">The <see cref="OpenTK.Input.Key"/> to check.</param>
  150. +        /// <returns>True if key is pressed; false otherwise.</returns>
  151. +        public bool this[short code]
  152. +        {
  153. +            get { return IsKeyDown(code); }
  154. +        }
  155. +
  156. +        /// <summary>
  157.          /// Gets a <see cref="System.Boolean"/> indicating whether this key is down.
  158.          /// </summary>
  159.          /// <param name="key">The <see cref="OpenTK.Input.Key"/> to check.</param>
  160. @@ -77,6 +82,15 @@
  161.          }
  162.  
  163.          /// <summary>
  164. +        /// Gets a <see cref="System.Boolean"/> indicating whether this scan code is down.
  165. +        /// </summary>
  166. +        /// <param name="code">The scan code to check.</param>
  167. +        public bool IsKeyDown(short code)
  168. +        {
  169. +            return ReadBit(code,true);
  170. +        }
  171. +
  172. +        /// <summary>
  173.          /// Gets a <see cref="System.Boolean"/> indicating whether this key is up.
  174.          /// </summary>
  175.          /// <param name="key">The <see cref="OpenTK.Input.Key"/> to check.</param>
  176. @@ -86,6 +100,15 @@
  177.          }
  178.  
  179.          /// <summary>
  180. +        /// Gets a <see cref="System.Boolean"/> indicating whether this scan code is down.
  181. +        /// </summary>
  182. +        /// <param name="code">The scan code to check.</param>
  183. +        public bool IsKeyUp(short code)
  184. +        {
  185. +            return !ReadBit(code,true);
  186. +        }
  187. +
  188. +        /// <summary>
  189.          /// Gets a <see cref="System.Boolean"/> indicating whether this keyboard
  190.          /// is connected.
  191.          /// </summary>
  192. @@ -187,48 +210,62 @@
  193.  
  194.          #region Internal Members
  195.  
  196. -        internal bool ReadBit(int offset)
  197. +        internal void SetKeyState(Key key, byte code, bool down)
  198.          {
  199. -            ValidateOffset(offset);
  200. +            if (down)
  201. +            {
  202. +                EnableBit((int)key);
  203. +                EnableBit(code,true);
  204. +            }
  205. +            else
  206. +            {
  207. +                DisableBit((int)key);
  208. +                DisableBit(code, true);
  209. +            }
  210. +        }
  211.  
  212. +        internal bool ReadBit(int offset, bool ScanCode = false)
  213. +        {
  214. +            ValidateOffset(offset, ScanCode);
  215. +
  216.              int int_offset = offset / 32;
  217.              int bit_offset = offset % 32;
  218.              unsafe
  219.              {
  220. -                fixed (int* k = Keys)
  221. -                {
  222. -                    return (*(k + int_offset) & (1 << bit_offset)) != 0u;
  223. -                }
  224. +                if (ScanCode)
  225. +                    fixed (int* c = Codes) { return (*(c + int_offset) & (1 << bit_offset)) != 0u; }
  226. +                else
  227. +                    fixed (int* k = Keys) { return (*(k + int_offset) & (1 << bit_offset)) != 0u; }
  228.              }
  229.          }
  230.  
  231. -        internal void EnableBit(int offset)
  232. +        internal void EnableBit(int offset, bool ScanCode = false)
  233.          {
  234. -            ValidateOffset(offset);
  235. +            ValidateOffset(offset, ScanCode);
  236.  
  237.              int int_offset = offset / 32;
  238.              int bit_offset = offset % 32;
  239.              unsafe
  240.              {
  241. -                fixed (int* k = Keys)
  242. -                {
  243. -                    *(k + int_offset) |= 1 << bit_offset;
  244. -                }
  245. +                if (ScanCode)
  246. +                    fixed (int* c = Codes) { *(c + int_offset) |= 1 << bit_offset; }
  247. +                else
  248. +                    fixed (int* k = Keys) { *(k + int_offset) |= 1 << bit_offset; }
  249.              }
  250.          }
  251.  
  252. -        internal void DisableBit(int offset)
  253. +        internal void DisableBit(int offset, bool ScanCode = false)
  254.          {
  255. -            ValidateOffset(offset);
  256. +            ValidateOffset(offset, ScanCode);
  257.  
  258.              int int_offset = offset / 32;
  259.              int bit_offset = offset % 32;
  260.              unsafe
  261.              {
  262. -                fixed (int* k = Keys)
  263. -                {
  264. -                    *(k + int_offset) &= ~(1 << bit_offset);
  265. -                }
  266. +                if (ScanCode)
  267. +                    fixed (int* c = Codes) { *(c + int_offset) &= ~(1 << bit_offset); }
  268. +                else
  269. +                    fixed (int* k = Keys) { *(k + int_offset) &= ~(1 << bit_offset); }
  270.              }
  271.          }
  272.  
  273. @@ -242,6 +279,12 @@
  274.                      for (int i = 0; i < NumInts; i++)
  275.                          *(k1 + i) |= *(k2 + i);
  276.                  }
  277. +                int* c2 = other.Codes;
  278. +                fixed (int* c1 = Codes)
  279. +                {
  280. +                    for (int i = 0; i < short.MaxValue; i++)
  281. +                        *(c1 + i) |= *(c2 + i);
  282. +                }
  283.              }
  284.              IsConnected |= other.IsConnected;
  285.          }
  286. @@ -250,9 +293,9 @@
  287.  
  288.          #region Private Members
  289.  
  290. -        static void ValidateOffset(int offset)
  291. +        static void ValidateOffset(int offset, bool ScanCode)
  292.          {
  293. -            if (offset < 0 || offset >= NumInts * IntSize)
  294. +            if (offset < 0 || offset >= (ScanCode ? 256 : NumInts * IntSize))
  295.                  throw new ArgumentOutOfRangeException("offset");
  296.          }
  297.  
  298. Index: Source/OpenTK/Platform/MacOS/CarbonGLNative.cs
  299. ===================================================================
  300. --- Source/OpenTK/Platform/MacOS/CarbonGLNative.cs  (revision 3125)
  301. +++ Source/OpenTK/Platform/MacOS/CarbonGLNative.cs  (working copy)
  302. @@ -368,6 +368,7 @@
  303.                      break;
  304.              }
  305.  
  306. +            OpenTK.Input.Key key;
  307.              switch (evt.KeyboardEventKind)
  308.              {
  309.                  case KeyboardEventKind.RawKeyRepeat:
  310. @@ -376,25 +377,15 @@
  311.                      break;
  312.  
  313.                  case KeyboardEventKind.RawKeyDown:
  314. -                {
  315. -                    OpenTK.Input.Key key;
  316. -                    if (Keymap.TryGetValue(code, out key))
  317. -                    {
  318. -                        InputDriver.Keyboard[0][key] = true;
  319. -                        OnKeyPress(mKeyPressArgs);
  320. -                    }
  321. +                    Keymap.TryGetValue(code, out key);
  322. +                    InputDriver.Keyboard[0].SetKey(key, (uint)code, true);
  323. +                    OnKeyPress(mKeyPressArgs);
  324.                      return OSStatus.NoError;
  325. -                }
  326.  
  327.                  case KeyboardEventKind.RawKeyUp:
  328. -                {
  329. -                    OpenTK.Input.Key key;
  330. -                    if (Keymap.TryGetValue(code, out key))
  331. -                    {
  332. -                        InputDriver.Keyboard[0][key] = false;
  333. -                    }
  334. +                    Keymap.TryGetValue(code, out key);
  335. +                    InputDriver.Keyboard[0].SetKey(key, (uint)code, false);
  336.                      return OSStatus.NoError;
  337. -                }
  338.  
  339.                  case KeyboardEventKind.RawKeyModifiersChanged:
  340.                      ProcessModifierKey(inEvent);
  341. @@ -614,21 +605,21 @@
  342.              Debug.Print("Modifiers Changed: {0}", modifiers);
  343.              
  344.              Input.KeyboardDevice keyboard = InputDriver.Keyboard[0];
  345. -            
  346. +
  347.              if (keyboard[OpenTK.Input.Key.AltLeft] ^ option)
  348. -                keyboard[OpenTK.Input.Key.AltLeft] = option;
  349. +                keyboard.SetKey(OpenTK.Input.Key.AltLeft, (uint)MacOSKeyModifiers.Option, option);
  350.              
  351.              if (keyboard[OpenTK.Input.Key.ShiftLeft] ^ shift)
  352. -                keyboard[OpenTK.Input.Key.ShiftLeft] = shift;
  353. +                keyboard.SetKey(OpenTK.Input.Key.ShiftLeft, (uint)MacOSKeyModifiers.Shift, shift);
  354.              
  355.              if (keyboard[OpenTK.Input.Key.WinLeft] ^ command)
  356. -                keyboard[OpenTK.Input.Key.WinLeft] = command;
  357. +                keyboard.SetKey(OpenTK.Input.Key.WinLeft, (uint)MacOSKeyModifiers.Command, command);
  358.              
  359.              if (keyboard[OpenTK.Input.Key.ControlLeft] ^ control)
  360. -                keyboard[OpenTK.Input.Key.ControlLeft] = control;
  361. +                keyboard.SetKey(OpenTK.Input.Key.ControlLeft, (uint)MacOSKeyModifiers.Control, control);
  362.              
  363.              if (keyboard[OpenTK.Input.Key.CapsLock] ^ caps)
  364. -                keyboard[OpenTK.Input.Key.CapsLock] = caps;
  365. +                keyboard.SetKey(OpenTK.Input.Key.CapsLock, (uint)MacOSKeyModifiers.CapsLock, caps);
  366.              
  367.          }
  368.  
  369. Index: Source/OpenTK/Platform/MacOS/HIDInput.cs
  370. ===================================================================
  371. --- Source/OpenTK/Platform/MacOS/HIDInput.cs    (revision 3125)
  372. +++ Source/OpenTK/Platform/MacOS/HIDInput.cs    (working copy)
  373. @@ -1,937 +1,932 @@
  374. -#region License
  375. -//
  376. -// The Open Toolkit Library License
  377. -//
  378. -// Copyright (c) 2006 - 2010 the Open Toolkit library.
  379. -//
  380. -// Permission is hereby granted, free of charge, to any person obtaining a copy
  381. -// of this software and associated documentation files (the "Software"), to deal
  382. -// in the Software without restriction, including without limitation the rights to
  383. -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  384. -// the Software, and to permit persons to whom the Software is furnished to do
  385. -// so, subject to the following conditions:
  386. -//
  387. -// The above copyright notice and this permission notice shall be included in all
  388. -// copies or substantial portions of the Software.
  389. -//
  390. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  391. -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  392. -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  393. -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  394. -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  395. -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  396. -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  397. -// OTHER DEALINGS IN THE SOFTWARE.
  398. -//
  399. -#endregion
  400. -
  401. -using System;
  402. -using System.Collections.Generic;
  403. -using System.Diagnostics;
  404. -using System.Runtime.InteropServices;
  405. -using OpenTK.Input;
  406. -
  407. -namespace OpenTK.Platform.MacOS
  408. -{
  409. -    using Carbon;
  410. -    using CFAllocatorRef = System.IntPtr;
  411. -    using CFDictionaryRef = System.IntPtr;
  412. -    using CFIndex = System.IntPtr;
  413. -    using CFRunLoop = System.IntPtr;
  414. -    using CFString = System.IntPtr;
  415. -    using CFStringRef = System.IntPtr; // Here used interchangeably with the CFString
  416. -    using CFTypeRef = System.IntPtr;
  417. -    using IOHIDDeviceRef = System.IntPtr;
  418. -    using IOHIDElementRef = System.IntPtr;
  419. -    using IOHIDManagerRef = System.IntPtr;
  420. -    using IOHIDValueRef = System.IntPtr;
  421. -    using IOOptionBits = System.IntPtr;
  422. -    using IOReturn = System.IntPtr;
  423. -
  424. -    // Requires Mac OS X 10.5 or higher.
  425. -    // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that?
  426. -    class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2
  427. -    {
  428. -        #region Fields
  429. -
  430. -        readonly IOHIDManagerRef hidmanager;
  431. -
  432. -        readonly Dictionary<IntPtr, MouseState> MouseDevices =
  433. -            new Dictionary<IntPtr, MouseState>(new IntPtrEqualityComparer());
  434. -        readonly Dictionary<int, IntPtr> MouseIndexToDevice =
  435. -            new Dictionary<int, IntPtr>();
  436. -        readonly Dictionary<IntPtr, KeyboardState> KeyboardDevices =
  437. -            new Dictionary<IntPtr, KeyboardState>(new IntPtrEqualityComparer());
  438. -        readonly Dictionary<int, IntPtr> KeyboardIndexToDevice =
  439. -            new Dictionary<int, IntPtr>();
  440. -
  441. -        readonly CFRunLoop RunLoop = CF.CFRunLoopGetMain();
  442. -        readonly CFString InputLoopMode = CF.RunLoopModeDefault;
  443. -        readonly CFDictionary DeviceTypes = new CFDictionary();
  444. -
  445. -        readonly NativeMethods.IOHIDDeviceCallback HandleDeviceAdded;
  446. -        readonly NativeMethods.IOHIDDeviceCallback HandleDeviceRemoved;
  447. -        readonly NativeMethods.IOHIDValueCallback HandleDeviceValueReceived;
  448. -
  449. -        #endregion
  450. -
  451. -        #region Constructors
  452. -
  453. -        public HIDInput()
  454. -        {
  455. -            Debug.Print("Using HIDInput.");
  456. -
  457. -            HandleDeviceAdded = DeviceAdded;
  458. -            HandleDeviceRemoved = DeviceRemoved;
  459. -            HandleDeviceValueReceived = DeviceValueReceived;
  460. -
  461. -            hidmanager = CreateHIDManager();
  462. -            RegisterHIDCallbacks(hidmanager);
  463. -        }
  464. -
  465. -        #endregion
  466. -
  467. -         #region Private Members
  468. -
  469. -        IOHIDManagerRef CreateHIDManager()
  470. -        {
  471. -            return NativeMethods.IOHIDManagerCreate(IntPtr.Zero, IntPtr.Zero);
  472. -        }
  473. -
  474. -        // Registers callbacks for device addition and removal. These callbacks
  475. -        // are called when we run the loop in CheckDevicesMode
  476. -        void RegisterHIDCallbacks(IOHIDManagerRef hidmanager)
  477. -        {
  478. -            NativeMethods.IOHIDManagerRegisterDeviceMatchingCallback(
  479. -                hidmanager, HandleDeviceAdded, IntPtr.Zero);
  480. -            NativeMethods.IOHIDManagerRegisterDeviceRemovalCallback(
  481. -                hidmanager, HandleDeviceRemoved, IntPtr.Zero);
  482. -            NativeMethods.IOHIDManagerScheduleWithRunLoop(hidmanager,
  483. -                RunLoop, InputLoopMode);
  484. -
  485. -            NativeMethods.IOHIDManagerSetDeviceMatching(hidmanager, DeviceTypes.Ref);
  486. -            NativeMethods.IOHIDManagerOpen(hidmanager, IOOptionBits.Zero);
  487. -
  488. -            OpenTK.Platform.MacOS.Carbon.CF.CFRunLoopRunInMode(InputLoopMode, 0.0, true);
  489. -        }
  490. -
  491. -        void DeviceAdded(IntPtr context, IOReturn res, IntPtr sender, IOHIDDeviceRef device)
  492. -        {
  493. -            if (NativeMethods.IOHIDDeviceOpen(device, IOOptionBits.Zero) == IOReturn.Zero)
  494. -            {
  495. -                if (NativeMethods.IOHIDDeviceConformsTo(device,
  496. -                        HIDPage.GenericDesktop, (int)HIDUsageGD.Mouse))
  497. -                {
  498. -                    if (!MouseDevices.ContainsKey(device))
  499. -                    {
  500. -                        Debug.Print("Mouse device {0} discovered", device);
  501. -                        MouseState state = new MouseState();
  502. -                        state.IsConnected = true;
  503. -                        MouseIndexToDevice.Add(MouseDevices.Count, device);
  504. -                        MouseDevices.Add(device, state);
  505. -                    }
  506. -                    else
  507. -                    {
  508. -                        Debug.Print("Mouse device {0} reconnected", device);
  509. -                        MouseState state = MouseDevices[device];
  510. -                        state.IsConnected = true;
  511. -                        MouseDevices[device] = state;
  512. -                    }
  513. -                }
  514. -
  515. -                if (NativeMethods.IOHIDDeviceConformsTo(device,
  516. -                        HIDPage.GenericDesktop, (int)HIDUsageGD.Keyboard))
  517. -                {
  518. -                    if (!KeyboardDevices.ContainsKey(device))
  519. -                    {
  520. -                        Debug.Print("Keyboard device {0} discovered", device);
  521. -                        KeyboardState state = new KeyboardState();
  522. -                        state.IsConnected = true;
  523. -                        KeyboardIndexToDevice.Add(KeyboardDevices.Count, device);
  524. -                        KeyboardDevices.Add(device, state);
  525. -                    }
  526. -                    else
  527. -                    {
  528. -                        Debug.Print("Keyboard device {0} reconnected", device);
  529. -                        KeyboardState state = KeyboardDevices[device];
  530. -                        state.IsConnected = true;
  531. -                        KeyboardDevices[device] = state;
  532. -                    }
  533. -                }
  534. -
  535. -                NativeMethods.IOHIDDeviceRegisterInputValueCallback(device,
  536. -                    HandleDeviceValueReceived, IntPtr.Zero);
  537. -                NativeMethods.IOHIDDeviceScheduleWithRunLoop(device, RunLoop, InputLoopMode);
  538. -            }
  539. -        }
  540. -
  541. -        void DeviceRemoved(IntPtr context, IOReturn res, IntPtr sender, IOHIDDeviceRef device)
  542. -        {
  543. -            if (NativeMethods.IOHIDDeviceConformsTo(device, HIDPage.GenericDesktop, (int)HIDUsageGD.Mouse) &&
  544. -                MouseDevices.ContainsKey(device))
  545. -            {
  546. -                Debug.Print("Mouse device {0} disconnected", device);
  547. -
  548. -                // Keep the device in case it comes back later on
  549. -                MouseState state = MouseDevices[device];
  550. -                state.IsConnected = false;
  551. -                MouseDevices[device] = state;
  552. -            }
  553. -
  554. -            if (NativeMethods.IOHIDDeviceConformsTo(device, HIDPage.GenericDesktop, (int)HIDUsageGD.Keyboard) &&
  555. -                KeyboardDevices.ContainsKey(device))
  556. -            {
  557. -                Debug.Print("Keyboard device {0} disconnected", device);
  558. -
  559. -                // Keep the device in case it comes back later on
  560. -                KeyboardState state = KeyboardDevices[device];
  561. -                state.IsConnected = false;
  562. -                KeyboardDevices[device] = state;
  563. -            }
  564. -
  565. -            NativeMethods.IOHIDDeviceRegisterInputValueCallback(device, null, IntPtr.Zero);
  566. -            NativeMethods.IOHIDDeviceUnscheduleWithRunLoop(device, RunLoop, InputLoopMode);
  567. -        }
  568. -
  569. -        void DeviceValueReceived(IntPtr context, IOReturn res, IntPtr sender, IOHIDValueRef val)
  570. -        {
  571. -            MouseState mouse;
  572. -            KeyboardState keyboard;
  573. -            if (MouseDevices.TryGetValue(sender, out mouse))
  574. -            {
  575. -                MouseDevices[sender] = UpdateMouse(mouse, val);
  576. -            }
  577. -            else if (KeyboardDevices.TryGetValue(sender, out keyboard))
  578. -            {
  579. -                KeyboardDevices[sender] = UpdateKeyboard(keyboard, val);
  580. -            }
  581. -        }
  582. -
  583. -        static MouseState UpdateMouse(MouseState state, IOHIDValueRef val)
  584. -        {
  585. -            IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val);
  586. -            int v_int = NativeMethods.IOHIDValueGetIntegerValue(val).ToInt32();
  587. -            //double v_physical = NativeMethods.IOHIDValueGetScaledValue(val, IOHIDValueScaleType.Physical);
  588. -            //double v_calbrated = NativeMethods.IOHIDValueGetScaledValue(val, IOHIDValueScaleType.Calibrated);
  589. -            HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem);
  590. -            int usage = NativeMethods.IOHIDElementGetUsage(elem);
  591. -
  592. -            switch (page)
  593. -            {
  594. -                case HIDPage.GenericDesktop:
  595. -                    switch ((HIDUsageGD)usage)
  596. -                    {
  597. -                        case HIDUsageGD.X:
  598. -                            state.X += v_int;
  599. -                            break;
  600. -
  601. -                        case HIDUsageGD.Y:
  602. -                            state.Y += v_int;
  603. -                            break;
  604. -
  605. -                        case HIDUsageGD.Wheel:
  606. -                            state.WheelPrecise += v_int;
  607. -                            break;
  608. -                    }
  609. -                    break;
  610. -
  611. -                case HIDPage.Button:
  612. -                    state[OpenTK.Input.MouseButton.Left + usage - 1] = v_int == 1;
  613. -                    break;
  614. -            }
  615. -
  616. -            return state;
  617. -        }
  618. -
  619. -        static KeyboardState UpdateKeyboard(KeyboardState state, IOHIDValueRef val)
  620. -        {
  621. -            IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val);
  622. -            int v_int = NativeMethods.IOHIDValueGetIntegerValue(val).ToInt32();
  623. -            HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem);
  624. -            int usage = NativeMethods.IOHIDElementGetUsage(elem);
  625. -
  626. -             switch (page)
  627. -            {
  628. -                case HIDPage.GenericDesktop:
  629. -                case HIDPage.KeyboardOrKeypad:
  630. -                    int raw = (int)usage;
  631. -                    if (raw >= RawKeyMap.Length || raw < 0)
  632. -                    {
  633. -                        Debug.Print("[Warning] Key {0} not mapped.", raw);
  634. -                        return state;
  635. -                    }
  636. -                    Key key = RawKeyMap[raw];
  637. -                    state[key] = v_int != 0;
  638. -                    break;
  639. -            }
  640. -
  641. -            return state;
  642. -        }
  643. -
  644. -        #endregion
  645. -
  646. -        #region IInputDriver2 Members
  647. -
  648. -        public IMouseDriver2 MouseDriver { get { return this; } }
  649. -        public IKeyboardDriver2 KeyboardDriver { get { return this; } }
  650. -        public IGamePadDriver GamePadDriver { get { throw new NotImplementedException(); } }
  651. -
  652. -        #endregion
  653. -
  654. -        #region IMouseDriver2 Members
  655. -
  656. -        MouseState IMouseDriver2.GetState()
  657. -        {
  658. -            MouseState master = new MouseState();
  659. -            foreach (KeyValuePair<IntPtr, MouseState> item in MouseDevices)
  660. -            {
  661. -                master.MergeBits(item.Value);
  662. -            }
  663. -
  664. -            return master;
  665. -        }
  666. -
  667. -        MouseState IMouseDriver2.GetState(int index)
  668. -        {
  669. -            IntPtr device;
  670. -            if (MouseIndexToDevice.TryGetValue(index, out device))
  671. -            {
  672. -                return MouseDevices[device];
  673. -            }
  674. -
  675. -            return new MouseState();
  676. -        }
  677. -
  678. -        void IMouseDriver2.SetPosition(double x, double y)
  679. -        {
  680. -            CG.SetLocalEventsSuppressionInterval(0.0);
  681. -            CG.WarpMouseCursorPosition(new Carbon.HIPoint(x, y));
  682. -        }
  683. -
  684. -        #endregion
  685. -
  686. -        #region IKeyboardDriver2
  687. -
  688. -        KeyboardState IKeyboardDriver2.GetState()
  689. -        {
  690. -            KeyboardState master = new KeyboardState();
  691. -            foreach (KeyValuePair<IntPtr, KeyboardState> item in KeyboardDevices)
  692. -            {
  693. -                master.MergeBits(item.Value);
  694. -            }
  695. -
  696. -            return master;
  697. -        }
  698. -
  699. -        KeyboardState IKeyboardDriver2.GetState(int index)
  700. -        {
  701. -            IntPtr device;
  702. -            if (KeyboardIndexToDevice.TryGetValue(index, out device))
  703. -            {
  704. -                return KeyboardDevices[device];
  705. -            }
  706. -
  707. -            return new KeyboardState();
  708. -        }
  709. -
  710. -        string IKeyboardDriver2.GetDeviceName(int index)
  711. -        {
  712. -            IntPtr device;
  713. -            if (KeyboardIndexToDevice.TryGetValue(index, out device))
  714. -            {
  715. -                IntPtr vendor_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDVendorIDKey);
  716. -                IntPtr product_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductIDKey);
  717. -                // Todo: find out the real vendor/product name from the relevant ids.
  718. -                return String.Format("{0}:{1}", vendor_id, product_id);
  719. -            }
  720. -            return String.Empty;
  721. -        }
  722. -
  723. -        #endregion
  724. -
  725. -        #region NativeMethods
  726. -
  727. -        class NativeMethods
  728. -        {
  729. -            const string hid = "/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit";
  730. -
  731. -            public static readonly CFString IOHIDVendorIDKey = CF.CFSTR("VendorID");
  732. -            public static readonly CFString IOHIDVendorIDSourceKey = CF.CFSTR("VendorIDSource");
  733. -            public static readonly CFString IOHIDProductIDKey = CF.CFSTR("ProductID");
  734. -            public static readonly CFString IOHIDVersionNumberKey = CF.CFSTR("VersionNumber");
  735. -            public static readonly CFString IOHIDManufacturerKey = CF.CFSTR("Manufacturer");
  736. -            public static readonly CFString IOHIDProductKey = CF.CFSTR("Product");
  737. -            public static readonly CFString IOHIDDeviceUsageKey = CF.CFSTR("DeviceUsage");
  738. -            public static readonly CFString IOHIDDeviceUsagePageKey = CF.CFSTR("DeviceUsagePage");
  739. -            public static readonly CFString IOHIDDeviceUsagePairsKey = CF.CFSTR("DeviceUsagePairs");
  740. -
  741. -            [DllImport(hid)]
  742. -            public static extern IOHIDManagerRef IOHIDManagerCreate(
  743. -                CFAllocatorRef allocator, IOOptionBits options) ;
  744. -
  745. -            // This routine will be called when a new (matching) device is connected.
  746. -            [DllImport(hid)]
  747. -            public static extern void IOHIDManagerRegisterDeviceMatchingCallback(
  748. -                IOHIDManagerRef inIOHIDManagerRef,
  749. -                IOHIDDeviceCallback inIOHIDDeviceCallback,
  750. -                IntPtr inContext);
  751. -
  752. -            // This routine will be called when a (matching) device is disconnected.
  753. -            [DllImport(hid)]
  754. -            public static extern void IOHIDManagerRegisterDeviceRemovalCallback(
  755. -                IOHIDManagerRef inIOHIDManagerRef,
  756. -                IOHIDDeviceCallback inIOHIDDeviceCallback,
  757. -                IntPtr inContext);
  758. -
  759. -            [DllImport(hid)]
  760. -            public static extern void IOHIDManagerScheduleWithRunLoop(
  761. -                IOHIDManagerRef inIOHIDManagerRef,
  762. -                CFRunLoop inCFRunLoop,
  763. -                CFString inCFRunLoopMode);
  764. -
  765. -            [DllImport(hid)]
  766. -            public static extern void IOHIDManagerSetDeviceMatching(
  767. -                IOHIDManagerRef manager,
  768. -                CFDictionaryRef matching) ;
  769. -
  770. -            [DllImport(hid)]
  771. -            public static extern IOReturn IOHIDManagerOpen(
  772. -                IOHIDManagerRef manager,
  773. -                IOOptionBits options) ;
  774. -
  775. -            [DllImport(hid)]
  776. -            public static extern IOReturn IOHIDDeviceOpen(
  777. -                IOHIDDeviceRef manager,
  778. -                IOOptionBits opts);
  779. -
  780. -            [DllImport(hid)]
  781. -            public static extern CFTypeRef IOHIDDeviceGetProperty(
  782. -                IOHIDDeviceRef device,
  783. -                CFStringRef key);
  784. -
  785. -            [DllImport(hid)]
  786. -            public static extern bool IOHIDDeviceConformsTo(
  787. -                IOHIDDeviceRef inIOHIDDeviceRef,  // IOHIDDeviceRef for the HID device
  788. -                HIDPage inUsagePage,      // the usage page to test conformance with
  789. -                int inUsage);         // the usage to test conformance with
  790. -
  791. -            [DllImport(hid)]
  792. -            public static extern void IOHIDDeviceRegisterInputValueCallback(
  793. -                IOHIDDeviceRef device,
  794. -                IOHIDValueCallback callback,
  795. -                IntPtr context);
  796. -
  797. -            [DllImport(hid)]
  798. -            public static extern void IOHIDDeviceScheduleWithRunLoop(
  799. -                IOHIDDeviceRef device,
  800. -                CFRunLoop inCFRunLoop,
  801. -                CFString inCFRunLoopMode);
  802. -
  803. -            [DllImport(hid)]
  804. -            public static extern void IOHIDDeviceUnscheduleWithRunLoop(
  805. -                IOHIDDeviceRef device,
  806. -                CFRunLoop inCFRunLoop,
  807. -                CFString inCFRunLoopMode);
  808. -
  809. -            [DllImport(hid)]
  810. -            public static extern IOHIDElementRef IOHIDValueGetElement(IOHIDValueRef @value);
  811. -
  812. -            [DllImport(hid)]
  813. -            public static extern CFIndex IOHIDValueGetIntegerValue(IOHIDValueRef @value);
  814. -
  815. -            [DllImport(hid)]
  816. -            public static extern double IOHIDValueGetScaledValue(
  817. -                IOHIDValueRef @value,
  818. -                IOHIDValueScaleType type) ;
  819. -
  820. -            [DllImport(hid)]
  821. -            public static extern int IOHIDElementGetUsage(IOHIDElementRef elem);
  822. -
  823. -            [DllImport(hid)]
  824. -            public static extern HIDPage IOHIDElementGetUsagePage(IOHIDElementRef elem);
  825. -
  826. -            public delegate void IOHIDDeviceCallback(IntPtr ctx, IOReturn res, IntPtr sender, IOHIDDeviceRef device);
  827. -            public delegate void IOHIDValueCallback(IntPtr ctx, IOReturn res, IntPtr sender, IOHIDValueRef val);
  828. -        }
  829. -
  830. -        enum IOHIDValueScaleType
  831. -        {
  832. -            Physical, // [device min, device max]
  833. -            Calibrated // [-1, +1]
  834. -        }
  835. -
  836. -        enum HIDPage
  837. -        {
  838. -            Undefined  = 0x00,
  839. -            GenericDesktop = 0x01,
  840. -            Simulation = 0x02,
  841. -            VR = 0x03,
  842. -            Sport  = 0x04,
  843. -            Game   = 0x05,
  844. -            /* Reserved 0x06 */
  845. -            KeyboardOrKeypad   = 0x07, /* USB Device Class Definition for Human Interface Devices (HID). Note: the usage type for all key codes is Selector (Sel). */
  846. -            LEDs   = 0x08,
  847. -            Button = 0x09,
  848. -            Ordinal    = 0x0A,
  849. -            Telephony  = 0x0B,
  850. -            Consumer   = 0x0C,
  851. -            Digitizer  = 0x0D,
  852. -            /* Reserved 0x0E */
  853. -            PID    = 0x0F, /* USB Physical Interface Device definitions for force feedback and related devices. */
  854. -            Unicode    = 0x10,
  855. -            /* Reserved 0x11 - 0x13 */
  856. -            AlphanumericDisplay    = 0x14,
  857. -            /* Reserved 0x15 - 0x7F */
  858. -            /* Monitor 0x80 - 0x83   USB Device Class Definition for Monitor Devices */
  859. -            /* Power 0x84 - 0x87     USB Device Class Definition for Power Devices */
  860. -            PowerDevice = 0x84,                /* Power Device Page */
  861. -            BatterySystem = 0x85,              /* Battery System Page */
  862. -            /* Reserved 0x88 - 0x8B */
  863. -            BarCodeScanner = 0x8C, /* (Point of Sale) USB Device Class Definition for Bar Code Scanner Devices */
  864. -            WeighingDevice = 0x8D, /* (Point of Sale) USB Device Class Definition for Weighing Devices */
  865. -            Scale  = 0x8D, /* (Point of Sale) USB Device Class Definition for Scale Devices */
  866. -            MagneticStripeReader = 0x8E,
  867. -            /* ReservedPointofSalepages 0x8F */
  868. -            CameraControl  = 0x90, /* USB Device Class Definition for Image Class Devices */
  869. -            Arcade = 0x91, /* OAAF Definitions for arcade and coinop related Devices */
  870. -            /* Reserved 0x92 - 0xFEFF */
  871. -            /* VendorDefined 0xFF00 - 0xFFFF */
  872. -            VendorDefinedStart = 0xFF00
  873. -        }
  874. -
  875. -        // Generic desktop usage
  876. -        enum HIDUsageGD
  877. -        {
  878. -            Pointer    = 0x01, /* Physical Collection */
  879. -            Mouse  = 0x02, /* Application Collection */
  880. -            /* 0x03 Reserved */
  881. -            Joystick   = 0x04, /* Application Collection */
  882. -            GamePad    = 0x05, /* Application Collection */
  883. -            Keyboard   = 0x06, /* Application Collection */
  884. -            Keypad = 0x07, /* Application Collection */
  885. -            MultiAxisController    = 0x08, /* Application Collection */
  886. -            /* 0x09 - 0x2F Reserved */
  887. -            X  = 0x30, /* Dynamic Value */
  888. -            Y  = 0x31, /* Dynamic Value */
  889. -            Z  = 0x32, /* Dynamic Value */
  890. -            Rx = 0x33, /* Dynamic Value */
  891. -            Ry = 0x34, /* Dynamic Value */
  892. -            Rz = 0x35, /* Dynamic Value */
  893. -            Slider = 0x36, /* Dynamic Value */
  894. -            Dial   = 0x37, /* Dynamic Value */
  895. -            Wheel  = 0x38, /* Dynamic Value */
  896. -            Hatswitch  = 0x39, /* Dynamic Value */
  897. -            CountedBuffer  = 0x3A, /* Logical Collection */
  898. -            ByteCount  = 0x3B, /* Dynamic Value */
  899. -            MotionWakeup   = 0x3C, /* One-Shot Control */
  900. -            Start  = 0x3D, /* On/Off Control */
  901. -            Select = 0x3E, /* On/Off Control */
  902. -            /* 0x3F Reserved */
  903. -            Vx = 0x40, /* Dynamic Value */
  904. -            Vy = 0x41, /* Dynamic Value */
  905. -            Vz = 0x42, /* Dynamic Value */
  906. -            Vbrx   = 0x43, /* Dynamic Value */
  907. -            Vbry   = 0x44, /* Dynamic Value */
  908. -            Vbrz   = 0x45, /* Dynamic Value */
  909. -            Vno    = 0x46, /* Dynamic Value */
  910. -            /* 0x47 - 0x7F Reserved */
  911. -            SystemControl  = 0x80, /* Application Collection */
  912. -            SystemPowerDown    = 0x81, /* One-Shot Control */
  913. -            SystemSleep    = 0x82, /* One-Shot Control */
  914. -            SystemWakeUp   = 0x83, /* One-Shot Control */
  915. -            SystemContextMenu  = 0x84, /* One-Shot Control */
  916. -            SystemMainMenu = 0x85, /* One-Shot Control */
  917. -            SystemAppMenu  = 0x86, /* One-Shot Control */
  918. -            SystemMenuHelp = 0x87, /* One-Shot Control */
  919. -            SystemMenuExit = 0x88, /* One-Shot Control */
  920. -            SystemMenu = 0x89, /* Selector */
  921. -            SystemMenuRight    = 0x8A, /* Re-Trigger Control */
  922. -            SystemMenuLeft = 0x8B, /* Re-Trigger Control */
  923. -            SystemMenuUp   = 0x8C, /* Re-Trigger Control */
  924. -            SystemMenuDown = 0x8D, /* Re-Trigger Control */
  925. -            /* 0x8E - 0x8F Reserved */
  926. -            DPadUp = 0x90, /* On/Off Control */
  927. -            DPadDown   = 0x91, /* On/Off Control */
  928. -            DPadRight  = 0x92, /* On/Off Control */
  929. -            DPadLeft   = 0x93, /* On/Off Control */
  930. -            /* 0x94 - 0xFFFF Reserved */
  931. -            Reserved = 0xFFFF
  932. -        }
  933. -
  934. -        enum HIDButton
  935. -        {
  936. -            Button_1  = 0x01, /* (primary/trigger) */
  937. -            Button_2  = 0x02, /* (secondary) */
  938. -            Button_3  = 0x03, /* (tertiary) */
  939. -            Button_4  = 0x04, /* 4th button */
  940. -            /* ... */
  941. -            Button_65535  = 0xFFFF
  942. -        }
  943. -
  944. -        enum HIDKey
  945. -        {
  946. -            ErrorRollOver = 0x01, /* ErrorRollOver */
  947. -            POSTFail  = 0x02, /* POSTFail */
  948. -            ErrorUndefined    = 0x03, /* ErrorUndefined */
  949. -            A = 0x04, /* a or A */
  950. -            B = 0x05, /* b or B */
  951. -            C = 0x06, /* c or C */
  952. -            D = 0x07, /* d or D */
  953. -            E = 0x08, /* e or E */
  954. -            F = 0x09, /* f or F */
  955. -            G = 0x0A, /* g or G */
  956. -            H = 0x0B, /* h or H */
  957. -            I = 0x0C, /* i or I */
  958. -            J = 0x0D, /* j or J */
  959. -            K = 0x0E, /* k or K */
  960. -            L = 0x0F, /* l or L */
  961. -            M = 0x10, /* m or M */
  962. -            N = 0x11, /* n or N */
  963. -            O = 0x12, /* o or O */
  964. -            P = 0x13, /* p or P */
  965. -            Q = 0x14, /* q or Q */
  966. -            R = 0x15, /* r or R */
  967. -            S = 0x16, /* s or S */
  968. -            T = 0x17, /* t or T */
  969. -            U = 0x18, /* u or U */
  970. -            V = 0x19, /* v or V */
  971. -            W = 0x1A, /* w or W */
  972. -            X = 0x1B, /* x or X */
  973. -            Y = 0x1C, /* y or Y */
  974. -            Z = 0x1D, /* z or Z */
  975. -            Number1 = 0x1E, /* 1 or ! */
  976. -            Number2 = 0x1F, /* 2 or @ */
  977. -            Number3 = 0x20, /* 3 or # */
  978. -            Number4 = 0x21, /* 4 or $ */
  979. -            Number5 = 0x22, /* 5 or % */
  980. -            Number6 = 0x23, /* 6 or ^ */
  981. -            Number7 = 0x24, /* 7 or & */
  982. -            Number8 = 0x25, /* 8 or * */
  983. -            Number9 = 0x26, /* 9 or ( */
  984. -            Number0 = 0x27, /* 0 or ) */
  985. -            ReturnOrEnter = 0x28, /* Return (Enter) */
  986. -            Escape    = 0x29, /* Escape */
  987. -            DeleteOrBackspace = 0x2A, /* Delete (Backspace) */
  988. -            Tab   = 0x2B, /* Tab */
  989. -            Spacebar  = 0x2C, /* Spacebar */
  990. -            Hyphen    = 0x2D, /* - or _ */
  991. -            EqualSign = 0x2E, /* = or + */
  992. -            OpenBracket   = 0x2F, /* [ or { */
  993. -            CloseBracket  = 0x30, /* ] or } */
  994. -            Backslash = 0x31, /* \ or | */
  995. -            NonUSPound    = 0x32, /* Non-US # or _ */
  996. -            Semicolon = 0x33, /* ; or : */
  997. -            Quote = 0x34, /* ' or " */
  998. -            GraveAccentAndTilde   = 0x35, /* Grave Accent and Tilde */
  999. -            Comma = 0x36, /* , or < */
  1000. -            Period    = 0x37, /* . or > */
  1001. -            Slash = 0x38, /* / or ? */
  1002. -            CapsLock  = 0x39, /* Caps Lock */
  1003. -            F1    = 0x3A, /* F1 */
  1004. -            F2    = 0x3B, /* F2 */
  1005. -            F3    = 0x3C, /* F3 */
  1006. -            F4    = 0x3D, /* F4 */
  1007. -            F5    = 0x3E, /* F5 */
  1008. -            F6    = 0x3F, /* F6 */
  1009. -            F7    = 0x40, /* F7 */
  1010. -            F8    = 0x41, /* F8 */
  1011. -            F9    = 0x42, /* F9 */
  1012. -            F10   = 0x43, /* F10 */
  1013. -            F11   = 0x44, /* F11 */
  1014. -            F12   = 0x45, /* F12 */
  1015. -            PrintScreen   = 0x46, /* Print Screen */
  1016. -            ScrollLock    = 0x47, /* Scroll Lock */
  1017. -            Pause = 0x48, /* Pause */
  1018. -            Insert    = 0x49, /* Insert */
  1019. -            Home  = 0x4A, /* Home */
  1020. -            PageUp    = 0x4B, /* Page Up */
  1021. -            DeleteForward = 0x4C, /* Delete Forward */
  1022. -            End   = 0x4D, /* End */
  1023. -            PageDown  = 0x4E, /* Page Down */
  1024. -            RightArrow    = 0x4F, /* Right Arrow */
  1025. -            LeftArrow = 0x50, /* Left Arrow */
  1026. -            DownArrow = 0x51, /* Down Arrow */
  1027. -            UpArrow   = 0x52, /* Up Arrow */
  1028. -            KeypadNumLock = 0x53, /* Keypad NumLock or Clear */
  1029. -            KeypadSlash   = 0x54, /* Keypad / */
  1030. -            KeypadAsterisk    = 0x55, /* Keypad * */
  1031. -            KeypadHyphen  = 0x56, /* Keypad - */
  1032. -            KeypadPlus    = 0x57, /* Keypad + */
  1033. -            KeypadEnter   = 0x58, /* Keypad Enter */
  1034. -            Keypad1   = 0x59, /* Keypad 1 or End */
  1035. -            Keypad2   = 0x5A, /* Keypad 2 or Down Arrow */
  1036. -            Keypad3   = 0x5B, /* Keypad 3 or Page Down */
  1037. -            Keypad4   = 0x5C, /* Keypad 4 or Left Arrow */
  1038. -            Keypad5   = 0x5D, /* Keypad 5 */
  1039. -            Keypad6   = 0x5E, /* Keypad 6 or Right Arrow */
  1040. -            Keypad7   = 0x5F, /* Keypad 7 or Home */
  1041. -            Keypad8   = 0x60, /* Keypad 8 or Up Arrow */
  1042. -            Keypad9   = 0x61, /* Keypad 9 or Page Up */
  1043. -            Keypad0   = 0x62, /* Keypad 0 or Insert */
  1044. -            KeypadPeriod  = 0x63, /* Keypad . or Delete */
  1045. -            NonUSBackslash    = 0x64, /* Non-US \ or | */
  1046. -            Application   = 0x65, /* Application */
  1047. -            Power = 0x66, /* Power */
  1048. -            KeypadEqualSign   = 0x67, /* Keypad = */
  1049. -            F13   = 0x68, /* F13 */
  1050. -            F14   = 0x69, /* F14 */
  1051. -            F15   = 0x6A, /* F15 */
  1052. -            F16   = 0x6B, /* F16 */
  1053. -            F17   = 0x6C, /* F17 */
  1054. -            F18   = 0x6D, /* F18 */
  1055. -            F19   = 0x6E, /* F19 */
  1056. -            F20   = 0x6F, /* F20 */
  1057. -            F21   = 0x70, /* F21 */
  1058. -            F22   = 0x71, /* F22 */
  1059. -            F23   = 0x72, /* F23 */
  1060. -            F24   = 0x73, /* F24 */
  1061. -            Execute   = 0x74, /* Execute */
  1062. -            Help  = 0x75, /* Help */
  1063. -            Menu  = 0x76, /* Menu */
  1064. -            Select    = 0x77, /* Select */
  1065. -            Stop  = 0x78, /* Stop */
  1066. -            Again = 0x79, /* Again */
  1067. -            Undo  = 0x7A, /* Undo */
  1068. -            Cut   = 0x7B, /* Cut */
  1069. -            Copy  = 0x7C, /* Copy */
  1070. -            Paste = 0x7D, /* Paste */
  1071. -            Find  = 0x7E, /* Find */
  1072. -            Mute  = 0x7F, /* Mute */
  1073. -            VolumeUp  = 0x80, /* Volume Up */
  1074. -            VolumeDown    = 0x81, /* Volume Down */
  1075. -            LockingCapsLock   = 0x82, /* Locking Caps Lock */
  1076. -            LockingNumLock    = 0x83, /* Locking Num Lock */
  1077. -            LockingScrollLock = 0x84, /* Locking Scroll Lock */
  1078. -            KeypadComma   = 0x85, /* Keypad Comma */
  1079. -            KeypadEqualSignAS400  = 0x86, /* Keypad Equal Sign for AS/400 */
  1080. -            International1    = 0x87, /* International1 */
  1081. -            International2    = 0x88, /* International2 */
  1082. -            International3    = 0x89, /* International3 */
  1083. -            International4    = 0x8A, /* International4 */
  1084. -            International5    = 0x8B, /* International5 */
  1085. -            International6    = 0x8C, /* International6 */
  1086. -            International7    = 0x8D, /* International7 */
  1087. -            International8    = 0x8E, /* International8 */
  1088. -            International9    = 0x8F, /* International9 */
  1089. -            LANG1 = 0x90, /* LANG1 */
  1090. -            LANG2 = 0x91, /* LANG2 */
  1091. -            LANG3 = 0x92, /* LANG3 */
  1092. -            LANG4 = 0x93, /* LANG4 */
  1093. -            LANG5 = 0x94, /* LANG5 */
  1094. -            LANG6 = 0x95, /* LANG6 */
  1095. -            LANG7 = 0x96, /* LANG7 */
  1096. -            LANG8 = 0x97, /* LANG8 */
  1097. -            LANG9 = 0x98, /* LANG9 */
  1098. -            AlternateErase    = 0x99, /* AlternateErase */
  1099. -            SysReqOrAttention = 0x9A, /* SysReq/Attention */
  1100. -            Cancel    = 0x9B, /* Cancel */
  1101. -            Clear = 0x9C, /* Clear */
  1102. -            Prior = 0x9D, /* Prior */
  1103. -            Return    = 0x9E, /* Return */
  1104. -            Separator = 0x9F, /* Separator */
  1105. -            Out   = 0xA0, /* Out */
  1106. -            Oper  = 0xA1, /* Oper */
  1107. -            ClearOrAgain  = 0xA2, /* Clear/Again */
  1108. -            CrSelOrProps  = 0xA3, /* CrSel/Props */
  1109. -            ExSel = 0xA4, /* ExSel */
  1110. -            /* 0xA5-0xDF Reserved */
  1111. -            LeftControl   = 0xE0, /* Left Control */
  1112. -            LeftShift = 0xE1, /* Left Shift */
  1113. -            LeftAlt   = 0xE2, /* Left Alt */
  1114. -            LeftGUI   = 0xE3, /* Left GUI */
  1115. -            RightControl  = 0xE4, /* Right Control */
  1116. -            RightShift    = 0xE5, /* Right Shift */
  1117. -            RightAlt  = 0xE6, /* Right Alt */
  1118. -            RightGUI  = 0xE7, /* Right GUI */
  1119. -            /* 0xE8-0xFFFF Reserved */
  1120. -            //_Reserved = 0xFFFF
  1121. -        }
  1122. -
  1123. -        // Maps HIDKey to OpenTK.Input.Key.
  1124. -        static readonly Key[] RawKeyMap = new Key[]
  1125. -        {
  1126. -            Key.Unknown,
  1127. -            Key.Unknown, /* ErrorRollOver */
  1128. -            Key.Unknown,  /* POSTFail */
  1129. -            Key.Unknown, /* ErrorUndefined */
  1130. -            Key.A, /* a or A */
  1131. -            Key.B, /* b or B */
  1132. -            Key.C, /* c or C */
  1133. -            Key.D, /* d or D */
  1134. -            Key.E, /* e or E */
  1135. -            Key.F, /* f or F */
  1136. -            Key.G, /* g or G */
  1137. -            Key.H, /* h or H */
  1138. -            Key.I, /* i or I */
  1139. -            Key.J, /* j or J */
  1140. -            Key.K, /* k or K */
  1141. -            Key.L, /* l or L */
  1142. -            Key.M, /* m or M */
  1143. -            Key.N, /* n or N */
  1144. -            Key.O, /* o or O */
  1145. -            Key.P, /* p or P */
  1146. -            Key.Q, /* q or Q */
  1147. -            Key.R, /* r or R */
  1148. -            Key.S, /* s or S */
  1149. -            Key.T, /* t or T */
  1150. -            Key.U, /* u or U */
  1151. -            Key.V, /* v or V */
  1152. -            Key.W, /* w or W */
  1153. -            Key.X, /* x or X */
  1154. -            Key.Y, /* y or Y */
  1155. -            Key.Z, /* z or Z */
  1156. -            Key.Number1, /* 1 or ! */
  1157. -            Key.Number2, /* 2 or @ */
  1158. -            Key.Number3, /* 3 or # */
  1159. -            Key.Number4, /* 4 or $ */
  1160. -            Key.Number5, /* 5 or % */
  1161. -            Key.Number6, /* 6 or ^ */
  1162. -            Key.Number7, /* 7 or & */
  1163. -            Key.Number8, /* 8 or * */
  1164. -            Key.Number9, /* 9 or ( */
  1165. -            Key.Number0, /* 0 or ) */
  1166. -            Key.Enter, /* Return (Enter) */
  1167. -            Key.Escape, /* Escape */
  1168. -            Key.BackSpace, /* Delete (Backspace) */
  1169. -            Key.Tab, /* Tab */
  1170. -            Key.Space, /* Spacebar */
  1171. -            Key.Minus, /* - or _ */
  1172. -            Key.Plus, /* = or + */
  1173. -            Key.BracketLeft, /* [ or { */
  1174. -            Key.BracketRight, /* ] or } */
  1175. -            Key.BackSlash, /* \ or | */
  1176. -            Key.Minus, /* Non-US # or _ */
  1177. -            Key.Semicolon, /* ; or : */
  1178. -            Key.Quote, /* ' or " */
  1179. -            Key.Tilde, /* Grave Accent and Tilde */
  1180. -            Key.Comma, /* , or < */
  1181. -            Key.Period, /* . or > */
  1182. -            Key.Slash, /* / or ? */
  1183. -            Key.CapsLock, /* Caps Lock */
  1184. -            Key.F1, /* F1 */
  1185. -            Key.F2, /* F2 */
  1186. -            Key.F3, /* F3 */
  1187. -            Key.F4, /* F4 */
  1188. -            Key.F5, /* F5 */
  1189. -            Key.F6, /* F6 */
  1190. -            Key.F7, /* F7 */
  1191. -            Key.F8, /* F8 */
  1192. -            Key.F9, /* F9 */
  1193. -            Key.F10, /* F10 */
  1194. -            Key.F11, /* F11 */
  1195. -            Key.F12, /* F12 */
  1196. -            Key.PrintScreen, /* Print Screen */
  1197. -            Key.ScrollLock, /* Scroll Lock */
  1198. -            Key.Pause, /* Pause */
  1199. -            Key.Insert, /* Insert */
  1200. -            Key.Home, /* Home */
  1201. -            Key.PageUp, /* Page Up */
  1202. -            Key.Delete, /* Delete Forward */
  1203. -            Key.End, /* End */
  1204. -            Key.PageDown, /* Page Down */
  1205. -            Key.Right, /* Right Arrow */
  1206. -            Key.Left, /* Left Arrow */
  1207. -            Key.Down, /* Down Arrow */
  1208. -            Key.Up, /* Up Arrow */
  1209. -            Key.NumLock, /* Keypad NumLock or Clear */
  1210. -            Key.KeypadDivide, /* Keypad / */
  1211. -            Key.KeypadMultiply, /* Keypad * */
  1212. -            Key.KeypadMinus, /* Keypad - */
  1213. -            Key.KeypadPlus, /* Keypad + */
  1214. -            Key.KeypadEnter, /* Keypad Enter */
  1215. -            Key.Keypad1, /* Keypad 1 or End */
  1216. -            Key.Keypad2, /* Keypad 2 or Down Arrow */
  1217. -            Key.Keypad3, /* Keypad 3 or Page Down */
  1218. -            Key.Keypad4, /* Keypad 4 or Left Arrow */
  1219. -            Key.Keypad5, /* Keypad 5 */
  1220. -            Key.Keypad6, /* Keypad 6 or Right Arrow */
  1221. -            Key.Keypad7, /* Keypad 7 or Home */
  1222. -            Key.Keypad8, /* Keypad 8 or Up Arrow */
  1223. -            Key.Keypad9, /* Keypad 9 or Page Up */
  1224. -            Key.Keypad0, /* Keypad 0 or Insert */
  1225. -            Key.KeypadDecimal, /* Keypad . or Delete */
  1226. -            Key.BackSlash, /* Non-US \ or | */
  1227. -            Key.Unknown, /* Application */
  1228. -            Key.Unknown, /* Power */
  1229. -            Key.Unknown, /* Keypad = */
  1230. -            Key.F13, /* F13 */
  1231. -            Key.F14, /* F14 */
  1232. -            Key.F15, /* F15 */
  1233. -            Key.F16, /* F16 */
  1234. -            Key.F17, /* F17 */
  1235. -            Key.F18, /* F18 */
  1236. -            Key.F19, /* F19 */
  1237. -            Key.F20, /* F20 */
  1238. -            Key.F21, /* F21 */
  1239. -            Key.F22, /* F22 */
  1240. -            Key.F23, /* F23 */
  1241. -            Key.F24, /* F24 */
  1242. -            Key.Unknown, /* Execute */
  1243. -            Key.Unknown, /* Help */
  1244. -            Key.Menu, /* Menu */
  1245. -            Key.Unknown, /* Select */
  1246. -            Key.Unknown, /* Stop */
  1247. -            Key.Unknown, /* Again */
  1248. -            Key.Unknown, /* Undo */
  1249. -            Key.Unknown, /* Cut */
  1250. -            Key.Unknown, /* Copy */
  1251. -            Key.Unknown, /* Paste */
  1252. -            Key.Unknown, /* Find */
  1253. -            Key.Unknown, /* Mute */
  1254. -            Key.Unknown, /* Volume Up */
  1255. -            Key.Unknown, /* Volume Down */
  1256. -            Key.CapsLock, /* Locking Caps Lock */
  1257. -            Key.NumLock , /* Locking Num Lock */
  1258. -            Key.ScrollLock, /* Locking Scroll Lock */
  1259. -            Key.KeypadDecimal, /* Keypad Comma */
  1260. -            Key.Unknown, /* Keypad Equal Sign for AS/400 */
  1261. -            Key.Unknown, /* International1 */
  1262. -            Key.Unknown, /* International2 */
  1263. -            Key.Unknown, /* International3 */
  1264. -            Key.Unknown, /* International4 */
  1265. -            Key.Unknown, /* International5 */
  1266. -            Key.Unknown, /* International6 */
  1267. -            Key.Unknown, /* International7 */
  1268. -            Key.Unknown, /* International8 */
  1269. -            Key.Unknown, /* International9 */
  1270. -            Key.Unknown, /* LANG1 */
  1271. -            Key.Unknown, /* LANG2 */
  1272. -            Key.Unknown, /* LANG3 */
  1273. -            Key.Unknown, /* LANG4 */
  1274. -            Key.Unknown, /* LANG5 */
  1275. -            Key.Unknown, /* LANG6 */
  1276. -            Key.Unknown, /* LANG7 */
  1277. -            Key.Unknown, /* LANG8 */
  1278. -            Key.Unknown, /* LANG9 */
  1279. -            Key.Unknown, /* AlternateErase */
  1280. -            Key.Unknown, /* SysReq/Attention */
  1281. -            Key.Unknown, /* Cancel */
  1282. -            Key.Unknown, /* Clear */
  1283. -            Key.Unknown, /* Prior */
  1284. -            Key.Enter, /* Return */
  1285. -            Key.Unknown, /* Separator */
  1286. -            Key.Unknown, /* Out */
  1287. -            Key.Unknown, /* Oper */
  1288. -            Key.Unknown, /* Clear/Again */
  1289. -            Key.Unknown, /* CrSel/Props */
  1290. -            Key.Unknown, /* ExSel */
  1291. -            /* 0xA5-0xDF Reserved */
  1292. -            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1293. -            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1294. -            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1295. -            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1296. -            Key.LControl, /* Left Control */
  1297. -            Key.LShift, /* Left Shift */
  1298. -            Key.LAlt, /* Left Alt */
  1299. -            Key.LWin, /* Left GUI */
  1300. -            Key.RControl, /* Right Control */
  1301. -            Key.RShift, /* Right Shift */
  1302. -            Key.RAlt, /* Right Alt */
  1303. -            Key.RWin, /* Right GUI */
  1304. -            /* 0xE8-0xFFFF Reserved */
  1305. -        };
  1306. -
  1307. -        #endregion
  1308. -    }
  1309. -}
  1310. -
  1311. +#region License
  1312. +//
  1313. +// The Open Toolkit Library License
  1314. +//
  1315. +// Copyright (c) 2006 - 2010 the Open Toolkit library.
  1316. +//
  1317. +// Permission is hereby granted, free of charge, to any person obtaining a copy
  1318. +// of this software and associated documentation files (the "Software"), to deal
  1319. +// in the Software without restriction, including without limitation the rights to
  1320. +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  1321. +// the Software, and to permit persons to whom the Software is furnished to do
  1322. +// so, subject to the following conditions:
  1323. +//
  1324. +// The above copyright notice and this permission notice shall be included in all
  1325. +// copies or substantial portions of the Software.
  1326. +//
  1327. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  1328. +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  1329. +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  1330. +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  1331. +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  1332. +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  1333. +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  1334. +// OTHER DEALINGS IN THE SOFTWARE.
  1335. +//
  1336. +#endregion
  1337. +
  1338. +using System;
  1339. +using System.Collections.Generic;
  1340. +using System.Diagnostics;
  1341. +using System.Runtime.InteropServices;
  1342. +using OpenTK.Input;
  1343. +
  1344. +namespace OpenTK.Platform.MacOS
  1345. +{
  1346. +    using Carbon;
  1347. +    using CFAllocatorRef = System.IntPtr;
  1348. +    using CFDictionaryRef = System.IntPtr;
  1349. +    using CFIndex = System.IntPtr;
  1350. +    using CFRunLoop = System.IntPtr;
  1351. +    using CFString = System.IntPtr;
  1352. +    using CFStringRef = System.IntPtr; // Here used interchangeably with the CFString
  1353. +    using CFTypeRef = System.IntPtr;
  1354. +    using IOHIDDeviceRef = System.IntPtr;
  1355. +    using IOHIDElementRef = System.IntPtr;
  1356. +    using IOHIDManagerRef = System.IntPtr;
  1357. +    using IOHIDValueRef = System.IntPtr;
  1358. +    using IOOptionBits = System.IntPtr;
  1359. +    using IOReturn = System.IntPtr;
  1360. +
  1361. +    // Requires Mac OS X 10.5 or higher.
  1362. +    // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that?
  1363. +    class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2
  1364. +    {
  1365. +        #region Fields
  1366. +
  1367. +        readonly IOHIDManagerRef hidmanager;
  1368. +
  1369. +        readonly Dictionary<IntPtr, MouseState> MouseDevices =
  1370. +            new Dictionary<IntPtr, MouseState>(new IntPtrEqualityComparer());
  1371. +        readonly Dictionary<int, IntPtr> MouseIndexToDevice =
  1372. +            new Dictionary<int, IntPtr>();
  1373. +        readonly Dictionary<IntPtr, KeyboardState> KeyboardDevices =
  1374. +            new Dictionary<IntPtr, KeyboardState>(new IntPtrEqualityComparer());
  1375. +        readonly Dictionary<int, IntPtr> KeyboardIndexToDevice =
  1376. +            new Dictionary<int, IntPtr>();
  1377. +
  1378. +        readonly CFRunLoop RunLoop = CF.CFRunLoopGetMain();
  1379. +        readonly CFString InputLoopMode = CF.RunLoopModeDefault;
  1380. +        readonly CFDictionary DeviceTypes = new CFDictionary();
  1381. +
  1382. +        readonly NativeMethods.IOHIDDeviceCallback HandleDeviceAdded;
  1383. +        readonly NativeMethods.IOHIDDeviceCallback HandleDeviceRemoved;
  1384. +        readonly NativeMethods.IOHIDValueCallback HandleDeviceValueReceived;
  1385. +
  1386. +        #endregion
  1387. +
  1388. +        #region Constructors
  1389. +
  1390. +        public HIDInput()
  1391. +        {
  1392. +            Debug.Print("Using HIDInput.");
  1393. +
  1394. +            HandleDeviceAdded = DeviceAdded;
  1395. +            HandleDeviceRemoved = DeviceRemoved;
  1396. +            HandleDeviceValueReceived = DeviceValueReceived;
  1397. +
  1398. +            hidmanager = CreateHIDManager();
  1399. +            RegisterHIDCallbacks(hidmanager);
  1400. +        }
  1401. +
  1402. +        #endregion
  1403. +
  1404. +         #region Private Members
  1405. +
  1406. +        IOHIDManagerRef CreateHIDManager()
  1407. +        {
  1408. +            return NativeMethods.IOHIDManagerCreate(IntPtr.Zero, IntPtr.Zero);
  1409. +        }
  1410. +
  1411. +        // Registers callbacks for device addition and removal. These callbacks
  1412. +        // are called when we run the loop in CheckDevicesMode
  1413. +        void RegisterHIDCallbacks(IOHIDManagerRef hidmanager)
  1414. +        {
  1415. +            NativeMethods.IOHIDManagerRegisterDeviceMatchingCallback(
  1416. +                hidmanager, HandleDeviceAdded, IntPtr.Zero);
  1417. +            NativeMethods.IOHIDManagerRegisterDeviceRemovalCallback(
  1418. +                hidmanager, HandleDeviceRemoved, IntPtr.Zero);
  1419. +            NativeMethods.IOHIDManagerScheduleWithRunLoop(hidmanager,
  1420. +                RunLoop, InputLoopMode);
  1421. +
  1422. +            NativeMethods.IOHIDManagerSetDeviceMatching(hidmanager, DeviceTypes.Ref);
  1423. +            NativeMethods.IOHIDManagerOpen(hidmanager, IOOptionBits.Zero);
  1424. +
  1425. +            OpenTK.Platform.MacOS.Carbon.CF.CFRunLoopRunInMode(InputLoopMode, 0.0, true);
  1426. +        }
  1427. +
  1428. +        void DeviceAdded(IntPtr context, IOReturn res, IntPtr sender, IOHIDDeviceRef device)
  1429. +        {
  1430. +            if (NativeMethods.IOHIDDeviceOpen(device, IOOptionBits.Zero) == IOReturn.Zero)
  1431. +            {
  1432. +                if (NativeMethods.IOHIDDeviceConformsTo(device,
  1433. +                        HIDPage.GenericDesktop, (int)HIDUsageGD.Mouse))
  1434. +                {
  1435. +                    if (!MouseDevices.ContainsKey(device))
  1436. +                    {
  1437. +                        Debug.Print("Mouse device {0} discovered", device);
  1438. +                        MouseState state = new MouseState();
  1439. +                        state.IsConnected = true;
  1440. +                        MouseIndexToDevice.Add(MouseDevices.Count, device);
  1441. +                        MouseDevices.Add(device, state);
  1442. +                    }
  1443. +                    else
  1444. +                    {
  1445. +                        Debug.Print("Mouse device {0} reconnected", device);
  1446. +                        MouseState state = MouseDevices[device];
  1447. +                        state.IsConnected = true;
  1448. +                        MouseDevices[device] = state;
  1449. +                    }
  1450. +                }
  1451. +
  1452. +                if (NativeMethods.IOHIDDeviceConformsTo(device,
  1453. +                        HIDPage.GenericDesktop, (int)HIDUsageGD.Keyboard))
  1454. +                {
  1455. +                    if (!KeyboardDevices.ContainsKey(device))
  1456. +                    {
  1457. +                        Debug.Print("Keyboard device {0} discovered", device);
  1458. +                        KeyboardState state = new KeyboardState();
  1459. +                        state.IsConnected = true;
  1460. +                        KeyboardIndexToDevice.Add(KeyboardDevices.Count, device);
  1461. +                        KeyboardDevices.Add(device, state);
  1462. +                    }
  1463. +                    else
  1464. +                    {
  1465. +                        Debug.Print("Keyboard device {0} reconnected", device);
  1466. +                        KeyboardState state = KeyboardDevices[device];
  1467. +                        state.IsConnected = true;
  1468. +                        KeyboardDevices[device] = state;
  1469. +                    }
  1470. +                }
  1471. +
  1472. +                NativeMethods.IOHIDDeviceRegisterInputValueCallback(device,
  1473. +                    HandleDeviceValueReceived, IntPtr.Zero);
  1474. +                NativeMethods.IOHIDDeviceScheduleWithRunLoop(device, RunLoop, InputLoopMode);
  1475. +            }
  1476. +        }
  1477. +
  1478. +        void DeviceRemoved(IntPtr context, IOReturn res, IntPtr sender, IOHIDDeviceRef device)
  1479. +        {
  1480. +            if (NativeMethods.IOHIDDeviceConformsTo(device, HIDPage.GenericDesktop, (int)HIDUsageGD.Mouse) &&
  1481. +                MouseDevices.ContainsKey(device))
  1482. +            {
  1483. +                Debug.Print("Mouse device {0} disconnected", device);
  1484. +
  1485. +                // Keep the device in case it comes back later on
  1486. +                MouseState state = MouseDevices[device];
  1487. +                state.IsConnected = false;
  1488. +                MouseDevices[device] = state;
  1489. +            }
  1490. +
  1491. +            if (NativeMethods.IOHIDDeviceConformsTo(device, HIDPage.GenericDesktop, (int)HIDUsageGD.Keyboard) &&
  1492. +                KeyboardDevices.ContainsKey(device))
  1493. +            {
  1494. +                Debug.Print("Keyboard device {0} disconnected", device);
  1495. +
  1496. +                // Keep the device in case it comes back later on
  1497. +                KeyboardState state = KeyboardDevices[device];
  1498. +                state.IsConnected = false;
  1499. +                KeyboardDevices[device] = state;
  1500. +            }
  1501. +
  1502. +            NativeMethods.IOHIDDeviceRegisterInputValueCallback(device, null, IntPtr.Zero);
  1503. +            NativeMethods.IOHIDDeviceUnscheduleWithRunLoop(device, RunLoop, InputLoopMode);
  1504. +        }
  1505. +
  1506. +        void DeviceValueReceived(IntPtr context, IOReturn res, IntPtr sender, IOHIDValueRef val)
  1507. +        {
  1508. +            MouseState mouse;
  1509. +            KeyboardState keyboard;
  1510. +            if (MouseDevices.TryGetValue(sender, out mouse))
  1511. +            {
  1512. +                MouseDevices[sender] = UpdateMouse(mouse, val);
  1513. +            }
  1514. +            else if (KeyboardDevices.TryGetValue(sender, out keyboard))
  1515. +            {
  1516. +                KeyboardDevices[sender] = UpdateKeyboard(keyboard, val);
  1517. +            }
  1518. +        }
  1519. +
  1520. +        static MouseState UpdateMouse(MouseState state, IOHIDValueRef val)
  1521. +        {
  1522. +            IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val);
  1523. +            int v_int = NativeMethods.IOHIDValueGetIntegerValue(val).ToInt32();
  1524. +            //double v_physical = NativeMethods.IOHIDValueGetScaledValue(val, IOHIDValueScaleType.Physical);
  1525. +            //double v_calbrated = NativeMethods.IOHIDValueGetScaledValue(val, IOHIDValueScaleType.Calibrated);
  1526. +            HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem);
  1527. +            int usage = NativeMethods.IOHIDElementGetUsage(elem);
  1528. +
  1529. +            switch (page)
  1530. +            {
  1531. +                case HIDPage.GenericDesktop:
  1532. +                    switch ((HIDUsageGD)usage)
  1533. +                    {
  1534. +                        case HIDUsageGD.X:
  1535. +                            state.X += v_int;
  1536. +                            break;
  1537. +
  1538. +                        case HIDUsageGD.Y:
  1539. +                            state.Y += v_int;
  1540. +                            break;
  1541. +
  1542. +                        case HIDUsageGD.Wheel:
  1543. +                            state.WheelPrecise += v_int;
  1544. +                            break;
  1545. +                    }
  1546. +                    break;
  1547. +
  1548. +                case HIDPage.Button:
  1549. +                    state[OpenTK.Input.MouseButton.Left + usage - 1] = v_int == 1;
  1550. +                    break;
  1551. +            }
  1552. +
  1553. +            return state;
  1554. +        }
  1555. +
  1556. +        static KeyboardState UpdateKeyboard(KeyboardState state, IOHIDValueRef val)
  1557. +        {
  1558. +            IOHIDElementRef elem = NativeMethods.IOHIDValueGetElement(val);
  1559. +            int v_int = NativeMethods.IOHIDValueGetIntegerValue(val).ToInt32();
  1560. +            HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem);
  1561. +            int usage = NativeMethods.IOHIDElementGetUsage(elem);
  1562. +
  1563. +            switch (page)
  1564. +            {
  1565. +                case HIDPage.GenericDesktop:
  1566. +                case HIDPage.KeyboardOrKeypad:
  1567. +                    if (usage >= RawKeyMap.Length || usage < 0)
  1568. +                        Debug.Print("[Warning] Key {0} not mapped.", usage);
  1569. +                    state.SetKeyState(RawKeyMap[usage], (byte)usage, v_int != 0);
  1570. +                    break;
  1571. +            }
  1572. +
  1573. +            return state;
  1574. +        }
  1575. +
  1576. +        #endregion
  1577. +
  1578. +        #region IInputDriver2 Members
  1579. +
  1580. +        public IMouseDriver2 MouseDriver { get { return this; } }
  1581. +        public IKeyboardDriver2 KeyboardDriver { get { return this; } }
  1582. +        public IGamePadDriver GamePadDriver { get { throw new NotImplementedException(); } }
  1583. +
  1584. +        #endregion
  1585. +
  1586. +        #region IMouseDriver2 Members
  1587. +
  1588. +        MouseState IMouseDriver2.GetState()
  1589. +        {
  1590. +            MouseState master = new MouseState();
  1591. +            foreach (KeyValuePair<IntPtr, MouseState> item in MouseDevices)
  1592. +            {
  1593. +                master.MergeBits(item.Value);
  1594. +            }
  1595. +
  1596. +            return master;
  1597. +        }
  1598. +
  1599. +        MouseState IMouseDriver2.GetState(int index)
  1600. +        {
  1601. +            IntPtr device;
  1602. +            if (MouseIndexToDevice.TryGetValue(index, out device))
  1603. +            {
  1604. +                return MouseDevices[device];
  1605. +            }
  1606. +
  1607. +            return new MouseState();
  1608. +        }
  1609. +
  1610. +        void IMouseDriver2.SetPosition(double x, double y)
  1611. +        {
  1612. +            CG.SetLocalEventsSuppressionInterval(0.0);
  1613. +            CG.WarpMouseCursorPosition(new Carbon.HIPoint(x, y));
  1614. +        }
  1615. +
  1616. +        #endregion
  1617. +
  1618. +        #region IKeyboardDriver2
  1619. +
  1620. +        KeyboardState IKeyboardDriver2.GetState()
  1621. +        {
  1622. +            KeyboardState master = new KeyboardState();
  1623. +            foreach (KeyValuePair<IntPtr, KeyboardState> item in KeyboardDevices)
  1624. +            {
  1625. +                master.MergeBits(item.Value);
  1626. +            }
  1627. +
  1628. +            return master;
  1629. +        }
  1630. +
  1631. +        KeyboardState IKeyboardDriver2.GetState(int index)
  1632. +        {
  1633. +            IntPtr device;
  1634. +            if (KeyboardIndexToDevice.TryGetValue(index, out device))
  1635. +            {
  1636. +                return KeyboardDevices[device];
  1637. +            }
  1638. +
  1639. +            return new KeyboardState();
  1640. +        }
  1641. +
  1642. +        string IKeyboardDriver2.GetDeviceName(int index)
  1643. +        {
  1644. +            IntPtr device;
  1645. +            if (KeyboardIndexToDevice.TryGetValue(index, out device))
  1646. +            {
  1647. +                IntPtr vendor_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDVendorIDKey);
  1648. +                IntPtr product_id = NativeMethods.IOHIDDeviceGetProperty(device, NativeMethods.IOHIDProductIDKey);
  1649. +                // Todo: find out the real vendor/product name from the relevant ids.
  1650. +                return String.Format("{0}:{1}", vendor_id, product_id);
  1651. +            }
  1652. +            return String.Empty;
  1653. +        }
  1654. +
  1655. +        #endregion
  1656. +
  1657. +        #region NativeMethods
  1658. +
  1659. +        class NativeMethods
  1660. +        {
  1661. +            const string hid = "/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit";
  1662. +
  1663. +            public static readonly CFString IOHIDVendorIDKey = CF.CFSTR("VendorID");
  1664. +            public static readonly CFString IOHIDVendorIDSourceKey = CF.CFSTR("VendorIDSource");
  1665. +            public static readonly CFString IOHIDProductIDKey = CF.CFSTR("ProductID");
  1666. +            public static readonly CFString IOHIDVersionNumberKey = CF.CFSTR("VersionNumber");
  1667. +            public static readonly CFString IOHIDManufacturerKey = CF.CFSTR("Manufacturer");
  1668. +            public static readonly CFString IOHIDProductKey = CF.CFSTR("Product");
  1669. +            public static readonly CFString IOHIDDeviceUsageKey = CF.CFSTR("DeviceUsage");
  1670. +            public static readonly CFString IOHIDDeviceUsagePageKey = CF.CFSTR("DeviceUsagePage");
  1671. +            public static readonly CFString IOHIDDeviceUsagePairsKey = CF.CFSTR("DeviceUsagePairs");
  1672. +
  1673. +            [DllImport(hid)]
  1674. +            public static extern IOHIDManagerRef IOHIDManagerCreate(
  1675. +                CFAllocatorRef allocator, IOOptionBits options) ;
  1676. +
  1677. +            // This routine will be called when a new (matching) device is connected.
  1678. +            [DllImport(hid)]
  1679. +            public static extern void IOHIDManagerRegisterDeviceMatchingCallback(
  1680. +                IOHIDManagerRef inIOHIDManagerRef,
  1681. +                IOHIDDeviceCallback inIOHIDDeviceCallback,
  1682. +                IntPtr inContext);
  1683. +
  1684. +            // This routine will be called when a (matching) device is disconnected.
  1685. +            [DllImport(hid)]
  1686. +            public static extern void IOHIDManagerRegisterDeviceRemovalCallback(
  1687. +                IOHIDManagerRef inIOHIDManagerRef,
  1688. +                IOHIDDeviceCallback inIOHIDDeviceCallback,
  1689. +                IntPtr inContext);
  1690. +
  1691. +            [DllImport(hid)]
  1692. +            public static extern void IOHIDManagerScheduleWithRunLoop(
  1693. +                IOHIDManagerRef inIOHIDManagerRef,
  1694. +                CFRunLoop inCFRunLoop,
  1695. +                CFString inCFRunLoopMode);
  1696. +
  1697. +            [DllImport(hid)]
  1698. +            public static extern void IOHIDManagerSetDeviceMatching(
  1699. +                IOHIDManagerRef manager,
  1700. +                CFDictionaryRef matching) ;
  1701. +
  1702. +            [DllImport(hid)]
  1703. +            public static extern IOReturn IOHIDManagerOpen(
  1704. +                IOHIDManagerRef manager,
  1705. +                IOOptionBits options) ;
  1706. +
  1707. +            [DllImport(hid)]
  1708. +            public static extern IOReturn IOHIDDeviceOpen(
  1709. +                IOHIDDeviceRef manager,
  1710. +                IOOptionBits opts);
  1711. +
  1712. +            [DllImport(hid)]
  1713. +            public static extern CFTypeRef IOHIDDeviceGetProperty(
  1714. +                IOHIDDeviceRef device,
  1715. +                CFStringRef key);
  1716. +
  1717. +            [DllImport(hid)]
  1718. +            public static extern bool IOHIDDeviceConformsTo(
  1719. +                IOHIDDeviceRef inIOHIDDeviceRef,  // IOHIDDeviceRef for the HID device
  1720. +                HIDPage inUsagePage,      // the usage page to test conformance with
  1721. +                int inUsage);         // the usage to test conformance with
  1722. +
  1723. +            [DllImport(hid)]
  1724. +            public static extern void IOHIDDeviceRegisterInputValueCallback(
  1725. +                IOHIDDeviceRef device,
  1726. +                IOHIDValueCallback callback,
  1727. +                IntPtr context);
  1728. +
  1729. +            [DllImport(hid)]
  1730. +            public static extern void IOHIDDeviceScheduleWithRunLoop(
  1731. +                IOHIDDeviceRef device,
  1732. +                CFRunLoop inCFRunLoop,
  1733. +                CFString inCFRunLoopMode);
  1734. +
  1735. +            [DllImport(hid)]
  1736. +            public static extern void IOHIDDeviceUnscheduleWithRunLoop(
  1737. +                IOHIDDeviceRef device,
  1738. +                CFRunLoop inCFRunLoop,
  1739. +                CFString inCFRunLoopMode);
  1740. +
  1741. +            [DllImport(hid)]
  1742. +            public static extern IOHIDElementRef IOHIDValueGetElement(IOHIDValueRef @value);
  1743. +
  1744. +            [DllImport(hid)]
  1745. +            public static extern CFIndex IOHIDValueGetIntegerValue(IOHIDValueRef @value);
  1746. +
  1747. +            [DllImport(hid)]
  1748. +            public static extern double IOHIDValueGetScaledValue(
  1749. +                IOHIDValueRef @value,
  1750. +                IOHIDValueScaleType type) ;
  1751. +
  1752. +            [DllImport(hid)]
  1753. +            public static extern int IOHIDElementGetUsage(IOHIDElementRef elem);
  1754. +
  1755. +            [DllImport(hid)]
  1756. +            public static extern HIDPage IOHIDElementGetUsagePage(IOHIDElementRef elem);
  1757. +
  1758. +            public delegate void IOHIDDeviceCallback(IntPtr ctx, IOReturn res, IntPtr sender, IOHIDDeviceRef device);
  1759. +            public delegate void IOHIDValueCallback(IntPtr ctx, IOReturn res, IntPtr sender, IOHIDValueRef val);
  1760. +        }
  1761. +
  1762. +        enum IOHIDValueScaleType
  1763. +        {
  1764. +            Physical, // [device min, device max]
  1765. +            Calibrated // [-1, +1]
  1766. +        }
  1767. +
  1768. +        enum HIDPage
  1769. +        {
  1770. +            Undefined  = 0x00,
  1771. +            GenericDesktop = 0x01,
  1772. +            Simulation = 0x02,
  1773. +            VR = 0x03,
  1774. +            Sport  = 0x04,
  1775. +            Game   = 0x05,
  1776. +            /* Reserved 0x06 */
  1777. +            KeyboardOrKeypad   = 0x07, /* USB Device Class Definition for Human Interface Devices (HID). Note: the usage type for all key codes is Selector (Sel). */
  1778. +            LEDs   = 0x08,
  1779. +            Button = 0x09,
  1780. +            Ordinal    = 0x0A,
  1781. +            Telephony  = 0x0B,
  1782. +            Consumer   = 0x0C,
  1783. +            Digitizer  = 0x0D,
  1784. +            /* Reserved 0x0E */
  1785. +            PID    = 0x0F, /* USB Physical Interface Device definitions for force feedback and related devices. */
  1786. +            Unicode    = 0x10,
  1787. +            /* Reserved 0x11 - 0x13 */
  1788. +            AlphanumericDisplay    = 0x14,
  1789. +            /* Reserved 0x15 - 0x7F */
  1790. +            /* Monitor 0x80 - 0x83   USB Device Class Definition for Monitor Devices */
  1791. +            /* Power 0x84 - 0x87     USB Device Class Definition for Power Devices */
  1792. +            PowerDevice = 0x84,                /* Power Device Page */
  1793. +            BatterySystem = 0x85,              /* Battery System Page */
  1794. +            /* Reserved 0x88 - 0x8B */
  1795. +            BarCodeScanner = 0x8C, /* (Point of Sale) USB Device Class Definition for Bar Code Scanner Devices */
  1796. +            WeighingDevice = 0x8D, /* (Point of Sale) USB Device Class Definition for Weighing Devices */
  1797. +            Scale  = 0x8D, /* (Point of Sale) USB Device Class Definition for Scale Devices */
  1798. +            MagneticStripeReader = 0x8E,
  1799. +            /* ReservedPointofSalepages 0x8F */
  1800. +            CameraControl  = 0x90, /* USB Device Class Definition for Image Class Devices */
  1801. +            Arcade = 0x91, /* OAAF Definitions for arcade and coinop related Devices */
  1802. +            /* Reserved 0x92 - 0xFEFF */
  1803. +            /* VendorDefined 0xFF00 - 0xFFFF */
  1804. +            VendorDefinedStart = 0xFF00
  1805. +        }
  1806. +
  1807. +        // Generic desktop usage
  1808. +        enum HIDUsageGD
  1809. +        {
  1810. +            Pointer    = 0x01, /* Physical Collection */
  1811. +            Mouse  = 0x02, /* Application Collection */
  1812. +            /* 0x03 Reserved */
  1813. +            Joystick   = 0x04, /* Application Collection */
  1814. +            GamePad    = 0x05, /* Application Collection */
  1815. +            Keyboard   = 0x06, /* Application Collection */
  1816. +            Keypad = 0x07, /* Application Collection */
  1817. +            MultiAxisController    = 0x08, /* Application Collection */
  1818. +            /* 0x09 - 0x2F Reserved */
  1819. +            X  = 0x30, /* Dynamic Value */
  1820. +            Y  = 0x31, /* Dynamic Value */
  1821. +            Z  = 0x32, /* Dynamic Value */
  1822. +            Rx = 0x33, /* Dynamic Value */
  1823. +            Ry = 0x34, /* Dynamic Value */
  1824. +            Rz = 0x35, /* Dynamic Value */
  1825. +            Slider = 0x36, /* Dynamic Value */
  1826. +            Dial   = 0x37, /* Dynamic Value */
  1827. +            Wheel  = 0x38, /* Dynamic Value */
  1828. +            Hatswitch  = 0x39, /* Dynamic Value */
  1829. +            CountedBuffer  = 0x3A, /* Logical Collection */
  1830. +            ByteCount  = 0x3B, /* Dynamic Value */
  1831. +            MotionWakeup   = 0x3C, /* One-Shot Control */
  1832. +            Start  = 0x3D, /* On/Off Control */
  1833. +            Select = 0x3E, /* On/Off Control */
  1834. +            /* 0x3F Reserved */
  1835. +            Vx = 0x40, /* Dynamic Value */
  1836. +            Vy = 0x41, /* Dynamic Value */
  1837. +            Vz = 0x42, /* Dynamic Value */
  1838. +            Vbrx   = 0x43, /* Dynamic Value */
  1839. +            Vbry   = 0x44, /* Dynamic Value */
  1840. +            Vbrz   = 0x45, /* Dynamic Value */
  1841. +            Vno    = 0x46, /* Dynamic Value */
  1842. +            /* 0x47 - 0x7F Reserved */
  1843. +            SystemControl  = 0x80, /* Application Collection */
  1844. +            SystemPowerDown    = 0x81, /* One-Shot Control */
  1845. +            SystemSleep    = 0x82, /* One-Shot Control */
  1846. +            SystemWakeUp   = 0x83, /* One-Shot Control */
  1847. +            SystemContextMenu  = 0x84, /* One-Shot Control */
  1848. +            SystemMainMenu = 0x85, /* One-Shot Control */
  1849. +            SystemAppMenu  = 0x86, /* One-Shot Control */
  1850. +            SystemMenuHelp = 0x87, /* One-Shot Control */
  1851. +            SystemMenuExit = 0x88, /* One-Shot Control */
  1852. +            SystemMenu = 0x89, /* Selector */
  1853. +            SystemMenuRight    = 0x8A, /* Re-Trigger Control */
  1854. +            SystemMenuLeft = 0x8B, /* Re-Trigger Control */
  1855. +            SystemMenuUp   = 0x8C, /* Re-Trigger Control */
  1856. +            SystemMenuDown = 0x8D, /* Re-Trigger Control */
  1857. +            /* 0x8E - 0x8F Reserved */
  1858. +            DPadUp = 0x90, /* On/Off Control */
  1859. +            DPadDown   = 0x91, /* On/Off Control */
  1860. +            DPadRight  = 0x92, /* On/Off Control */
  1861. +            DPadLeft   = 0x93, /* On/Off Control */
  1862. +            /* 0x94 - 0xFFFF Reserved */
  1863. +            Reserved = 0xFFFF
  1864. +        }
  1865. +
  1866. +        enum HIDButton
  1867. +        {
  1868. +            Button_1  = 0x01, /* (primary/trigger) */
  1869. +            Button_2  = 0x02, /* (secondary) */
  1870. +            Button_3  = 0x03, /* (tertiary) */
  1871. +            Button_4  = 0x04, /* 4th button */
  1872. +            /* ... */
  1873. +            Button_65535  = 0xFFFF
  1874. +        }
  1875. +
  1876. +        enum HIDKey
  1877. +        {
  1878. +            ErrorRollOver = 0x01, /* ErrorRollOver */
  1879. +            POSTFail  = 0x02, /* POSTFail */
  1880. +            ErrorUndefined    = 0x03, /* ErrorUndefined */
  1881. +            A = 0x04, /* a or A */
  1882. +            B = 0x05, /* b or B */
  1883. +            C = 0x06, /* c or C */
  1884. +            D = 0x07, /* d or D */
  1885. +            E = 0x08, /* e or E */
  1886. +            F = 0x09, /* f or F */
  1887. +            G = 0x0A, /* g or G */
  1888. +            H = 0x0B, /* h or H */
  1889. +            I = 0x0C, /* i or I */
  1890. +            J = 0x0D, /* j or J */
  1891. +            K = 0x0E, /* k or K */
  1892. +            L = 0x0F, /* l or L */
  1893. +            M = 0x10, /* m or M */
  1894. +            N = 0x11, /* n or N */
  1895. +            O = 0x12, /* o or O */
  1896. +            P = 0x13, /* p or P */
  1897. +            Q = 0x14, /* q or Q */
  1898. +            R = 0x15, /* r or R */
  1899. +            S = 0x16, /* s or S */
  1900. +            T = 0x17, /* t or T */
  1901. +            U = 0x18, /* u or U */
  1902. +            V = 0x19, /* v or V */
  1903. +            W = 0x1A, /* w or W */
  1904. +            X = 0x1B, /* x or X */
  1905. +            Y = 0x1C, /* y or Y */
  1906. +            Z = 0x1D, /* z or Z */
  1907. +            Number1 = 0x1E, /* 1 or ! */
  1908. +            Number2 = 0x1F, /* 2 or @ */
  1909. +            Number3 = 0x20, /* 3 or # */
  1910. +            Number4 = 0x21, /* 4 or $ */
  1911. +            Number5 = 0x22, /* 5 or % */
  1912. +            Number6 = 0x23, /* 6 or ^ */
  1913. +            Number7 = 0x24, /* 7 or & */
  1914. +            Number8 = 0x25, /* 8 or * */
  1915. +            Number9 = 0x26, /* 9 or ( */
  1916. +            Number0 = 0x27, /* 0 or ) */
  1917. +            ReturnOrEnter = 0x28, /* Return (Enter) */
  1918. +            Escape    = 0x29, /* Escape */
  1919. +            DeleteOrBackspace = 0x2A, /* Delete (Backspace) */
  1920. +            Tab   = 0x2B, /* Tab */
  1921. +            Spacebar  = 0x2C, /* Spacebar */
  1922. +            Hyphen    = 0x2D, /* - or _ */
  1923. +            EqualSign = 0x2E, /* = or + */
  1924. +            OpenBracket   = 0x2F, /* [ or { */
  1925. +            CloseBracket  = 0x30, /* ] or } */
  1926. +            Backslash = 0x31, /* \ or | */
  1927. +            NonUSPound    = 0x32, /* Non-US # or _ */
  1928. +            Semicolon = 0x33, /* ; or : */
  1929. +            Quote = 0x34, /* ' or " */
  1930. +            GraveAccentAndTilde   = 0x35, /* Grave Accent and Tilde */
  1931. +            Comma = 0x36, /* , or < */
  1932. +            Period    = 0x37, /* . or > */
  1933. +            Slash = 0x38, /* / or ? */
  1934. +            CapsLock  = 0x39, /* Caps Lock */
  1935. +            F1    = 0x3A, /* F1 */
  1936. +            F2    = 0x3B, /* F2 */
  1937. +            F3    = 0x3C, /* F3 */
  1938. +            F4    = 0x3D, /* F4 */
  1939. +            F5    = 0x3E, /* F5 */
  1940. +            F6    = 0x3F, /* F6 */
  1941. +            F7    = 0x40, /* F7 */
  1942. +            F8    = 0x41, /* F8 */
  1943. +            F9    = 0x42, /* F9 */
  1944. +            F10   = 0x43, /* F10 */
  1945. +            F11   = 0x44, /* F11 */
  1946. +            F12   = 0x45, /* F12 */
  1947. +            PrintScreen   = 0x46, /* Print Screen */
  1948. +            ScrollLock    = 0x47, /* Scroll Lock */
  1949. +            Pause = 0x48, /* Pause */
  1950. +            Insert    = 0x49, /* Insert */
  1951. +            Home  = 0x4A, /* Home */
  1952. +            PageUp    = 0x4B, /* Page Up */
  1953. +            DeleteForward = 0x4C, /* Delete Forward */
  1954. +            End   = 0x4D, /* End */
  1955. +            PageDown  = 0x4E, /* Page Down */
  1956. +            RightArrow    = 0x4F, /* Right Arrow */
  1957. +            LeftArrow = 0x50, /* Left Arrow */
  1958. +            DownArrow = 0x51, /* Down Arrow */
  1959. +            UpArrow   = 0x52, /* Up Arrow */
  1960. +            KeypadNumLock = 0x53, /* Keypad NumLock or Clear */
  1961. +            KeypadSlash   = 0x54, /* Keypad / */
  1962. +            KeypadAsterisk    = 0x55, /* Keypad * */
  1963. +            KeypadHyphen  = 0x56, /* Keypad - */
  1964. +            KeypadPlus    = 0x57, /* Keypad + */
  1965. +            KeypadEnter   = 0x58, /* Keypad Enter */
  1966. +            Keypad1   = 0x59, /* Keypad 1 or End */
  1967. +            Keypad2   = 0x5A, /* Keypad 2 or Down Arrow */
  1968. +            Keypad3   = 0x5B, /* Keypad 3 or Page Down */
  1969. +            Keypad4   = 0x5C, /* Keypad 4 or Left Arrow */
  1970. +            Keypad5   = 0x5D, /* Keypad 5 */
  1971. +            Keypad6   = 0x5E, /* Keypad 6 or Right Arrow */
  1972. +            Keypad7   = 0x5F, /* Keypad 7 or Home */
  1973. +            Keypad8   = 0x60, /* Keypad 8 or Up Arrow */
  1974. +            Keypad9   = 0x61, /* Keypad 9 or Page Up */
  1975. +            Keypad0   = 0x62, /* Keypad 0 or Insert */
  1976. +            KeypadPeriod  = 0x63, /* Keypad . or Delete */
  1977. +            NonUSBackslash    = 0x64, /* Non-US \ or | */
  1978. +            Application   = 0x65, /* Application */
  1979. +            Power = 0x66, /* Power */
  1980. +            KeypadEqualSign   = 0x67, /* Keypad = */
  1981. +            F13   = 0x68, /* F13 */
  1982. +            F14   = 0x69, /* F14 */
  1983. +            F15   = 0x6A, /* F15 */
  1984. +            F16   = 0x6B, /* F16 */
  1985. +            F17   = 0x6C, /* F17 */
  1986. +            F18   = 0x6D, /* F18 */
  1987. +            F19   = 0x6E, /* F19 */
  1988. +            F20   = 0x6F, /* F20 */
  1989. +            F21   = 0x70, /* F21 */
  1990. +            F22   = 0x71, /* F22 */
  1991. +            F23   = 0x72, /* F23 */
  1992. +            F24   = 0x73, /* F24 */
  1993. +            Execute   = 0x74, /* Execute */
  1994. +            Help  = 0x75, /* Help */
  1995. +            Menu  = 0x76, /* Menu */
  1996. +            Select    = 0x77, /* Select */
  1997. +            Stop  = 0x78, /* Stop */
  1998. +            Again = 0x79, /* Again */
  1999. +            Undo  = 0x7A, /* Undo */
  2000. +            Cut   = 0x7B, /* Cut */
  2001. +            Copy  = 0x7C, /* Copy */
  2002. +            Paste = 0x7D, /* Paste */
  2003. +            Find  = 0x7E, /* Find */
  2004. +            Mute  = 0x7F, /* Mute */
  2005. +            VolumeUp  = 0x80, /* Volume Up */
  2006. +            VolumeDown    = 0x81, /* Volume Down */
  2007. +            LockingCapsLock   = 0x82, /* Locking Caps Lock */
  2008. +            LockingNumLock    = 0x83, /* Locking Num Lock */
  2009. +            LockingScrollLock = 0x84, /* Locking Scroll Lock */
  2010. +            KeypadComma   = 0x85, /* Keypad Comma */
  2011. +            KeypadEqualSignAS400  = 0x86, /* Keypad Equal Sign for AS/400 */
  2012. +            International1    = 0x87, /* International1 */
  2013. +            International2    = 0x88, /* International2 */
  2014. +            International3    = 0x89, /* International3 */
  2015. +            International4    = 0x8A, /* International4 */
  2016. +            International5    = 0x8B, /* International5 */
  2017. +            International6    = 0x8C, /* International6 */
  2018. +            International7    = 0x8D, /* International7 */
  2019. +            International8    = 0x8E, /* International8 */
  2020. +            International9    = 0x8F, /* International9 */
  2021. +            LANG1 = 0x90, /* LANG1 */
  2022. +            LANG2 = 0x91, /* LANG2 */
  2023. +            LANG3 = 0x92, /* LANG3 */
  2024. +            LANG4 = 0x93, /* LANG4 */
  2025. +            LANG5 = 0x94, /* LANG5 */
  2026. +            LANG6 = 0x95, /* LANG6 */
  2027. +            LANG7 = 0x96, /* LANG7 */
  2028. +            LANG8 = 0x97, /* LANG8 */
  2029. +            LANG9 = 0x98, /* LANG9 */
  2030. +            AlternateErase    = 0x99, /* AlternateErase */
  2031. +            SysReqOrAttention = 0x9A, /* SysReq/Attention */
  2032. +            Cancel    = 0x9B, /* Cancel */
  2033. +            Clear = 0x9C, /* Clear */
  2034. +            Prior = 0x9D, /* Prior */
  2035. +            Return    = 0x9E, /* Return */
  2036. +            Separator = 0x9F, /* Separator */
  2037. +            Out   = 0xA0, /* Out */
  2038. +            Oper  = 0xA1, /* Oper */
  2039. +            ClearOrAgain  = 0xA2, /* Clear/Again */
  2040. +            CrSelOrProps  = 0xA3, /* CrSel/Props */
  2041. +            ExSel = 0xA4, /* ExSel */
  2042. +            /* 0xA5-0xDF Reserved */
  2043. +            LeftControl   = 0xE0, /* Left Control */
  2044. +            LeftShift = 0xE1, /* Left Shift */
  2045. +            LeftAlt   = 0xE2, /* Left Alt */
  2046. +            LeftGUI   = 0xE3, /* Left GUI */
  2047. +            RightControl  = 0xE4, /* Right Control */
  2048. +            RightShift    = 0xE5, /* Right Shift */
  2049. +            RightAlt  = 0xE6, /* Right Alt */
  2050. +            RightGUI  = 0xE7, /* Right GUI */
  2051. +            /* 0xE8-0xFFFF Reserved */
  2052. +            //_Reserved = 0xFFFF
  2053. +        }
  2054. +
  2055. +        // Maps HIDKey to OpenTK.Input.Key.
  2056. +        static readonly Key[] RawKeyMap = new Key[]
  2057. +        {
  2058. +            Key.Unknown,
  2059. +            Key.Unknown, /* ErrorRollOver */
  2060. +            Key.Unknown,  /* POSTFail */
  2061. +            Key.Unknown, /* ErrorUndefined */
  2062. +            Key.A, /* a or A */
  2063. +            Key.B, /* b or B */
  2064. +            Key.C, /* c or C */
  2065. +            Key.D, /* d or D */
  2066. +            Key.E, /* e or E */
  2067. +            Key.F, /* f or F */
  2068. +            Key.G, /* g or G */
  2069. +            Key.H, /* h or H */
  2070. +            Key.I, /* i or I */
  2071. +            Key.J, /* j or J */
  2072. +            Key.K, /* k or K */
  2073. +            Key.L, /* l or L */
  2074. +            Key.M, /* m or M */
  2075. +            Key.N, /* n or N */
  2076. +            Key.O, /* o or O */
  2077. +            Key.P, /* p or P */
  2078. +            Key.Q, /* q or Q */
  2079. +            Key.R, /* r or R */
  2080. +            Key.S, /* s or S */
  2081. +            Key.T, /* t or T */
  2082. +            Key.U, /* u or U */
  2083. +            Key.V, /* v or V */
  2084. +            Key.W, /* w or W */
  2085. +            Key.X, /* x or X */
  2086. +            Key.Y, /* y or Y */
  2087. +            Key.Z, /* z or Z */
  2088. +            Key.Number1, /* 1 or ! */
  2089. +            Key.Number2, /* 2 or @ */
  2090. +            Key.Number3, /* 3 or # */
  2091. +            Key.Number4, /* 4 or $ */
  2092. +            Key.Number5, /* 5 or % */
  2093. +            Key.Number6, /* 6 or ^ */
  2094. +            Key.Number7, /* 7 or & */
  2095. +            Key.Number8, /* 8 or * */
  2096. +            Key.Number9, /* 9 or ( */
  2097. +            Key.Number0, /* 0 or ) */
  2098. +            Key.Enter, /* Return (Enter) */
  2099. +            Key.Escape, /* Escape */
  2100. +            Key.BackSpace, /* Delete (Backspace) */
  2101. +            Key.Tab, /* Tab */
  2102. +            Key.Space, /* Spacebar */
  2103. +            Key.Minus, /* - or _ */
  2104. +            Key.Plus, /* = or + */
  2105. +            Key.BracketLeft, /* [ or { */
  2106. +            Key.BracketRight, /* ] or } */
  2107. +            Key.BackSlash, /* \ or | */
  2108. +            Key.Minus, /* Non-US # or _ */
  2109. +            Key.Semicolon, /* ; or : */
  2110. +            Key.Quote, /* ' or " */
  2111. +            Key.Tilde, /* Grave Accent and Tilde */
  2112. +            Key.Comma, /* , or < */
  2113. +            Key.Period, /* . or > */
  2114. +            Key.Slash, /* / or ? */
  2115. +            Key.CapsLock, /* Caps Lock */
  2116. +            Key.F1, /* F1 */
  2117. +            Key.F2, /* F2 */
  2118. +            Key.F3, /* F3 */
  2119. +            Key.F4, /* F4 */
  2120. +            Key.F5, /* F5 */
  2121. +            Key.F6, /* F6 */
  2122. +            Key.F7, /* F7 */
  2123. +            Key.F8, /* F8 */
  2124. +            Key.F9, /* F9 */
  2125. +            Key.F10, /* F10 */
  2126. +            Key.F11, /* F11 */
  2127. +            Key.F12, /* F12 */
  2128. +            Key.PrintScreen, /* Print Screen */
  2129. +            Key.ScrollLock, /* Scroll Lock */
  2130. +            Key.Pause, /* Pause */
  2131. +            Key.Insert, /* Insert */
  2132. +            Key.Home, /* Home */
  2133. +            Key.PageUp, /* Page Up */
  2134. +            Key.Delete, /* Delete Forward */
  2135. +            Key.End, /* End */
  2136. +            Key.PageDown, /* Page Down */
  2137. +            Key.Right, /* Right Arrow */
  2138. +            Key.Left, /* Left Arrow */
  2139. +            Key.Down, /* Down Arrow */
  2140. +            Key.Up, /* Up Arrow */
  2141. +            Key.NumLock, /* Keypad NumLock or Clear */
  2142. +            Key.KeypadDivide, /* Keypad / */
  2143. +            Key.KeypadMultiply, /* Keypad * */
  2144. +            Key.KeypadMinus, /* Keypad - */
  2145. +            Key.KeypadPlus, /* Keypad + */
  2146. +            Key.KeypadEnter, /* Keypad Enter */
  2147. +            Key.Keypad1, /* Keypad 1 or End */
  2148. +            Key.Keypad2, /* Keypad 2 or Down Arrow */
  2149. +            Key.Keypad3, /* Keypad 3 or Page Down */
  2150. +            Key.Keypad4, /* Keypad 4 or Left Arrow */
  2151. +            Key.Keypad5, /* Keypad 5 */
  2152. +            Key.Keypad6, /* Keypad 6 or Right Arrow */
  2153. +            Key.Keypad7, /* Keypad 7 or Home */
  2154. +            Key.Keypad8, /* Keypad 8 or Up Arrow */
  2155. +            Key.Keypad9, /* Keypad 9 or Page Up */
  2156. +            Key.Keypad0, /* Keypad 0 or Insert */
  2157. +            Key.KeypadDecimal, /* Keypad . or Delete */
  2158. +            Key.BackSlash, /* Non-US \ or | */
  2159. +            Key.Unknown, /* Application */
  2160. +            Key.Unknown, /* Power */
  2161. +            Key.Unknown, /* Keypad = */
  2162. +            Key.F13, /* F13 */
  2163. +            Key.F14, /* F14 */
  2164. +            Key.F15, /* F15 */
  2165. +            Key.F16, /* F16 */
  2166. +            Key.F17, /* F17 */
  2167. +            Key.F18, /* F18 */
  2168. +            Key.F19, /* F19 */
  2169. +            Key.F20, /* F20 */
  2170. +            Key.F21, /* F21 */
  2171. +            Key.F22, /* F22 */
  2172. +            Key.F23, /* F23 */
  2173. +            Key.F24, /* F24 */
  2174. +            Key.Unknown, /* Execute */
  2175. +            Key.Unknown, /* Help */
  2176. +            Key.Menu, /* Menu */
  2177. +            Key.Unknown, /* Select */
  2178. +            Key.Unknown, /* Stop */
  2179. +            Key.Unknown, /* Again */
  2180. +            Key.Unknown, /* Undo */
  2181. +            Key.Unknown, /* Cut */
  2182. +            Key.Unknown, /* Copy */
  2183. +            Key.Unknown, /* Paste */
  2184. +            Key.Unknown, /* Find */
  2185. +            Key.Unknown, /* Mute */
  2186. +            Key.Unknown, /* Volume Up */
  2187. +            Key.Unknown, /* Volume Down */
  2188. +            Key.CapsLock, /* Locking Caps Lock */
  2189. +            Key.NumLock , /* Locking Num Lock */
  2190. +            Key.ScrollLock, /* Locking Scroll Lock */
  2191. +            Key.KeypadDecimal, /* Keypad Comma */
  2192. +            Key.Unknown, /* Keypad Equal Sign for AS/400 */
  2193. +            Key.Unknown, /* International1 */
  2194. +            Key.Unknown, /* International2 */
  2195. +            Key.Unknown, /* International3 */
  2196. +            Key.Unknown, /* International4 */
  2197. +            Key.Unknown, /* International5 */
  2198. +            Key.Unknown, /* International6 */
  2199. +            Key.Unknown, /* International7 */
  2200. +            Key.Unknown, /* International8 */
  2201. +            Key.Unknown, /* International9 */
  2202. +            Key.Unknown, /* LANG1 */
  2203. +            Key.Unknown, /* LANG2 */
  2204. +            Key.Unknown, /* LANG3 */
  2205. +            Key.Unknown, /* LANG4 */
  2206. +            Key.Unknown, /* LANG5 */
  2207. +            Key.Unknown, /* LANG6 */
  2208. +            Key.Unknown, /* LANG7 */
  2209. +            Key.Unknown, /* LANG8 */
  2210. +            Key.Unknown, /* LANG9 */
  2211. +            Key.Unknown, /* AlternateErase */
  2212. +            Key.Unknown, /* SysReq/Attention */
  2213. +            Key.Unknown, /* Cancel */
  2214. +            Key.Unknown, /* Clear */
  2215. +            Key.Unknown, /* Prior */
  2216. +            Key.Enter, /* Return */
  2217. +            Key.Unknown, /* Separator */
  2218. +            Key.Unknown, /* Out */
  2219. +            Key.Unknown, /* Oper */
  2220. +            Key.Unknown, /* Clear/Again */
  2221. +            Key.Unknown, /* CrSel/Props */
  2222. +            Key.Unknown, /* ExSel */
  2223. +            /* 0xA5-0xDF Reserved */
  2224. +            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2225. +            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2226. +            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2227. +            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2228. +            Key.LControl, /* Left Control */
  2229. +            Key.LShift, /* Left Shift */
  2230. +            Key.LAlt, /* Left Alt */
  2231. +            Key.LWin, /* Left GUI */
  2232. +            Key.RControl, /* Right Control */
  2233. +            Key.RShift, /* Right Shift */
  2234. +            Key.RAlt, /* Right Alt */
  2235. +            Key.RWin, /* Right GUI */
  2236. +            /* 0xE8-0xFFFF Reserved */
  2237. +        };
  2238. +
  2239. +        #endregion
  2240. +    }
  2241. +}
  2242. +
  2243. Index: Source/OpenTK/Platform/Windows/WMInput.cs
  2244. ===================================================================
  2245. --- Source/OpenTK/Platform/Windows/WMInput.cs   (revision 3125)
  2246. +++ Source/OpenTK/Platform/Windows/WMInput.cs   (working copy)
  2247. @@ -70,14 +70,12 @@
  2248.  
  2249.          void UpdateKeyboard()
  2250.          {
  2251. -            for (int i = 0; i < 256; i++)
  2252. +            for (byte i = 0; i < byte.MaxValue; i++)
  2253.              {
  2254. -                VirtualKeys key = (VirtualKeys)i;
  2255. -                bool pressed = (Functions.GetAsyncKeyState(key) >> 8) != 0;
  2256. -                if (KeyMap.ContainsKey(key))
  2257. -                {
  2258. -                        keyboard[KeyMap[key]] = pressed;
  2259. -                }
  2260. +                bool pressed = (Functions.GetAsyncKeyState((VirtualKeys)i) >> 8) != 0;
  2261. +                Key key;
  2262. +                KeyMap.TryGetValue((VirtualKeys)i,out key);
  2263. +                keyboard.SetKeyState(key, i, pressed);
  2264.              }
  2265.          }
  2266.  
  2267. Index: Source/OpenTK/Platform/Windows/WinGLNative.cs
  2268. ===================================================================
  2269. --- Source/OpenTK/Platform/Windows/WinGLNative.cs   (revision 3125)
  2270. +++ Source/OpenTK/Platform/Windows/WinGLNative.cs   (working copy)
  2271. @@ -89,7 +89,13 @@
  2272.          IList<KeyboardDevice> keyboards = new List<KeyboardDevice>(1);
  2273.          IList<MouseDevice> mice = new List<MouseDevice>(1);
  2274.          const long ExtendedBit = 1 << 24;           // Used to distinguish left and right control, alt and enter keys.
  2275. -        static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0);         // Used to distinguish left and right shift keys.
  2276. +        
  2277. +        public static readonly uint ShiftLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LSHIFT, 0);
  2278. +        public static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0);
  2279. +        public static readonly uint ControlLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LCONTROL, 0);
  2280. +        public static readonly uint ControlRightScanCode = Functions.MapVirtualKey(VirtualKeys.RCONTROL, 0);
  2281. +        public static readonly uint AltLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LMENU, 0);
  2282. +        public static readonly uint AltRightScanCode = Functions.MapVirtualKey(VirtualKeys.RMENU, 0);
  2283.  
  2284.          KeyPressEventArgs key_press = new KeyPressEventArgs((char)0);
  2285.  
  2286. @@ -369,6 +375,8 @@
  2287.                      // In this case, both keys will be reported as pressed.
  2288.  
  2289.                      bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
  2290. +                    uint scancode = (uint)((lParam.ToInt64() >> 16) & 0xFF);
  2291. +                    Key key = Key.Unknown;
  2292.                      switch ((VirtualKeys)wParam)
  2293.                      {
  2294.                          case VirtualKeys.SHIFT:
  2295. @@ -382,56 +390,51 @@
  2296.                              // Otherwise, the state of one key might be stuck to pressed.
  2297.                              if (ShiftRightScanCode != 0 && pressed)
  2298.                              {
  2299. -                                unchecked
  2300. -                                {
  2301. -                                    if (((lParam.ToInt64() >> 16) & 0xFF) == ShiftRightScanCode)
  2302. -                                        keyboard[Input.Key.ShiftRight] = pressed;
  2303. -                                    else
  2304. -                                        keyboard[Input.Key.ShiftLeft] = pressed;
  2305. -                                }
  2306. +                                if (scancode == ShiftRightScanCode)
  2307. +                                    key = Input.Key.ShiftRight;
  2308. +                                else
  2309. +                                    key = Input.Key.ShiftLeft;
  2310.                              }
  2311.                              else
  2312.                              {
  2313.                                  // Windows 9x and NT4.0 or key release event.
  2314. -                                keyboard[Input.Key.ShiftLeft] = keyboard[Input.Key.ShiftRight] = pressed;
  2315. +                                keyboard.SetKey(Input.Key.ShiftLeft, ShiftLeftScanCode, pressed);
  2316. +                                keyboard.SetKey(Input.Key.ShiftRight, ShiftRightScanCode, pressed);
  2317.                              }
  2318. -                            return IntPtr.Zero;
  2319. +                            break;
  2320.  
  2321.                          case VirtualKeys.CONTROL:
  2322.                              if (extended)
  2323. -                                keyboard[Input.Key.ControlRight] = pressed;
  2324. +                                key = Input.Key.ControlRight;
  2325.                              else
  2326. -                                keyboard[Input.Key.ControlLeft] = pressed;
  2327. -                            return IntPtr.Zero;
  2328. +                                key = Input.Key.ControlLeft;
  2329. +                            break;
  2330.  
  2331.                          case VirtualKeys.MENU:
  2332.                              if (extended)
  2333. -                                keyboard[Input.Key.AltRight] = pressed;
  2334. +                                key = Input.Key.AltRight;
  2335.                              else
  2336. -                                keyboard[Input.Key.AltLeft] = pressed;
  2337. -                            return IntPtr.Zero;
  2338. +                                key = Input.Key.AltLeft;
  2339. +                            break;
  2340.  
  2341.                          case VirtualKeys.RETURN:
  2342.                              if (extended)
  2343. -                                keyboard[Key.KeypadEnter] = pressed;
  2344. +                                key = Key.KeypadEnter;
  2345.                              else
  2346. -                                keyboard[Key.Enter] = pressed;
  2347. -                            return IntPtr.Zero;
  2348. +                                key = Key.Enter;
  2349. +                            break;
  2350.  
  2351.                          default:
  2352.                              if (!KeyMap.ContainsKey((VirtualKeys)wParam))
  2353. -                            {
  2354.                                  Debug.Print("Virtual key {0} ({1}) not mapped.", (VirtualKeys)wParam, (long)lParam);
  2355. -                                break;
  2356. -                            }
  2357.                              else
  2358. -                            {
  2359. -                                keyboard[KeyMap[(VirtualKeys)wParam]] = pressed;
  2360. -                            }
  2361. -                            return IntPtr.Zero;
  2362. +                                key = KeyMap[(VirtualKeys)wParam];
  2363. +                            break;
  2364.                      }
  2365. -                    break;
  2366.  
  2367. +                    keyboard.SetKey(key, scancode, pressed);
  2368. +                    return IntPtr.Zero;
  2369. +
  2370.                  case WindowMessage.SYSCHAR:
  2371.                      return IntPtr.Zero;
  2372.  
  2373. Index: Source/OpenTK/Platform/Windows/WinRawKeyboard.cs
  2374. ===================================================================
  2375. --- Source/OpenTK/Platform/Windows/WinRawKeyboard.cs    (revision 3125)
  2376. +++ Source/OpenTK/Platform/Windows/WinRawKeyboard.cs    (working copy)
  2377. @@ -171,31 +171,30 @@
  2378.              switch (rin.Data.Keyboard.VKey)
  2379.              {
  2380.                  case VirtualKeys.SHIFT:
  2381. -                    keyboard[Input.Key.ShiftLeft] = keyboard[Input.Key.ShiftRight] = pressed;
  2382. +                    keyboard.SetKeyState(Key.ShiftLeft, (byte)WinGLNative.ShiftLeftScanCode, pressed);
  2383. +                    keyboard.SetKeyState(Key.ShiftRight, (byte)WinGLNative.ShiftRightScanCode, pressed);
  2384.                      processed = true;
  2385.                      break;
  2386.  
  2387.                  case VirtualKeys.CONTROL:
  2388. -                    keyboard[Input.Key.ControlLeft] = keyboard[Input.Key.ControlRight] = pressed;
  2389. +                    keyboard.SetKeyState(Key.ControlLeft, (byte)WinGLNative.ControlLeftScanCode, pressed);
  2390. +                    keyboard.SetKeyState(Key.ControlRight, (byte)WinGLNative.ControlRightScanCode, pressed);
  2391.                      processed = true;
  2392.                      break;
  2393.  
  2394.                  case VirtualKeys.MENU:
  2395. -                    keyboard[Input.Key.AltLeft] = keyboard[Input.Key.AltRight] = pressed;
  2396. +                    keyboard.SetKeyState(Key.AltLeft, (byte)WinGLNative.AltLeftScanCode, pressed);
  2397. +                    keyboard.SetKeyState(Key.AltRight, (byte)WinGLNative.AltRightScanCode, pressed);
  2398.                      processed = true;
  2399.                      break;
  2400.  
  2401.                  default:
  2402. -                    if (!KeyMap.ContainsKey(rin.Data.Keyboard.VKey))
  2403. -                    {
  2404. -                        Debug.Print("Virtual key {0} ({1}) not mapped.",
  2405. -                                    rin.Data.Keyboard.VKey, (int)rin.Data.Keyboard.VKey);
  2406. -                    }
  2407. -                    else
  2408. -                    {
  2409. -                        keyboard[KeyMap[rin.Data.Keyboard.VKey]] = pressed;
  2410. -                        processed = true;
  2411. -                    }
  2412. +                    Key key;
  2413. +                    KeyMap.TryGetValue(rin.Data.Keyboard.VKey, out key);
  2414. +                    if (key == Key.Unknown)
  2415. +                        Debug.Print("Virtual key {0} ({1}) not mapped.", rin.Data.Keyboard.VKey, (int)rin.Data.Keyboard.VKey);
  2416. +                    keyboard.SetKeyState(key, BitConverter.GetBytes(rin.Data.Keyboard.MakeCode)[0], pressed);
  2417. +                    processed = true;
  2418.                      break;
  2419.              }
  2420.  
  2421. Index: Source/OpenTK/Platform/X11/X11Input.cs
  2422. ===================================================================
  2423. --- Source/OpenTK/Platform/X11/X11Input.cs  (revision 3125)
  2424. +++ Source/OpenTK/Platform/X11/X11Input.cs  (working copy)
  2425. @@ -157,20 +157,22 @@
  2426.                  case XEventName.KeyPress:
  2427.                  case XEventName.KeyRelease:
  2428.                      bool pressed = e.type == XEventName.KeyPress;
  2429. +                    XKey keysym = (XKey)API.LookupKeysym(ref e.KeyEvent, 0);
  2430. +                    XKey keysym2 = (XKey)API.LookupKeysym(ref e.KeyEvent, 1);
  2431. +                    Key key = Key.Unknown;
  2432.  
  2433. -                    IntPtr keysym = API.LookupKeysym(ref e.KeyEvent, 0);
  2434. -                    IntPtr keysym2 = API.LookupKeysym(ref e.KeyEvent, 1);
  2435. -
  2436. -                    if (keymap.ContainsKey((XKey)keysym))
  2437. -                        keyboard[keymap[(XKey)keysym]] = pressed;
  2438. -                    else if (keymap.ContainsKey((XKey)keysym2))
  2439. -                        keyboard[keymap[(XKey)keysym2]] = pressed;
  2440. +                    if (keymap.ContainsKey(keysym))
  2441. +                        key = keymap[keysym];
  2442. +                    else if (keymap.ContainsKey(keysym2))
  2443. +                        key = keymap[keysym2];
  2444.                      else
  2445.                          Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.KeyEvent.keycode, (XKey)keysym, (XKey)keysym2);
  2446. +
  2447. +                    keyboard.SetKey(key, (uint)e.KeyEvent.keycode, pressed);
  2448.                      break;
  2449.  
  2450.                  case XEventName.ButtonPress:
  2451. -                    if      (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = true;
  2452. +                    if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = true;
  2453.                      else if (e.ButtonEvent.button == 2) mouse[OpenTK.Input.MouseButton.Middle] = true;
  2454.                      else if (e.ButtonEvent.button == 3) mouse[OpenTK.Input.MouseButton.Right] = true;
  2455.                      else if (e.ButtonEvent.button == 4) mouse.Wheel++;
  2456. @@ -190,7 +192,7 @@
  2457.                      break;
  2458.  
  2459.                  case XEventName.ButtonRelease:
  2460. -                    if      (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = false;
  2461. +                    if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = false;
  2462.                      else if (e.ButtonEvent.button == 2) mouse[OpenTK.Input.MouseButton.Middle] = false;
  2463.                      else if (e.ButtonEvent.button == 3) mouse[OpenTK.Input.MouseButton.Right] = false;
  2464.                      else if (e.ButtonEvent.button == 6) mouse[OpenTK.Input.MouseButton.Button1] = false;