#region Fields
Key key;
+ bool repeat;
KeyboardState state;
- uint scancode;
#endregion
public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
{
Key = args.Key;
- ScanCode = args.ScanCode;
}
#endregion
[CLSCompliant(false)]
public uint ScanCode
{
- get { return scancode; }
- internal set { scancode = value; }
+ get { return (uint)Key; }
}
/// <summary>
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
}
}
//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)
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);
}
var e = KeyUpArgs;
e.Keyboard = KeyboardState;
e.Key = key;
+ e.IsRepeat = false;
KeyUp(this, e);
}
Key key = TranslateKey(ev.Key.Keysym.Scancode);
if (key_pressed)
{
- window.OnKeyDown(key);
+ window.OnKeyDown(key, ev.Key.Repeat > 0);
}
else
{
// 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);
{
if (pressed)
{
- OnKeyDown(key);
+ OnKeyDown(key, repeat_count > 0);
}
else
{
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;
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
+ }
}
public static bool MouseWarpActive = false;
+ readonly bool xi2_supported;
+ readonly int xi2_opcode;
+
#endregion
#region Constructors
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;
}
{
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
{
}
}
+ 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
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);