Added KeyRepeat to IKeyboard.

Multiple keyboards correctly reported under Windows (Raw input driver).
Corrected some key maps in X11 and Windows Raw keyboards.
This commit is contained in:
the_fiddler 2007-09-21 20:03:53 +00:00
parent d6678f0587
commit 66b046a58c
4 changed files with 133 additions and 90 deletions

View file

@ -4,6 +4,8 @@
*/ */
#endregion #endregion
using System;
namespace OpenTK.Input namespace OpenTK.Input
{ {
public interface IKeyboard : IInputDevice public interface IKeyboard : IInputDevice
@ -12,18 +14,13 @@ namespace OpenTK.Input
int NumberOfKeys { get; } int NumberOfKeys { get; }
int NumberOfFunctionKeys { get; } int NumberOfFunctionKeys { get; }
int NumberOfLeds { get; } int NumberOfLeds { get; }
long DeviceID { get; } IntPtr DeviceID { get; }
bool KeyRepeat { get; set; }
event KeyDownEvent KeyDown; event KeyDownEvent KeyDown;
event KeyUpEvent KeyUp; event KeyUpEvent KeyUp;
} }
public delegate void KeyDownEvent(object sender, Key key); public delegate void KeyDownEvent(IKeyboard sender, Key key);
public delegate void KeyUpEvent(object sender, Key key); public delegate void KeyUpEvent(IKeyboard sender, Key key);
//public class KeyEventArgs : System.EventArgs
//{
// private Key key;
// public Key Key { get { return key; } }
//}
} }

View file

@ -21,7 +21,8 @@ namespace OpenTK.Input
private bool[] keys = new bool[(int)Key.MaxKeys]; private bool[] keys = new bool[(int)Key.MaxKeys];
private string description; private string description;
private int numKeys, numFKeys, numLeds; private int numKeys, numFKeys, numLeds;
private long devID; private IntPtr devID;
private bool repeat;
#region --- Constructors --- #region --- Constructors ---
@ -38,15 +39,18 @@ namespace OpenTK.Input
get { return keys[(int)k]; } get { return keys[(int)k]; }
internal set internal set
{ {
keys[(int)k] = value; if (keys[(int)k] != value || KeyRepeat)
{
keys[(int)k] = value;
if (value && KeyDown != null) if (value && KeyDown != null)
{ {
KeyDown(this, k); KeyDown(this, k);
} }
else if (!value && KeyUp != null) else if (!value && KeyUp != null)
{ {
KeyUp(this, k); KeyUp(this, k);
}
} }
} }
} }
@ -72,12 +76,29 @@ namespace OpenTK.Input
/// <summary> /// <summary>
/// Device dependent ID. /// Device dependent ID.
/// </summary> /// </summary>
public long DeviceID public IntPtr DeviceID
{ {
get { return devID; } get { return devID; }
internal set { devID = value; } internal set { devID = value; }
} }
#region public bool KeyRepeat
/// <summary>
/// Gets or sets a value indicating whether key repeat is turned on or off.
/// </summary>
/// <remarks>
/// Setting key repeat to on will generate multiple KeyDown events when a key is held pressed.
/// Setting key repeat to on will generate only one KeyDown/KeyUp event pair when a key is held pressed.
/// </remarks>
public bool KeyRepeat
{
get { return repeat; }
set { repeat = value; }
}
#endregion
/// <summary> /// <summary>
/// Occurs when a key is pressed. /// Occurs when a key is pressed.
/// </summary> /// </summary>
@ -171,11 +192,13 @@ namespace OpenTK.Input
Home, Home,
End, End,
CapsLock, CapsLock,
ScrollLock,
PrintScreen, PrintScreen,
Pause, Pause,
NumLock, NumLock,
// Special keys // Special keys
Clear, // Keypad5 with NumLock off.
Sleep, Sleep,
/*LogOff, /*LogOff,
Help, Help,
@ -205,9 +228,9 @@ namespace OpenTK.Input
PlayPause, PlayPause,
Stop, Stop,
VolumeUp, VolumeUp,
VOlumeDown, VolumeDown,
PreviousTrack, TrackPrevious,
NextTrack,*/ TrackNext,*/
// Keypad keys // Keypad keys
Keypad0, Keypad0,

