Merge branch 'scancodes'

Conflicts:
	Source/OpenTK/OpenTK.csproj
	Source/OpenTK/Platform/Windows/WinFactory.cs
This commit is contained in:
Stefanos A 2013-10-11 01:05:55 +02:00
commit 73e3614338
7 changed files with 378 additions and 532 deletions

View file

@ -261,6 +261,8 @@ namespace OpenTK.Input
KeypadPlus = KeypadAdd,
/// <summary>The keypad decimal key.</summary>
KeypadDecimal,
/// <summary>The keypad period key (equivalent to KeypadDecimal).</summary>
KeypadPeriod = KeypadDecimal,
/// <summary>The keypad enter key.</summary>
KeypadEnter,
@ -343,6 +345,8 @@ namespace OpenTK.Input
// Symbols
/// <summary>The tilde key.</summary>
Tilde,
/// <summary>The grave key (equivaent to Tilde).</summary>
Grave = Tilde,
/// <summary>The minus key.</summary>
Minus,
//Equal,
@ -368,6 +372,8 @@ namespace OpenTK.Input
Slash,
/// <summary>The backslash key.</summary>
BackSlash,
/// <summary>The secondary backslash key.</summary>
NonUSBackSlash,
/// <summary>Indicates the last available keyboard key.</summary>
LastKey
}

View file

@ -332,9 +332,6 @@
<Compile Include="Platform\Windows\WinKeyMap.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\Windows\WMInput.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\Windows\WinGLNative.cs">
<SubType>Code</SubType>
</Compile>

View file

