Index: Source/OpenTK/Platform/Windows/WinGLNative.cs =================================================================== --- Source/OpenTK/Platform/Windows/WinGLNative.cs (revision 3125) +++ Source/OpenTK/Platform/Windows/WinGLNative.cs (working copy) @@ -89,7 +89,13 @@ IList keyboards = new List(1); IList mice = new List(1); const long ExtendedBit = 1 << 24; // Used to distinguish left and right control, alt and enter keys. - static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0); // Used to distinguish left and right shift keys. + + public static readonly uint ShiftLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LSHIFT, 0); + public static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0); + public static readonly uint ControlLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LCONTROL, 0); + public static readonly uint ControlRightScanCode = Functions.MapVirtualKey(VirtualKeys.RCONTROL, 0); + public static readonly uint AltLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LMENU, 0); + public static readonly uint AltRightScanCode = Functions.MapVirtualKey(VirtualKeys.RMENU, 0); KeyPressEventArgs key_press = new KeyPressEventArgs((char)0); @@ -369,6 +375,8 @@ // In this case, both keys will be reported as pressed. bool extended = (lParam.ToInt64() & ExtendedBit) != 0; + uint scancode = (uint)((lParam.ToInt64() >> 16) & 0xFF); + Key key = Key.Unknown; switch ((VirtualKeys)wParam) { case VirtualKeys.SHIFT: @@ -382,56 +390,51 @@ // Otherwise, the state of one key might be stuck to pressed. if (ShiftRightScanCode != 0 && pressed) { - unchecked - { - if (((lParam.ToInt64() >> 16) & 0xFF) == ShiftRightScanCode) - keyboard[Input.Key.ShiftRight] = pressed; - else - keyboard[Input.Key.ShiftLeft] = pressed; - } + if (scancode == ShiftRightScanCode) + key = Input.Key.ShiftRight; + else + key = Input.Key.ShiftLeft; } else { // Windows 9x and NT4.0 or key release event. - keyboard[Input.Key.ShiftLeft] = keyboard[Input.Key.ShiftRight] = pressed; + keyboard.SetKey(Input.Key.ShiftLeft, ShiftLeftScanCode, pressed); + keyboard.SetKey(Input.Key.ShiftRight, ShiftRightScanCode, pressed); } - return IntPtr.Zero; + break; case VirtualKeys.CONTROL: if (extended) - keyboard[Input.Key.ControlRight] = pressed; + key = Input.Key.ControlRight; else - keyboard[Input.Key.ControlLeft] = pressed; - return IntPtr.Zero; + key = Input.Key.ControlLeft; + break; case VirtualKeys.MENU: if (extended) - keyboard[Input.Key.AltRight] = pressed; + key = Input.Key.AltRight; else - keyboard[Input.Key.AltLeft] = pressed; - return IntPtr.Zero; + key = Input.Key.AltLeft; + break; case VirtualKeys.RETURN: if (extended) - keyboard[Key.KeypadEnter] = pressed; + key = Key.KeypadEnter; else - keyboard[Key.Enter] = pressed; - return IntPtr.Zero; + key = Key.Enter; + break; default: if (!KeyMap.ContainsKey((VirtualKeys)wParam)) - { Debug.Print("Virtual key {0} ({1}) not mapped.", (VirtualKeys)wParam, (long)lParam); - break; - } else - { - keyboard[KeyMap[(VirtualKeys)wParam]] = pressed; - } - return IntPtr.Zero; + key = KeyMap[(VirtualKeys)wParam]; + break; } - break; + keyboard.SetKey(key, scancode, pressed); + return IntPtr.Zero; + case WindowMessage.SYSCHAR: return IntPtr.Zero; Index: Source/OpenTK/Platform/Windows/WMInput.cs =================================================================== --- Source/OpenTK/Platform/Windows/WMInput.cs (revision 3125) +++ Source/OpenTK/Platform/Windows/WMInput.cs (working copy) @@ -70,14 +70,12 @@ void UpdateKeyboard() { - for (int i = 0; i < 256; i++) + for (byte i = 0; i < byte.MaxValue; i++) { - VirtualKeys key = (VirtualKeys)i; - bool pressed = (Functions.GetAsyncKeyState(key) >> 8) != 0; - if (KeyMap.ContainsKey(key)) - { - keyboard[KeyMap[key]] = pressed; - } + bool pressed = (Functions.GetAsyncKeyState((VirtualKeys)i) >> 8) != 0; + Key key; + KeyMap.TryGetValue((VirtualKeys)i,out key); + keyboard.SetKeyState(key, i, pressed); } } Index: Source/OpenTK/Platform/Windows/WinRawKeyboard.cs =================================================================== --- Source/OpenTK/Platform/Windows/WinRawKeyboard.cs (revision 3125) +++ Source/OpenTK/Platform/Windows/WinRawKeyboard.cs (working copy) @@ -171,31 +171,30 @@ switch (rin.Data.Keyboard.VKey) { case VirtualKeys.SHIFT: - keyboard[Input.Key.ShiftLeft] = keyboard[Input.Key.ShiftRight] = pressed; + keyboard.SetKeyState(Key.ShiftLeft, (byte)WinGLNative.ShiftLeftScanCode, pressed); + keyboard.SetKeyState(Key.ShiftRight, (byte)WinGLNative.ShiftRightScanCode, pressed); processed = true; break; case VirtualKeys.CONTROL: - keyboard[Input.Key.ControlLeft] = keyboard[Input.Key.ControlRight] = pressed; + keyboard.SetKeyState(Key.ControlLeft, (byte)WinGLNative.ControlLeftScanCode, pressed); + keyboard.SetKeyState(Key.ControlRight, (byte)WinGLNative.ControlRightScanCode, pressed); processed = true; break; case VirtualKeys.MENU: - keyboard[Input.Key.AltLeft] = keyboard[Input.Key.AltRight] = pressed; + keyboard.SetKeyState(Key.AltLeft, (byte)WinGLNative.AltLeftScanCode, pressed); + keyboard.SetKeyState(Key.AltRight, (byte)WinGLNative.AltRightScanCode, pressed); processed = true; break; default: - if (!KeyMap.ContainsKey(rin.Data.Keyboard.VKey)) - { - Debug.Print("Virtual key {0} ({1}) not mapped.", - rin.Data.Keyboard.VKey, (int)rin.Data.Keyboard.VKey); - } - else - { - keyboard[KeyMap[rin.Data.Keyboard.VKey]] = pressed; - processed = true; - } + Key key; + KeyMap.TryGetValue(rin.Data.Keyboard.VKey, out key); + if (key == Key.Unknown) + Debug.Print("Virtual key {0} ({1}) not mapped.", rin.Data.Keyboard.VKey, (int)rin.Data.Keyboard.VKey); + keyboard.SetKeyState(key, BitConverter.GetBytes(rin.Data.Keyboard.MakeCode)[0], pressed); + processed = true; break; } Index: Source/OpenTK/Platform/MacOS/HIDInput.cs =================================================================== --- Source/OpenTK/Platform/MacOS/HIDInput.cs (revision 3125) +++ Source/OpenTK/Platform/MacOS/HIDInput.cs (working copy) @@ -250,18 +250,13 @@ HIDPage page = NativeMethods.IOHIDElementGetUsagePage(elem); int usage = NativeMethods.IOHIDElementGetUsage(elem); - switch (page) + switch (page) { case HIDPage.GenericDesktop: case HIDPage.KeyboardOrKeypad: - int raw = (int)usage; - if (raw >= RawKeyMap.Length || raw < 0) - { - Debug.Print("[Warning] Key {0} not mapped.", raw); - return state; - } - Key key = RawKeyMap[raw]; - state[key] = v_int != 0; + if (usage >= RawKeyMap.Length || usage < 0) + Debug.Print("[Warning] Key {0} not mapped.", usage); + state.SetKeyState(RawKeyMap[usage], (byte)usage, v_int != 0); break; } Index: Source/OpenTK/Platform/MacOS/CarbonGLNative.cs =================================================================== --- Source/OpenTK/Platform/MacOS/CarbonGLNative.cs (revision 3125) +++ Source/OpenTK/Platform/MacOS/CarbonGLNative.cs (working copy) @@ -368,6 +368,7 @@ break; } + OpenTK.Input.Key key; switch (evt.KeyboardEventKind) { case KeyboardEventKind.RawKeyRepeat: @@ -376,25 +377,15 @@ break; case KeyboardEventKind.RawKeyDown: - { - OpenTK.Input.Key key; - if (Keymap.TryGetValue(code, out key)) - { - InputDriver.Keyboard[0][key] = true; - OnKeyPress(mKeyPressArgs); - } + Keymap.TryGetValue(code, out key); + InputDriver.Keyboard[0].SetKey(key, (uint)code, true); + OnKeyPress(mKeyPressArgs); return OSStatus.NoError; - } case KeyboardEventKind.RawKeyUp: - { - OpenTK.Input.Key key; - if (Keymap.TryGetValue(code, out key)) - { - InputDriver.Keyboard[0][key] = false; - } + Keymap.TryGetValue(code, out key); + InputDriver.Keyboard[0].SetKey(key, (uint)code, false); return OSStatus.NoError; - } case KeyboardEventKind.RawKeyModifiersChanged: ProcessModifierKey(inEvent); @@ -614,21 +605,21 @@ Debug.Print("Modifiers Changed: {0}", modifiers); Input.KeyboardDevice keyboard = InputDriver.Keyboard[0]; - + if (keyboard[OpenTK.Input.Key.AltLeft] ^ option) - keyboard[OpenTK.Input.Key.AltLeft] = option; + keyboard.SetKey(OpenTK.Input.Key.AltLeft, (uint)MacOSKeyModifiers.Option, option); if (keyboard[OpenTK.Input.Key.ShiftLeft] ^ shift) - keyboard[OpenTK.Input.Key.ShiftLeft] = shift; + keyboard.SetKey(OpenTK.Input.Key.ShiftLeft, (uint)MacOSKeyModifiers.Shift, shift); if (keyboard[OpenTK.Input.Key.WinLeft] ^ command) - keyboard[OpenTK.Input.Key.WinLeft] = command; + keyboard.SetKey(OpenTK.Input.Key.WinLeft, (uint)MacOSKeyModifiers.Command, command); if (keyboard[OpenTK.Input.Key.ControlLeft] ^ control) - keyboard[OpenTK.Input.Key.ControlLeft] = control; + keyboard.SetKey(OpenTK.Input.Key.ControlLeft, (uint)MacOSKeyModifiers.Control, control); if (keyboard[OpenTK.Input.Key.CapsLock] ^ caps) - keyboard[OpenTK.Input.Key.CapsLock] = caps; + keyboard.SetKey(OpenTK.Input.Key.CapsLock, (uint)MacOSKeyModifiers.CapsLock, caps); } Index: Source/OpenTK/Platform/X11/X11Input.cs =================================================================== --- Source/OpenTK/Platform/X11/X11Input.cs (revision 3125) +++ Source/OpenTK/Platform/X11/X11Input.cs (working copy) @@ -157,20 +157,22 @@ case XEventName.KeyPress: case XEventName.KeyRelease: bool pressed = e.type == XEventName.KeyPress; + XKey keysym = (XKey)API.LookupKeysym(ref e.KeyEvent, 0); + XKey keysym2 = (XKey)API.LookupKeysym(ref e.KeyEvent, 1); + Key key = Key.Unknown; - IntPtr keysym = API.LookupKeysym(ref e.KeyEvent, 0); - IntPtr keysym2 = API.LookupKeysym(ref e.KeyEvent, 1); - - if (keymap.ContainsKey((XKey)keysym)) - keyboard[keymap[(XKey)keysym]] = pressed; - else if (keymap.ContainsKey((XKey)keysym2)) - keyboard[keymap[(XKey)keysym2]] = pressed; + if (keymap.ContainsKey(keysym)) + key = keymap[keysym]; + else if (keymap.ContainsKey(keysym2)) + key = keymap[keysym2]; else Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.KeyEvent.keycode, (XKey)keysym, (XKey)keysym2); + + keyboard.SetKey(key, (uint)e.KeyEvent.keycode, pressed); break; case XEventName.ButtonPress: - if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = true; + if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = true; else if (e.ButtonEvent.button == 2) mouse[OpenTK.Input.MouseButton.Middle] = true; else if (e.ButtonEvent.button == 3) mouse[OpenTK.Input.MouseButton.Right] = true; else if (e.ButtonEvent.button == 4) mouse.Wheel++; @@ -190,7 +192,7 @@ break; case XEventName.ButtonRelease: - if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = false; + if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = false; else if (e.ButtonEvent.button == 2) mouse[OpenTK.Input.MouseButton.Middle] = false; else if (e.ButtonEvent.button == 3) mouse[OpenTK.Input.MouseButton.Right] = false; else if (e.ButtonEvent.button == 6) mouse[OpenTK.Input.MouseButton.Button1] = false; Index: Source/OpenTK/Input/KeyboardDevice.cs =================================================================== --- Source/OpenTK/Input/KeyboardDevice.cs (revision 3125) +++ Source/OpenTK/Input/KeyboardDevice.cs (working copy) @@ -22,6 +22,7 @@ { //private IKeyboard keyboard; private bool[] keys = new bool[Enum.GetValues(typeof(Key)).Length]; + private bool[] scancodes = new bool[256]; private string description; private int numKeys, numFKeys, numLeds; private IntPtr devID; @@ -44,24 +45,16 @@ public bool this[Key key] { get { return keys[(int)key]; } - internal set - { - if (keys[(int)key] != value || KeyRepeat) - { - keys[(int)key] = value; + } - if (value && KeyDown != null) - { - args.Key = key; - KeyDown(this, args); - } - else if (!value && KeyUp != null) - { - args.Key = key; - KeyUp(this, args); - } - } - } + /// + /// Gets a value indicating the status of the specified Key. + /// + /// The scancode to check. + /// True if the scancode is pressed, false otherwise. + public bool this[uint scancode] + { + get { return scancodes[scancode]; } } /// @@ -197,12 +190,34 @@ internal void ClearKeys() { for (int i = 0; i < keys.Length; i++) - if (this[(Key)i]) // Make sure KeyUp events are *not* raised for keys that are up, even if key repeat is on. - this[(Key)i] = false; + keys[i] = false; + for (uint i = 0; i < scancodes.Length; i++) + scancodes[i] = false; } #endregion + internal void SetKey(Key key, uint scancode, bool state) + { + if (keys[(int)key] != state || KeyRepeat) + { + keys[(int)key] = scancodes[scancode] = state; + + if (state && KeyDown != null) + { + args.Key = key; + args.ScanCode = scancode; + KeyDown(this, args); + } + else if (!state && KeyUp != null) + { + args.Key = key; + args.ScanCode = scancode; + KeyUp(this, args); + } + } + } + #endregion } } \ No newline at end of file Index: Source/OpenTK/Input/KeyboardKeyEventArgs.cs =================================================================== --- Source/OpenTK/Input/KeyboardKeyEventArgs.cs (revision 3125) +++ Source/OpenTK/Input/KeyboardKeyEventArgs.cs (working copy) @@ -46,6 +46,7 @@ #region Fields Key key; + uint scancode; #endregion @@ -63,6 +64,7 @@ public KeyboardKeyEventArgs(KeyboardKeyEventArgs args) { Key = args.Key; + ScanCode = args.ScanCode; } #endregion @@ -77,6 +79,14 @@ get { return key; } internal set { key = value; } } + /// + /// Gets the scancode which generated this event. + /// + public uint ScanCode + { + get { return scancode; } + internal set { scancode = value; } + } #endregion } Index: Source/OpenTK/Input/KeyboardState.cs =================================================================== --- Source/OpenTK/Input/KeyboardState.cs (revision 3125) +++ Source/OpenTK/Input/KeyboardState.cs (working copy) @@ -43,6 +43,7 @@ const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize; // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh... unsafe fixed int Keys[NumInts]; + unsafe fixed int Codes[256]; bool is_connected; #endregion @@ -58,16 +59,20 @@ public bool this[Key key] { get { return IsKeyDown(key); } - internal set - { - if (value) - EnableBit((int)key); - else - DisableBit((int)key); - } } /// + /// Gets a indicating whether the specified + /// is pressed. + /// + /// The to check. + /// True if key is pressed; false otherwise. + public bool this[short code] + { + get { return IsKeyDown(code); } + } + + /// /// Gets a indicating whether this key is down. /// /// The to check. @@ -77,6 +82,15 @@ } /// + /// Gets a indicating whether this scan code is down. + /// + /// The scan code to check. + public bool IsKeyDown(short code) + { + return ReadBit(code,true); + } + + /// /// Gets a indicating whether this key is up. /// /// The to check. @@ -86,6 +100,15 @@ } /// + /// Gets a indicating whether this scan code is down. + /// + /// The scan code to check. + public bool IsKeyUp(short code) + { + return !ReadBit(code,true); + } + + /// /// Gets a indicating whether this keyboard /// is connected. /// @@ -187,48 +210,62 @@ #region Internal Members - internal bool ReadBit(int offset) + internal void SetKeyState(Key key, byte code, bool down) { - ValidateOffset(offset); + if (down) + { + EnableBit((int)key); + EnableBit(code,true); + } + else + { + DisableBit((int)key); + DisableBit(code, true); + } + } + internal bool ReadBit(int offset, bool ScanCode = false) + { + ValidateOffset(offset, ScanCode); + int int_offset = offset / 32; int bit_offset = offset % 32; unsafe { - fixed (int* k = Keys) - { - return (*(k + int_offset) & (1 << bit_offset)) != 0u; - } + if (ScanCode) + fixed (int* c = Codes) { return (*(c + int_offset) & (1 << bit_offset)) != 0u; } + else + fixed (int* k = Keys) { return (*(k + int_offset) & (1 << bit_offset)) != 0u; } } } - internal void EnableBit(int offset) + internal void EnableBit(int offset, bool ScanCode = false) { - ValidateOffset(offset); + ValidateOffset(offset, ScanCode); int int_offset = offset / 32; int bit_offset = offset % 32; unsafe { - fixed (int* k = Keys) - { - *(k + int_offset) |= 1 << bit_offset; - } + if (ScanCode) + fixed (int* c = Codes) { *(c + int_offset) |= 1 << bit_offset; } + else + fixed (int* k = Keys) { *(k + int_offset) |= 1 << bit_offset; } } } - internal void DisableBit(int offset) + internal void DisableBit(int offset, bool ScanCode = false) { - ValidateOffset(offset); + ValidateOffset(offset, ScanCode); int int_offset = offset / 32; int bit_offset = offset % 32; unsafe { - fixed (int* k = Keys) - { - *(k + int_offset) &= ~(1 << bit_offset); - } + if (ScanCode) + fixed (int* c = Codes) { *(c + int_offset) &= ~(1 << bit_offset); } + else + fixed (int* k = Keys) { *(k + int_offset) &= ~(1 << bit_offset); } } } @@ -242,6 +279,12 @@ for (int i = 0; i < NumInts; i++) *(k1 + i) |= *(k2 + i); } + int* c2 = other.Codes; + fixed (int* c1 = Codes) + { + for (int i = 0; i < short.MaxValue; i++) + *(c1 + i) |= *(c2 + i); + } } IsConnected |= other.IsConnected; } @@ -250,9 +293,9 @@ #region Private Members - static void ValidateOffset(int offset) + static void ValidateOffset(int offset, bool ScanCode) { - if (offset < 0 || offset >= NumInts * IntSize) + if (offset < 0 || offset >= (ScanCode ? 256 : NumInts * IntSize)) throw new ArgumentOutOfRangeException("offset"); }