View file

@ -21,7 +21,7 @@ namespace OpenTK.Platform.Windows
internal class WinRawKeyboard : IKeyboardDriver, IDisposable internal class WinRawKeyboard : IKeyboardDriver, IDisposable
{ {
private List<Keyboard> keyboards = new List<Keyboard>(); private List<Keyboard> keyboards = new List<Keyboard>();
private IntPtr windowHandle; private IntPtr window;
#region internal static Dictionary<VirtualKeys, Input.Key> KeyMap #region internal static Dictionary<VirtualKeys, Input.Key> KeyMap
@ -38,81 +38,85 @@ namespace OpenTK.Platform.Windows
{ {
try try
{ {
KeyMap.Add(VirtualKeys.ESCAPE, Input.Key.Escape); KeyMap.Add(VirtualKeys.ESCAPE, Key.Escape);
// Function keys // Function keys
for (int i = 0; i < 24; i++) for (int i = 0; i < 24; i++)
{ {
KeyMap.Add((VirtualKeys)((int)VirtualKeys.F1 + i), Input.Key.F1 + i); KeyMap.Add((VirtualKeys)((int)VirtualKeys.F1 + i), Key.F1 + i);
} }
// Number keys (0-9) // Number keys (0-9)
for (int i = 0; i <= 9; i++) for (int i = 0; i <= 9; i++)
{ {
KeyMap.Add((VirtualKeys)(0x30 + i), Input.Key.Number0 + i); KeyMap.Add((VirtualKeys)(0x30 + i), Key.Number0 + i);
} }
// Letters (A-Z) // Letters (A-Z)
for (int i = 0; i < 26; i++) for (int i = 0; i < 26; i++)
{ {
KeyMap.Add((VirtualKeys)(0x41 + i), Input.Key.A + i); KeyMap.Add((VirtualKeys)(0x41 + i), Key.A + i);
} }
KeyMap.Add(VirtualKeys.TAB, Input.Key.Tab); KeyMap.Add(VirtualKeys.TAB, Key.Tab);
KeyMap.Add(VirtualKeys.CAPITAL, Input.Key.CapsLock); KeyMap.Add(VirtualKeys.CAPITAL, Key.CapsLock);
KeyMap.Add(VirtualKeys.LCONTROL, Input.Key.ControlLeft); KeyMap.Add(VirtualKeys.LCONTROL, Key.ControlLeft);
KeyMap.Add(VirtualKeys.LSHIFT, Input.Key.ShiftLeft); KeyMap.Add(VirtualKeys.LSHIFT, Key.ShiftLeft);
KeyMap.Add(VirtualKeys.LWIN, Input.Key.WinLeft); KeyMap.Add(VirtualKeys.LWIN, Key.WinLeft);
KeyMap.Add(VirtualKeys.LMENU, Input.Key.AltLeft); KeyMap.Add(VirtualKeys.LMENU, Key.AltLeft);
KeyMap.Add(VirtualKeys.SPACE, Input.Key.Space); KeyMap.Add(VirtualKeys.SPACE, Key.Space);
KeyMap.Add(VirtualKeys.RMENU, Input.Key.AltRight); KeyMap.Add(VirtualKeys.RMENU, Key.AltRight);
KeyMap.Add(VirtualKeys.RWIN, Input.Key.WinRight); KeyMap.Add(VirtualKeys.RWIN, Key.WinRight);
KeyMap.Add(VirtualKeys.APPS, Input.Key.Menu); KeyMap.Add(VirtualKeys.APPS, Key.Menu);
KeyMap.Add(VirtualKeys.RCONTROL, Input.Key.ControlRight); KeyMap.Add(VirtualKeys.RCONTROL, Key.ControlRight);
KeyMap.Add(VirtualKeys.RSHIFT, Input.Key.ShiftRight); KeyMap.Add(VirtualKeys.RSHIFT, Key.ShiftRight);
KeyMap.Add(VirtualKeys.RETURN, Input.Key.Enter); KeyMap.Add(VirtualKeys.RETURN, Key.Enter);
KeyMap.Add(VirtualKeys.BACK, Input.Key.BackSpace); KeyMap.Add(VirtualKeys.BACK, Key.BackSpace);
KeyMap.Add(VirtualKeys.OEM_1, Input.Key.Semicolon); // Varies by keyboard, ;: on Win2K/US KeyMap.Add(VirtualKeys.OEM_1, Key.Semicolon); // Varies by keyboard, ;: on Win2K/US
KeyMap.Add(VirtualKeys.OEM_2, Input.Key.Slash); // Varies by keyboard, /? on Win2K/US KeyMap.Add(VirtualKeys.OEM_2, Key.Slash); // Varies by keyboard, /? on Win2K/US
KeyMap.Add(VirtualKeys.OEM_3, Input.Key.Tilde); // Varies by keyboard, `~ on Win2K/US KeyMap.Add(VirtualKeys.OEM_3, Key.Tilde); // Varies by keyboard, `~ on Win2K/US
KeyMap.Add(VirtualKeys.OEM_4, Input.Key.BracketLeft); // Varies by keyboard, [{ on Win2K/US KeyMap.Add(VirtualKeys.OEM_4, Key.BracketLeft); // Varies by keyboard, [{ on Win2K/US
KeyMap.Add(VirtualKeys.OEM_5, Input.Key.BackSlash); // Varies by keyboard, \| on Win2K/US KeyMap.Add(VirtualKeys.OEM_5, Key.BackSlash); // Varies by keyboard, \| on Win2K/US
KeyMap.Add(VirtualKeys.OEM_6, Input.Key.BracketRight); // Varies by keyboard, ]} on Win2K/US KeyMap.Add(VirtualKeys.OEM_6, Key.BracketRight); // Varies by keyboard, ]} on Win2K/US
KeyMap.Add(VirtualKeys.OEM_7, Input.Key.Quote); // Varies by keyboard, '" on Win2K/US KeyMap.Add(VirtualKeys.OEM_7, Key.Quote); // Varies by keyboard, '" on Win2K/US
KeyMap.Add(VirtualKeys.OEM_PLUS, Input.Key.Plus); // Invariant: + KeyMap.Add(VirtualKeys.OEM_PLUS, Key.Plus); // Invariant: +
KeyMap.Add(VirtualKeys.OEM_COMMA, Input.Key.Comma); // Invariant: , KeyMap.Add(VirtualKeys.OEM_COMMA, Key.Comma); // Invariant: ,
KeyMap.Add(VirtualKeys.OEM_MINUS, Input.Key.Minus); // Invariant: - KeyMap.Add(VirtualKeys.OEM_MINUS, Key.Minus); // Invariant: -
KeyMap.Add(VirtualKeys.OEM_PERIOD, Input.Key.Period); // Invariant: . KeyMap.Add(VirtualKeys.OEM_PERIOD, Key.Period); // Invariant: .
KeyMap.Add(VirtualKeys.HOME, Input.Key.Home); KeyMap.Add(VirtualKeys.HOME, Key.Home);
KeyMap.Add(VirtualKeys.END, Input.Key.End); KeyMap.Add(VirtualKeys.END, Key.End);
KeyMap.Add(VirtualKeys.DELETE, Input.Key.Delete); KeyMap.Add(VirtualKeys.DELETE, Key.Delete);
KeyMap.Add(VirtualKeys.PRIOR, Input.Key.PageUp); KeyMap.Add(VirtualKeys.PRIOR, Key.PageUp);
KeyMap.Add(VirtualKeys.NEXT, Input.Key.PageDown); KeyMap.Add(VirtualKeys.NEXT, Key.PageDown);
KeyMap.Add(VirtualKeys.PRINT, Input.Key.PrintScreen); KeyMap.Add(VirtualKeys.PRINT, Key.PrintScreen);
KeyMap.Add(VirtualKeys.PAUSE, Input.Key.Pause); KeyMap.Add(VirtualKeys.PAUSE, Key.Pause);
KeyMap.Add(VirtualKeys.NUMLOCK, Input.Key.NumLock); KeyMap.Add(VirtualKeys.NUMLOCK, Key.NumLock);
KeyMap.Add(VirtualKeys.SLEEP, Input.Key.Sleep); KeyMap.Add(VirtualKeys.SCROLL, Key.ScrollLock);
KeyMap.Add(VirtualKeys.SNAPSHOT, Key.PrintScreen);
KeyMap.Add(VirtualKeys.CLEAR, Key.Clear);
KeyMap.Add(VirtualKeys.INSERT, Key.Insert);
KeyMap.Add(VirtualKeys.SLEEP, Key.Sleep);
// Keypad // Keypad
for (int i = 0; i <= 9; i++) for (int i = 0; i <= 9; i++)
{ {
KeyMap.Add((VirtualKeys)((int)VirtualKeys.NUMPAD0 + i), Input.Key.Keypad0 + i); KeyMap.Add((VirtualKeys)((int)VirtualKeys.NUMPAD0 + i), Key.Keypad0 + i);
} }
KeyMap.Add(VirtualKeys.DECIMAL, Input.Key.KeypadDecimal); KeyMap.Add(VirtualKeys.DECIMAL, Key.KeypadDecimal);
KeyMap.Add(VirtualKeys.ADD, Input.Key.KeypadAdd); KeyMap.Add(VirtualKeys.ADD, Key.KeypadAdd);
KeyMap.Add(VirtualKeys.SUBTRACT, Input.Key.KeypadSubtract); KeyMap.Add(VirtualKeys.SUBTRACT, Key.KeypadSubtract);
KeyMap.Add(VirtualKeys.DIVIDE, Input.Key.KeypadDivide); KeyMap.Add(VirtualKeys.DIVIDE, Key.KeypadDivide);
KeyMap.Add(VirtualKeys.MULTIPLY, Input.Key.KeypadMultiply); KeyMap.Add(VirtualKeys.MULTIPLY, Key.KeypadMultiply);
// Navigation // Navigation
KeyMap.Add(VirtualKeys.UP, Input.Key.Up); KeyMap.Add(VirtualKeys.UP, Key.Up);
KeyMap.Add(VirtualKeys.DOWN, Input.Key.Down); KeyMap.Add(VirtualKeys.DOWN, Key.Down);
KeyMap.Add(VirtualKeys.LEFT, Input.Key.Left); KeyMap.Add(VirtualKeys.LEFT, Key.Left);
KeyMap.Add(VirtualKeys.RIGHT, Input.Key.Right); KeyMap.Add(VirtualKeys.RIGHT, Key.Right);
} }
catch (ArgumentException e) catch (ArgumentException e)
{ {
@ -138,10 +142,10 @@ namespace OpenTK.Platform.Windows
internal WinRawKeyboard(IntPtr windowHandle) internal WinRawKeyboard(IntPtr windowHandle)
{ {
Debug.WriteLine("Initializing keyboard driver."); Debug.WriteLine("Initializing keyboard driver (WinRawKeyboard).");
Debug.Indent(); Debug.Indent();
this.windowHandle = windowHandle; this.window = windowHandle;
InitKeyMap(); InitKeyMap();
UpdateKeyboardList(); UpdateKeyboardList();
@ -172,12 +176,13 @@ namespace OpenTK.Platform.Windows
Marshal.FreeHGlobal(name_ptr); Marshal.FreeHGlobal(name_ptr);
if (name.ToLower().Contains("root")) if (name.ToLower().Contains("root"))
{ {
// This is a terminal services devices, skip it. // This is a terminal services device, skip it.
continue; continue;
} }
else if (ridl[i].Type == RawInputDeviceType.KEYBOARD || ridl[i].Type == RawInputDeviceType.HID) else if (ridl[i].Type == RawInputDeviceType.KEYBOARD || ridl[i].Type == RawInputDeviceType.HID)
{ {
//It's a keyboard or a USB device that could be a keyboard // This is a keyboard or USB keyboard device. In the latter case, discover if it really is a
// keyboard device by qeurying the registry.
// remove the \??\ // remove the \??\
name = name.Substring(4); name = name.Substring(4);
@ -189,7 +194,6 @@ namespace OpenTK.Platform.Windows
string id_03 = split[2]; // 3&13c0b0c5&0 (Protocol code) string id_03 = split[2]; // 3&13c0b0c5&0 (Protocol code)
// The final part is the class GUID and is not needed here // The final part is the class GUID and is not needed here
string findme = string.Format( string findme = string.Format(
@"System\CurrentControlSet\Enum\{0}\{1}\{2}", @"System\CurrentControlSet\Enum\{0}\{1}\{2}",
id_01, id_02, id_03); id_01, id_02, id_03);
@ -214,13 +218,14 @@ namespace OpenTK.Platform.Windows
kb.NumberOfLeds = info.Device.Keyboard.NumberOfIndicators; kb.NumberOfLeds = info.Device.Keyboard.NumberOfIndicators;
kb.NumberOfFunctionKeys = info.Device.Keyboard.NumberOfFunctionKeys; kb.NumberOfFunctionKeys = info.Device.Keyboard.NumberOfFunctionKeys;
kb.NumberOfKeys = info.Device.Keyboard.NumberOfKeysTotal; kb.NumberOfKeys = info.Device.Keyboard.NumberOfKeysTotal;
kb.DeviceID = (info.Device.Keyboard.Type << 32) + info.Device.Keyboard.SubType; //kb.DeviceID = (info.Device.Keyboard.Type << 32) + info.Device.Keyboard.SubType;
kb.DeviceID = ridl[i].Device;
if (!keyboards.Contains(kb)) //if (!keyboards.Contains(kb))
{ //{
this.RegisterKeyboardDevice(kb); this.RegisterKeyboardDevice(kb);
keyboards.Add(kb); keyboards.Add(kb);
} //}
} }
} }
} }
@ -238,7 +243,7 @@ namespace OpenTK.Platform.Windows
rid[0].UsagePage = 1; rid[0].UsagePage = 1;
rid[0].Usage = 6; rid[0].Usage = 6;
rid[0].Flags = RawInputDeviceFlags.INPUTSINK; rid[0].Flags = RawInputDeviceFlags.INPUTSINK;
rid[0].Target = windowHandle; rid[0].Target = window;
if (!API.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize)) if (!API.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize))
{ {
@ -274,31 +279,36 @@ namespace OpenTK.Platform.Windows
bool pressed = bool pressed =
rin.Data.Keyboard.Message == (int)WindowMessage.KEYDOWN || rin.Data.Keyboard.Message == (int)WindowMessage.KEYDOWN ||
rin.Data.Keyboard.Message == (int)WindowMessage.SYSKEYDOWN; rin.Data.Keyboard.Message == (int)WindowMessage.SYSKEYDOWN;
int index = keyboards.FindIndex(delegate(Keyboard kb)
{
return kb.DeviceID == rin.Header.Device;
});
// Generic control, shift, alt keys may be sent instead of left/right. // Generic control, shift, alt keys may be sent instead of left/right.
// It seems you have to explicitly register left/right events. // It seems you have to explicitly register left/right events.
switch (rin.Data.Keyboard.VKey) switch (rin.Data.Keyboard.VKey)
{ {
case VirtualKeys.SHIFT: case VirtualKeys.SHIFT:
keyboards[0][Input.Key.ShiftLeft] = keyboards[0][Input.Key.ShiftRight] = pressed; keyboards[index][Input.Key.ShiftLeft] = keyboards[index][Input.Key.ShiftRight] = pressed;
return true; return true;
case VirtualKeys.CONTROL: case VirtualKeys.CONTROL:
keyboards[0][Input.Key.ControlLeft] = keyboards[0][Input.Key.ControlRight] = pressed; keyboards[index][Input.Key.ControlLeft] = keyboards[index][Input.Key.ControlRight] = pressed;
return true; return true;
case VirtualKeys.MENU: case VirtualKeys.MENU:
keyboards[0][Input.Key.AltLeft] = keyboards[0][Input.Key.AltRight] = pressed; keyboards[index][Input.Key.AltLeft] = keyboards[index][Input.Key.AltRight] = pressed;
return true; return true;
default: default:
if (!WinRawKeyboard.KeyMap.ContainsKey(rin.Data.Keyboard.VKey)) if (!WinRawKeyboard.KeyMap.ContainsKey(rin.Data.Keyboard.VKey))
{ {
Debug.Print("Virtual key {0} not mapped.", rin.Data.Keyboard.VKey); Debug.Print("Virtual key {0} ({1}) not mapped.",
rin.Data.Keyboard.VKey, (int)rin.Data.Keyboard.VKey);
} }
else else
{ {
keyboards[0][WinRawKeyboard.KeyMap[rin.Data.Keyboard.VKey]] = pressed; keyboards[index][WinRawKeyboard.KeyMap[rin.Data.Keyboard.VKey]] = pressed;
} }
return false; return false;
} }

View file

@ -12,6 +12,8 @@ using OpenTK.Input;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Diagnostics; using System.Diagnostics;
// TODO: How to detect multiple keyboards?
namespace OpenTK.Platform.X11 namespace OpenTK.Platform.X11
{ {
/// <summary> /// <summary>
@ -162,6 +164,9 @@ namespace OpenTK.Platform.X11
internal X11Keyboard(WindowInfo window) internal X11Keyboard(WindowInfo window)
{ {
if (window == null)
throw new ArgumentException("Window cannot be null.");
this.window = window; this.window = window;
Initialize(); Initialize();
@ -183,6 +188,7 @@ namespace OpenTK.Platform.X11
Keyboard kb = new Keyboard(); Keyboard kb = new Keyboard();
kb.Description = "Default X11 keyboard"; kb.Description = "Default X11 keyboard";
kb.NumberOfKeys = lastKeyCode - firstKeyCode + 1; kb.NumberOfKeys = lastKeyCode - firstKeyCode + 1;
kb.DeviceID = IntPtr.Zero;
keyboards.Add(kb); keyboards.Add(kb);
Debug.Print("Keyboard added: {0}", kb.ToString()); Debug.Print("Keyboard added: {0}", kb.ToString());
} }
@ -203,16 +209,23 @@ namespace OpenTK.Platform.X11
IntPtr keysym = API.LookupKeysym(ref e, 0); IntPtr keysym = API.LookupKeysym(ref e, 0);
IntPtr keysym2 = API.LookupKeysym(ref e, 1); IntPtr keysym2 = API.LookupKeysym(ref e, 1);
Debug.Print("Key down: {0}", e.ToString());
int index = keyboards.FindIndex(delegate(Keyboard kb)
{
return kb.DeviceID == IntPtr.Zero;
});
switch (keysym.ToInt64()) switch (keysym.ToInt64())
{ {
default: default:
if (keymap.ContainsKey((XKey)keysym)) if (keymap.ContainsKey((XKey)keysym))
{ {
keyboards[0][keymap[(XKey)keysym]] = pressed; keyboards[index][keymap[(XKey)keysym]] = pressed;
} }
else if (keymap.ContainsKey((XKey)keysym2)) else if (keymap.ContainsKey((XKey)keysym2))
{ {
keyboards[0][keymap[(XKey)keysym2]] = pressed; keyboards[index][keymap[(XKey)keysym2]] = pressed;
} }
else else
{ {