@ -1,209 +0,0 @@
#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
#if !MINIMAL
using System.Drawing;
#endif
using System.Threading;
using System.Text;
using OpenTK.Input;
namespace OpenTK.Platform.Windows
{
// Input driver for legacy (pre XP) Windows platforms.
// Supports a single mouse and keyboard through async input.
// Supports multiple joysticks through WinMM.
sealed class WMInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2/*, IGamePadDriver*/ //HACK uncomment and implement
{
#region Fields
readonly object MouseLock = new object();
readonly object KeyboardLock = new object();
readonly WinMMJoystick gamepad_driver = new WinMMJoystick();
readonly WinKeyMap KeyMap = new WinKeyMap();
KeyboardState keyboard = new KeyboardState();
MouseState mouse = new MouseState();
bool disposed;
#endregion
#region Constructor
public WMInput()
: base()
{
Debug.WriteLine("Using WMInput.");
}
#endregion
#region Private Members
void UpdateKeyboard()
{
for (byte i = 0; i < byte.MaxValue; i++)
{
bool pressed = (Functions.GetAsyncKeyState((VirtualKeys)i) >> 8) != 0;
Key key;
KeyMap.TryGetValue((VirtualKeys)i,out key);
keyboard.SetKeyState(key, i, pressed);
}
}
void UpdateMouse()
{
POINT p = new POINT();
Functions.GetCursorPos(ref p);
mouse.X = p.X;
mouse.Y = p.Y;
// Note: we cannot poll the mouse wheel
mouse[MouseButton.Left] = (Functions.GetAsyncKeyState(VirtualKeys.LBUTTON) >> 8) != 0;
mouse[MouseButton.Middle] = (Functions.GetAsyncKeyState(VirtualKeys.RBUTTON) >> 8) != 0;
mouse[MouseButton.Right] = (Functions.GetAsyncKeyState(VirtualKeys.MBUTTON) >> 8) != 0;
mouse[MouseButton.Button1] = (Functions.GetAsyncKeyState(VirtualKeys.XBUTTON1) >> 8) != 0;
mouse[MouseButton.Button2] = (Functions.GetAsyncKeyState(VirtualKeys.XBUTTON2) >> 8) != 0;
}
#endregion
#region IInputDriver2 Members
public IKeyboardDriver2 KeyboardDriver
{
get { return this; }
}
public IMouseDriver2 MouseDriver
{
get { return this; }
}
public IGamePadDriver GamePadDriver
{
get { return null; } //HACK return this when implemented.
}
#endregion
#region IMouseDriver2 Members
public MouseState GetState()
{
lock (MouseLock)
{
UpdateMouse();
return mouse;
}
}
public MouseState GetState(int index)
{
lock (MouseLock)
{
UpdateMouse();
if (index == 0)
return mouse;
else
return new MouseState();
}
}
public void SetPosition(double x, double y)
{
Functions.SetCursorPos((int)x, (int)y);
}
#endregion
#region IKeyboardDriver2 Members
KeyboardState IKeyboardDriver2.GetState()
{
lock (KeyboardLock)
{
UpdateKeyboard();
return keyboard;
}
}
KeyboardState IKeyboardDriver2.GetState(int index)
{
lock (KeyboardLock)
{
UpdateKeyboard();
if (index == 0)
return keyboard;
else
return new KeyboardState();
}
}
string IKeyboardDriver2.GetDeviceName(int index)
{
return "Default Windows Keyboard";
}
#endregion
#region IDisposable Members
void Dispose(bool manual)
{
if (!disposed)
{
if (manual)
{
// Todo: implement this
}
else
{
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~WMInput()
{
Dispose(false);
}
#endregion
}
}

View file

@ -43,6 +43,11 @@ namespace OpenTK.Platform.Windows
public WinFactory()
{
if (System.Environment.OSVersion.Version.Major <= 4)
{
throw new PlatformNotSupportedException("OpenTK requires Windows XP or higher");
}
if (System.Environment.OSVersion.Version.Major >= 6)
{
// Enable high-dpi support
@ -112,13 +117,7 @@ namespace OpenTK.Platform.Windows
{
if (inputDriver == null)
{
// If Windows version is NT5 or higher, we are able to use raw input.
if (System.Environment.OSVersion.Version.Major > 5 ||
(System.Environment.OSVersion.Version.Major == 5 &&
System.Environment.OSVersion.Version.Minor > 0))
inputDriver = new WinRawInput();
else
inputDriver = new WMInput();
inputDriver = new WinRawInput();
}
return inputDriver;
}

View file

@ -375,64 +375,16 @@ namespace OpenTK.Platform.Windows
// 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)
short scancode = (short)((lParam.ToInt64() >> 16) & 0xFF);
VirtualKeys vkey = (VirtualKeys)wParam;
bool is_valid;
Key key = KeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
if (is_valid)
{
case VirtualKeys.SHIFT:
// The behavior of this key is very strange. Unlike Control and Alt, there is no extended bit
// to distinguish between left and right keys. Moreover, pressing both keys and releasing one
// may result in both keys being held down (but not always).
// The only reliable way to solve this was reported by BlueMonkMN at the forums: we should
// check the scancodes. It looks like GLFW does the same thing, so it should be reliable.
// Note: we release both keys when either shift is released.
// Otherwise, the state of one key might be stuck to pressed.
if (ShiftRightScanCode != 0 && pressed)
{
if (scancode == ShiftRightScanCode)
key = Input.Key.ShiftRight;
else
key = Input.Key.ShiftLeft;
}
else
{
// Windows 9x and NT4.0 or key release event.
keyboard.SetKey(Input.Key.ShiftLeft, ShiftLeftScanCode, pressed);
keyboard.SetKey(Input.Key.ShiftRight, ShiftRightScanCode, pressed);
}
break;
case VirtualKeys.CONTROL:
if (extended)
key = Input.Key.ControlRight;
else
key = Input.Key.ControlLeft;
break;
case VirtualKeys.MENU:
if (extended)
key = Input.Key.AltRight;
else
key = Input.Key.AltLeft;
break;
case VirtualKeys.RETURN:
if (extended)
key = Key.KeypadEnter;
else
key = Key.Enter;
break;
default:
if (!KeyMap.ContainsKey((VirtualKeys)wParam))
Debug.Print("Virtual key {0} ({1}) not mapped.", (VirtualKeys)wParam, (long)lParam);
else
key = KeyMap[(VirtualKeys)wParam];
break;
keyboard.SetKey(key, (byte)scancode, pressed);
}
keyboard.SetKey(key, scancode, pressed);
return IntPtr.Zero;
case WindowMessage.SYSCHAR:

View file

@ -27,96 +27,214 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTK.Input;
namespace OpenTK.Platform.Windows
{
class WinKeyMap : Dictionary<VirtualKeys, Input.Key>
class WinKeyMap
{
/// <summary>
/// Initializes the map between VirtualKeys and OpenTK.Key
/// </summary>
readonly Dictionary<int, Key> ScanMap = new Dictionary<int, Key>();
public WinKeyMap()
{
this.Add(VirtualKeys.ESCAPE, Key.Escape);
// 0 - 15
Append(Key.Unknown);
Append(Key.Escape);
// Function keys
for (int i = 0; i < 24; i++)
for (int i = 0; i < 9; i++)
Append(Key.Number1 + i);
Append(Key.Number0);
Append(Key.Minus);
Append(Key.Plus);
Append(Key.BackSpace);
Append(Key.Tab);
// 16-31
Append(Key.Q);
Append(Key.W);
Append(Key.E);
Append(Key.R);
Append(Key.T);
Append(Key.Y);
Append(Key.U);
Append(Key.I);
Append(Key.O);
Append(Key.P);
Append(Key.BracketLeft);
Append(Key.BracketRight);
Append(Key.Enter);
Append(Key.ControlLeft);
Append(Key.A);
Append(Key.S);
// 32 - 47
Append(Key.D);
Append(Key.F);
Append(Key.G);
Append(Key.H);
Append(Key.J);
Append(Key.K);
Append(Key.L);
Append(Key.Semicolon);
Append(Key.Quote);
Append(Key.Grave);
Append(Key.ShiftLeft);
Append(Key.BackSlash);
Append(Key.Z);
Append(Key.X);
Append(Key.C);
Append(Key.V);
// 48 - 63
Append(Key.B);
Append(Key.N);
Append(Key.M);
Append(Key.Comma);
Append(Key.Period);
Append(Key.Slash);
Append(Key.ShiftRight);
Append(Key.PrintScreen);
Append(Key.AltLeft);
Append(Key.Space);
Append(Key.CapsLock);
Append(Key.F1);
Append(Key.F2);
Append(Key.F3);
Append(Key.F4);
Append(Key.F5);
// 64 - 79
Append(Key.F6);
Append(Key.F7);
Append(Key.F8);
Append(Key.F9);
Append(Key.F10);
Append(Key.NumLock);
Append(Key.ScrollLock);
Append(Key.Home);
Append(Key.Up);
Append(Key.PageUp);
Append(Key.KeypadMinus);
Append(Key.Left);
Append(Key.Keypad5);
Append(Key.Right);
Append(Key.KeypadPlus);
Append(Key.End);
// 80 - 95
Append(Key.Down);
Append(Key.PageDown);
Append(Key.Insert);
Append(Key.Delete);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.NonUSBackSlash);
Append(Key.F11);
Append(Key.F12);
Append(Key.Pause);
Append(Key.Unknown);
Append(Key.WinLeft);
Append(Key.WinRight);
Append(Key.Menu);
Append(Key.Unknown);
Append(Key.Unknown);
// 96 - 111
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.F13);
Append(Key.F14);
Append(Key.F15);
Append(Key.F16);
Append(Key.F17);
Append(Key.F18);
Append(Key.F19);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
// 112 - 127
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
Append(Key.Unknown);
}
void Append(Key key)
{
ScanMap.Add(ScanMap.Count, key);
}
public Key TranslateKey(short scancode, VirtualKeys vkey, bool extended0, bool extended1, out bool is_valid)
{
is_valid = true;
Key key;
ScanMap.TryGetValue(scancode, out key);
if (!extended0)
{
this.Add((VirtualKeys)((int)VirtualKeys.F1 + i), Key.F1 + i);
switch (key)
{
case Key.Insert: key = Key.Keypad0; break;
case Key.End: key = Key.Keypad1; break;
case Key.Down: key = Key.Keypad2; break;
case Key.PageDown: key = Key.Keypad3; break;
case Key.Left: key = Key.Keypad4; break;
case Key.Right: key = Key.Keypad6; break;
case Key.Home: key = Key.Keypad7; break;
case Key.Up: key = Key.Keypad8; break;
case Key.PageUp: key = Key.Keypad9; break;
case Key.PrintScreen: key = Key.KeypadMultiply; break;
case Key.Delete: key = Key.KeypadDecimal; break;
case Key.NumLock:
if (vkey == VirtualKeys.Last)
is_valid = false;
else if (vkey == VirtualKeys.PAUSE)
key = Key.Pause;
break;
}
}
else
{
switch (key)
{
case Key.Enter: key = Key.KeypadEnter; break;
case Key.AltLeft: key = Key.AltRight; break;
case Key.AltRight: key = Key.AltLeft; break;
case Key.ControlLeft: key = Key.ControlRight; break;
case Key.ControlRight: key = Key.ControlLeft; break;
case Key.ShiftLeft: is_valid = false; break;
}
}
// Number keys (0-9)
for (int i = 0; i <= 9; i++)
if (extended1)
{
this.Add((VirtualKeys)(0x30 + i), Key.Number0 + i);
switch (key)
{
case Key.ControlLeft: key = Key.Pause; break;
}
}
// Letters (A-Z)
for (int i = 0; i < 26; i++)
{
this.Add((VirtualKeys)(0x41 + i), Key.A + i);
}
this.Add(VirtualKeys.TAB, Key.Tab);
this.Add(VirtualKeys.CAPITAL, Key.CapsLock);
this.Add(VirtualKeys.LCONTROL, Key.ControlLeft);
this.Add(VirtualKeys.LSHIFT, Key.ShiftLeft);
this.Add(VirtualKeys.LWIN, Key.WinLeft);
this.Add(VirtualKeys.LMENU, Key.AltLeft);
this.Add(VirtualKeys.SPACE, Key.Space);
this.Add(VirtualKeys.RMENU, Key.AltRight);
this.Add(VirtualKeys.RWIN, Key.WinRight);
this.Add(VirtualKeys.APPS, Key.Menu);
this.Add(VirtualKeys.RCONTROL, Key.ControlRight);
this.Add(VirtualKeys.RSHIFT, Key.ShiftRight);
this.Add(VirtualKeys.RETURN, Key.Enter);
this.Add(VirtualKeys.BACK, Key.BackSpace);
this.Add(VirtualKeys.OEM_1, Key.Semicolon); // Varies by keyboard, ;: on Win2K/US
this.Add(VirtualKeys.OEM_2, Key.Slash); // Varies by keyboard, /? on Win2K/US
this.Add(VirtualKeys.OEM_3, Key.Tilde); // Varies by keyboard, `~ on Win2K/US
this.Add(VirtualKeys.OEM_4, Key.BracketLeft); // Varies by keyboard, [{ on Win2K/US
this.Add(VirtualKeys.OEM_5, Key.BackSlash); // Varies by keyboard, \| on Win2K/US
this.Add(VirtualKeys.OEM_6, Key.BracketRight); // Varies by keyboard, ]} on Win2K/US
this.Add(VirtualKeys.OEM_7, Key.Quote); // Varies by keyboard, '" on Win2K/US
this.Add(VirtualKeys.OEM_PLUS, Key.Plus); // Invariant: +
this.Add(VirtualKeys.OEM_COMMA, Key.Comma); // Invariant: ,
this.Add(VirtualKeys.OEM_MINUS, Key.Minus); // Invariant: -
this.Add(VirtualKeys.OEM_PERIOD, Key.Period); // Invariant: .
this.Add(VirtualKeys.HOME, Key.Home);
this.Add(VirtualKeys.END, Key.End);
this.Add(VirtualKeys.DELETE, Key.Delete);
this.Add(VirtualKeys.PRIOR, Key.PageUp);
this.Add(VirtualKeys.NEXT, Key.PageDown);
this.Add(VirtualKeys.PRINT, Key.PrintScreen);
this.Add(VirtualKeys.PAUSE, Key.Pause);
this.Add(VirtualKeys.NUMLOCK, Key.NumLock);
this.Add(VirtualKeys.SCROLL, Key.ScrollLock);
this.Add(VirtualKeys.SNAPSHOT, Key.PrintScreen);
this.Add(VirtualKeys.CLEAR, Key.Clear);
this.Add(VirtualKeys.INSERT, Key.Insert);
this.Add(VirtualKeys.SLEEP, Key.Sleep);
// Keypad
for (int i = 0; i <= 9; i++)
{
this.Add((VirtualKeys)((int)VirtualKeys.NUMPAD0 + i), Key.Keypad0 + i);
}
this.Add(VirtualKeys.DECIMAL, Key.KeypadDecimal);
this.Add(VirtualKeys.ADD, Key.KeypadAdd);
this.Add(VirtualKeys.SUBTRACT, Key.KeypadSubtract);
this.Add(VirtualKeys.DIVIDE, Key.KeypadDivide);
this.Add(VirtualKeys.MULTIPLY, Key.KeypadMultiply);
// Navigation
this.Add(VirtualKeys.UP, Key.Up);
this.Add(VirtualKeys.DOWN, Key.Down);
this.Add(VirtualKeys.LEFT, Key.Left);
this.Add(VirtualKeys.RIGHT, Key.Right);
return key;
}
}
}

View file

@ -157,6 +157,13 @@ namespace OpenTK.Platform.Windows
bool pressed =
rin.Data.Keyboard.Message == (int)WindowMessage.KEYDOWN ||
rin.Data.Keyboard.Message == (int)WindowMessage.SYSKEYDOWN;
var scancode = rin.Data.Keyboard.MakeCode;
var vkey = rin.Data.Keyboard.VKey;
bool extended0 = (int)(rin.Data.Keyboard.Flags & RawInputKeyboardDataFlags.E0) != 0;
bool extended1 = (int)(rin.Data.Keyboard.Flags & RawInputKeyboardDataFlags.E1) != 0;
bool is_valid = true;
ContextHandle handle = new ContextHandle(rin.Header.Device);
KeyboardState keyboard;
@ -175,36 +182,12 @@ namespace OpenTK.Platform.Windows
int keyboard_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0;
keyboard = keyboards[keyboard_handle];
// Generic control, shift, alt keys may be sent instead of left/right.
// It seems you have to explicitly register left/right events.
switch (rin.Data.Keyboard.VKey)
Key key = KeyMap.TranslateKey(scancode, vkey, extended0, extended1, out is_valid);
if (is_valid)
{
case VirtualKeys.SHIFT:
keyboard.SetKeyState(Key.ShiftLeft, (byte)WinGLNative.ShiftLeftScanCode, pressed);
keyboard.SetKeyState(Key.ShiftRight, (byte)WinGLNative.ShiftRightScanCode, pressed);
processed = true;
break;
case VirtualKeys.CONTROL:
keyboard.SetKeyState(Key.ControlLeft, (byte)WinGLNative.ControlLeftScanCode, pressed);
keyboard.SetKeyState(Key.ControlRight, (byte)WinGLNative.ControlRightScanCode, pressed);
processed = true;
break;
case VirtualKeys.MENU:
keyboard.SetKeyState(Key.AltLeft, (byte)WinGLNative.AltLeftScanCode, pressed);
keyboard.SetKeyState(Key.AltRight, (byte)WinGLNative.AltRightScanCode, pressed);
processed = true;
break;
default:
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;
keyboard.SetKeyState(key, (byte)scancode, pressed);
processed = true;
}
lock (UpdateLock)