mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-09-20 14:37:09 +00:00
[Input] Implement key repeat
This commit is contained in:
parent
d968281a1b
commit
8b7d5bc7e4
|
@ -46,8 +46,8 @@ namespace OpenTK.Input
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
|
bool repeat;
|
||||||
KeyboardState state;
|
KeyboardState state;
|
||||||
uint scancode;
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -65,7 +65,6 @@ namespace OpenTK.Input
|
||||||
public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
|
public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
|
||||||
{
|
{
|
||||||
Key = args.Key;
|
Key = args.Key;
|
||||||
ScanCode = args.ScanCode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -87,8 +86,7 @@ namespace OpenTK.Input
|
||||||
[CLSCompliant(false)]
|
[CLSCompliant(false)]
|
||||||
public uint ScanCode
|
public uint ScanCode
|
||||||
{
|
{
|
||||||
get { return scancode; }
|
get { return (uint)Key; }
|
||||||
internal set { scancode = value; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -145,6 +143,21 @@ namespace OpenTK.Input
|
||||||
internal set { state = value; }
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,10 +416,7 @@ namespace OpenTK.Platform.MacOS
|
||||||
//GetKey(keyCode, modifierFlags, keyArgs);
|
//GetKey(keyCode, modifierFlags, keyArgs);
|
||||||
Key key = MacOSKeyMap.GetKey(keyCode);
|
Key key = MacOSKeyMap.GetKey(keyCode);
|
||||||
|
|
||||||
if (!isARepeat || InputDriver.Keyboard[0].KeyRepeat)
|
OnKeyDown(key, isARepeat);
|
||||||
{
|
|
||||||
OnKeyDown(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers));
|
var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers));
|
||||||
foreach (var c in s)
|
foreach (var c in s)
|
||||||
|
|
|
@ -121,13 +121,14 @@ namespace OpenTK.Platform
|
||||||
WindowStateChanged(this, e);
|
WindowStateChanged(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OnKeyDown(Key key)
|
protected void OnKeyDown(Key key, bool repeat)
|
||||||
{
|
{
|
||||||
KeyboardState.SetKeyState(key, true);
|
KeyboardState.SetKeyState(key, true);
|
||||||
|
|
||||||
var e = KeyDownArgs;
|
var e = KeyDownArgs;
|
||||||
e.Keyboard = KeyboardState;
|
e.Keyboard = KeyboardState;
|
||||||
e.Key = key;
|
e.Key = key;
|
||||||
|
e.IsRepeat = repeat;
|
||||||
KeyDown(this, e);
|
KeyDown(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +146,7 @@ namespace OpenTK.Platform
|
||||||
var e = KeyUpArgs;
|
var e = KeyUpArgs;
|
||||||
e.Keyboard = KeyboardState;
|
e.Keyboard = KeyboardState;
|
||||||
e.Key = key;
|
e.Key = key;
|
||||||
|
e.IsRepeat = false;
|
||||||
KeyUp(this, e);
|
KeyUp(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ namespace OpenTK.Platform.SDL2
|
||||||
Key key = TranslateKey(ev.Key.Keysym.Scancode);
|
Key key = TranslateKey(ev.Key.Keysym.Scancode);
|
||||||
if (key_pressed)
|
if (key_pressed)
|
||||||
{
|
{
|
||||||
window.OnKeyDown(key);
|
window.OnKeyDown(key, ev.Key.Repeat > 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -581,7 +581,8 @@ namespace OpenTK.Platform.Windows
|
||||||
// In this case, both keys will be reported as pressed.
|
// In this case, both keys will be reported as pressed.
|
||||||
|
|
||||||
bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
|
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;
|
VirtualKeys vkey = (VirtualKeys)wParam;
|
||||||
bool is_valid;
|
bool is_valid;
|
||||||
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
|
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
|
||||||
|
@ -590,7 +591,7 @@ namespace OpenTK.Platform.Windows
|
||||||
{
|
{
|
||||||
if (pressed)
|
if (pressed)
|
||||||
{
|
{
|
||||||
OnKeyDown(key);
|
OnKeyDown(key, repeat_count > 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1707,7 +1707,7 @@ namespace OpenTK.Platform.X11
|
||||||
public double root_y;
|
public double root_y;
|
||||||
public double event_x;
|
public double event_x;
|
||||||
public double event_y;
|
public double event_y;
|
||||||
public int flags;
|
public XIEventFlags flags;
|
||||||
public XIButtonState buttons;
|
public XIButtonState buttons;
|
||||||
public XIValuatorState valuators;
|
public XIValuatorState valuators;
|
||||||
public XIModifierState mods;
|
public XIModifierState mods;
|
||||||
|
@ -1828,4 +1828,32 @@ namespace OpenTK.Platform.X11
|
||||||
RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease),
|
RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease),
|
||||||
RawMotionMask = (1 << (int)XIEventType.RawMotion),
|
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;
|
public static bool MouseWarpActive = false;
|
||||||
|
|
||||||
|
readonly bool xi2_supported;
|
||||||
|
readonly int xi2_opcode;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
@ -228,6 +231,14 @@ namespace OpenTK.Platform.X11
|
||||||
bool supported;
|
bool supported;
|
||||||
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out 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;
|
exists = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,8 +859,41 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
if (pressed)
|
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
|
// Raise KeyDown event
|
||||||
OnKeyDown(key);
|
OnKeyDown(key, is_repeat);
|
||||||
}
|
}
|
||||||
else
|
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
|
#endregion
|
||||||
|
|
||||||
#region Bounds
|
#region Bounds
|
||||||
|
|
|
@ -40,7 +40,8 @@ namespace OpenTK.Platform.X11
|
||||||
List<MouseState> mice = new List<MouseState>();
|
List<MouseState> mice = new List<MouseState>();
|
||||||
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
|
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
|
||||||
internal readonly X11WindowInfo window;
|
internal readonly X11WindowInfo window;
|
||||||
static int XIOpCode;
|
internal static int XIOpCode { get; private set; }
|
||||||
|
static bool supported;
|
||||||
|
|
||||||
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
|
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
|
||||||
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
|
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
|
||||||
|
|
Loading…
Reference in a new issue