[Input] Implement key repeat
This commit is contained in:
parent
d968281a1b
commit
8b7d5bc7e4
8 changed files with 119 additions and 15 deletions
|
@ -46,8 +46,8 @@ namespace OpenTK.Input
|
|||
#region Fields
|
||||
|
||||
Key key;
|
||||
bool repeat;
|
||||
KeyboardState state;
|
||||
uint scancode;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -65,7 +65,6 @@ namespace OpenTK.Input
|
|||
public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
|
||||
{
|
||||
Key = args.Key;
|
||||
ScanCode = args.ScanCode;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -87,8 +86,7 @@ namespace OpenTK.Input
|
|||
[CLSCompliant(false)]
|
||||
public uint ScanCode
|
||||
{
|
||||
get { return scancode; }
|
||||
internal set { scancode = value; }
|
||||
get { return (uint)Key; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -145,6 +143,21 @@ namespace OpenTK.Input
|
|||
internal set { state = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="System.Boolean"/> indicating whether
|
||||
/// this key event is a repeat.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, if this event was caused by the user holding down
|
||||
/// a key; false, if this was caused by the user pressing a
|
||||
/// key for the first time.
|
||||
/// </value>
|
||||
public bool IsRepeat
|
||||
{
|
||||
get { return repeat; }
|
||||
internal set { repeat = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -416,10 +416,7 @@ namespace OpenTK.Platform.MacOS
|
|||
//GetKey(keyCode, modifierFlags, keyArgs);
|
||||
Key key = MacOSKeyMap.GetKey(keyCode);
|
||||
|
||||
if (!isARepeat || InputDriver.Keyboard[0].KeyRepeat)
|
||||
{
|
||||
OnKeyDown(key);
|
||||
}
|
||||
OnKeyDown(key, isARepeat);
|
||||
|
||||
var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers));
|
||||
foreach (var c in s)
|
||||
|
|
|
@ -121,13 +121,14 @@ namespace OpenTK.Platform
|
|||
WindowStateChanged(this, e);
|
||||
}
|
||||
|
||||
protected void OnKeyDown(Key key)
|
||||
protected void OnKeyDown(Key key, bool repeat)
|
||||
{
|
||||
KeyboardState.SetKeyState(key, true);
|
||||
|
||||
var e = KeyDownArgs;
|
||||
e.Keyboard = KeyboardState;
|
||||
e.Key = key;
|
||||
e.IsRepeat = repeat;
|
||||
KeyDown(this, e);
|
||||
}
|
||||
|
||||
|
@ -145,6 +146,7 @@ namespace OpenTK.Platform
|
|||
var e = KeyUpArgs;
|
||||
e.Keyboard = KeyboardState;
|
||||
e.Key = key;
|
||||
e.IsRepeat = false;
|
||||
KeyUp(this, e);
|
||||
}
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ namespace OpenTK.Platform.SDL2
|
|||
Key key = TranslateKey(ev.Key.Keysym.Scancode);
|
||||
if (key_pressed)
|
||||
{
|
||||
window.OnKeyDown(key);
|
||||
window.OnKeyDown(key, ev.Key.Repeat > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -581,7 +581,8 @@ namespace OpenTK.Platform.Windows
|
|||
// In this case, both keys will be reported as pressed.
|
||||
|
||||
bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
|
||||
short scancode = (short)((lParam.ToInt64() >> 16) & 0xFF);
|
||||
short scancode = (short)((lParam.ToInt64() >> 16) & 0xff);
|
||||
ushort repeat_count = unchecked((ushort)((ulong)lParam.ToInt64() & 0xffffu));
|
||||
VirtualKeys vkey = (VirtualKeys)wParam;
|
||||
bool is_valid;
|
||||
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
|
||||
|
@ -590,7 +591,7 @@ namespace OpenTK.Platform.Windows
|
|||
{
|
||||
if (pressed)
|
||||
{
|
||||
OnKeyDown(key);
|
||||
OnKeyDown(key, repeat_count > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1707,7 +1707,7 @@ namespace OpenTK.Platform.X11
|
|||
public double root_y;
|
||||
public double event_x;
|
||||
public double event_y;
|
||||
public int flags;
|
||||
public XIEventFlags flags;
|
||||
public XIButtonState buttons;
|
||||
public XIValuatorState valuators;
|
||||
public XIModifierState mods;
|
||||
|
@ -1828,4 +1828,32 @@ namespace OpenTK.Platform.X11
|
|||
RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease),
|
||||
RawMotionMask = (1 << (int)XIEventType.RawMotion),
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum XIKeyEventFlags
|
||||
{
|
||||
Repeat = (1 << 16),
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum XIPointerEventFlags
|
||||
{
|
||||
Emulated = (1 << 16),
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum XITouchEventFlags
|
||||
{
|
||||
PendingEnd = (1 << 16),
|
||||
EmulatingPointer = (1 << 17),
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum XIEventFlags
|
||||
{
|
||||
KeyRepeat = XIKeyEventFlags.Repeat,
|
||||
PointerEmulated = XIPointerEventFlags.Emulated,
|
||||
TouchPendingEnd = XITouchEventFlags.PendingEnd,
|
||||
TouchEmulatingPointer = XITouchEventFlags.EmulatingPointer
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,9 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
public static bool MouseWarpActive = false;
|
||||
|
||||
readonly bool xi2_supported;
|
||||
readonly int xi2_opcode;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
@ -228,6 +231,14 @@ namespace OpenTK.Platform.X11
|
|||
bool supported;
|
||||
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out supported);
|
||||
|
||||
// The XInput2 extension makes keyboard and mouse handling much easier.
|
||||
// Check whether it is available.
|
||||
xi2_supported = XI2Mouse.IsSupported(window.Display);
|
||||
if (xi2_supported)
|
||||
{
|
||||
xi2_opcode = XI2Mouse.XIOpCode;
|
||||
}
|
||||
|
||||
exists = true;
|
||||
}
|
||||
|
||||
|
@ -848,8 +859,41 @@ namespace OpenTK.Platform.X11
|
|||
{
|
||||
if (pressed)
|
||||
{
|
||||
// Check if this is a key repeat event.
|
||||
// X11 does not provide this information,
|
||||
// so we rely on the XInput2 extension for that.
|
||||
// Todo: hack this when XInput2 is not available
|
||||
// by checking if another KeyPress event is enqueued.
|
||||
bool is_repeat = false;
|
||||
if (xi2_supported && e.GenericEventCookie.extension == xi2_opcode)
|
||||
{
|
||||
if (e.GenericEventCookie.evtype == (int)XIEventType.KeyPress)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
XIDeviceEvent* xi = (XIDeviceEvent*)e.GenericEventCookie.data;
|
||||
is_repeat = (xi->flags & XIEventFlags.KeyRepeat) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (API.Pending(window.Display) > 0)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
XEvent dummy = new XEvent();
|
||||
KeyRepeatTestData arg = new KeyRepeatTestData();
|
||||
arg.Event = e;
|
||||
API.CheckIfEvent(window.Display, ref dummy, IsKeyRepeatPredicate,
|
||||
new IntPtr(&arg));
|
||||
is_repeat = arg.IsRepeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Raise KeyDown event
|
||||
OnKeyDown(key);
|
||||
OnKeyDown(key, is_repeat);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1010,6 +1054,24 @@ namespace OpenTK.Platform.X11
|
|||
}
|
||||
}
|
||||
|
||||
struct KeyRepeatTestData
|
||||
{
|
||||
public XEvent Event;
|
||||
public bool IsRepeat;
|
||||
}
|
||||
|
||||
unsafe static bool IsKeyRepeatPredicate(IntPtr display, ref XEvent e, IntPtr arg)
|
||||
{
|
||||
// IsRepeat is true when the event queue contains an identical
|
||||
// KeyPress event at later time no greater than 2.
|
||||
KeyRepeatTestData* data = (KeyRepeatTestData*)arg;
|
||||
data->IsRepeat =
|
||||
e.type == XEventName.KeyPress &&
|
||||
e.KeyEvent.keycode == data->Event.KeyEvent.keycode &&
|
||||
e.KeyEvent.time.ToInt64() - data->Event.KeyEvent.time.ToInt64() < 2;
|
||||
return false; // keep the event in the queue
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Bounds
|
||||
|
|
|
@ -40,7 +40,8 @@ namespace OpenTK.Platform.X11
|
|||
List<MouseState> mice = new List<MouseState>();
|
||||
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
|
||||
internal readonly X11WindowInfo window;
|
||||
static int XIOpCode;
|
||||
internal static int XIOpCode { get; private set; }
|
||||
static bool supported;
|
||||
|
||||
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
|
||||
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
|
||||
|
|
Loading…
Reference in a new issue