mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 07:45:37 +00:00
Merge branch 'xkeyfix' of https://github.com/thefiddler/opentk into develop
This commit is contained in:
commit
ade8e61625
|
@ -697,7 +697,6 @@
|
||||||
<Compile Include="Platform\X11\X11Keyboard.cs" />
|
<Compile Include="Platform\X11\X11Keyboard.cs" />
|
||||||
<Compile Include="Platform\X11\X11Mouse.cs" />
|
<Compile Include="Platform\X11\X11Mouse.cs" />
|
||||||
<Compile Include="Input\ButtonState.cs" />
|
<Compile Include="Input\ButtonState.cs" />
|
||||||
<Compile Include="Platform\X11\XI2Mouse.cs" />
|
|
||||||
<EmbeddedResource Include="OpenTK.dll.config">
|
<EmbeddedResource Include="OpenTK.dll.config">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
@ -798,7 +797,11 @@
|
||||||
<Compile Include="Platform\MacOS\Quartz\CoreFoundation.cs">
|
<Compile Include="Platform\MacOS\Quartz\CoreFoundation.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Platform\X11\Bindings\Xkb.cs" />
|
||||||
<Compile Include="Input\MouseScroll.cs" />
|
<Compile Include="Input\MouseScroll.cs" />
|
||||||
|
<Compile Include="Platform\X11\X11Input.cs" />
|
||||||
|
<Compile Include="Platform\X11\XI2Input.cs" />
|
||||||
|
<Compile Include="Platform\X11\XI2MouseKeyboard.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -44,6 +44,9 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
const string lib = "libXi";
|
const string lib = "libXi";
|
||||||
|
|
||||||
|
internal const int XIAllDevices = 0;
|
||||||
|
internal const int XIAllMasterDevices = 1;
|
||||||
|
|
||||||
// mouse
|
// mouse
|
||||||
internal static readonly IntPtr ButtonLeft = Functions.XInternAtom(API.DefaultDisplay, "Button Left", false);
|
internal static readonly IntPtr ButtonLeft = Functions.XInternAtom(API.DefaultDisplay, "Button Left", false);
|
||||||
internal static readonly IntPtr ButtonMiddle = Functions.XInternAtom(API.DefaultDisplay, "Button Middle", false);
|
internal static readonly IntPtr ButtonMiddle = Functions.XInternAtom(API.DefaultDisplay, "Button Middle", false);
|
||||||
|
@ -124,4 +127,13 @@ namespace OpenTK.Platform.X11
|
||||||
[DllImport(lib, EntryPoint = "XIQueryVersion")]
|
[DllImport(lib, EntryPoint = "XIQueryVersion")]
|
||||||
internal static extern Status QueryVersion(Display display, ref int major, ref int minor);
|
internal static extern Status QueryVersion(Display display, ref int major, ref int minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum XIDeviceType
|
||||||
|
{
|
||||||
|
MasterPointer = 1,
|
||||||
|
MasterKeyboard = 2,
|
||||||
|
SlavePointer = 3,
|
||||||
|
SlaveKeyboard = 4,
|
||||||
|
FloatingSlave = 5,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
302
Source/OpenTK/Platform/X11/Bindings/Xkb.cs
Normal file
302
Source/OpenTK/Platform/X11/Bindings/Xkb.cs
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// Xkb.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Stefanos Apostolopoulos <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.X11
|
||||||
|
{
|
||||||
|
using Atom = IntPtr;
|
||||||
|
using KeyCode = Byte;
|
||||||
|
using XkbControlsPtr = IntPtr;
|
||||||
|
using XkbServerMapPtr = IntPtr;
|
||||||
|
using XkbClientMapPtr = IntPtr;
|
||||||
|
using XkbIndicatorPtr = IntPtr;
|
||||||
|
using XkbCompatMapPtr = IntPtr;
|
||||||
|
using XkbGeometryPtr = IntPtr;
|
||||||
|
|
||||||
|
class Xkb
|
||||||
|
{
|
||||||
|
const string lib = "libX11";
|
||||||
|
|
||||||
|
internal const int KeyNameLength = 4;
|
||||||
|
internal const int NumModifiers = 8;
|
||||||
|
internal const int NumVirtualMods = 16;
|
||||||
|
internal const int NumIndicators = 32;
|
||||||
|
internal const int NumKbdGroups = 4;
|
||||||
|
internal const int UseCoreKeyboard = 0x0100;
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbFreeKeyboard")]
|
||||||
|
unsafe internal extern static void FreeKeyboard(XkbDesc* descr, int which, bool free);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbAllocKeyboard")]
|
||||||
|
unsafe internal extern static XkbDesc* AllocKeyboard(IntPtr display);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbGetKeyboard")]
|
||||||
|
internal extern static IntPtr GetKeyboard(IntPtr display, XkbKeyboardMask which, int device_id);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbGetMap")]
|
||||||
|
internal extern static IntPtr GetMap(IntPtr display, XkbKeyboardMask which, int device_spec);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbGetNames")]
|
||||||
|
unsafe internal extern static IntPtr GetNames(IntPtr display, XkbNamesMask which, XkbDesc* xkb);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbKeycodeToKeysym")]
|
||||||
|
internal extern static XKey KeycodeToKeysym(IntPtr display, int keycode, int group, int level);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbQueryExtension")]
|
||||||
|
internal extern static bool QueryExtension(IntPtr display, out int opcode_rtrn, out int event_rtrn,
|
||||||
|
out int error_rtrn, ref int major_in_out, ref int minor_in_out);
|
||||||
|
|
||||||
|
[DllImport(lib, EntryPoint = "XkbSetDetectableAutoRepeat")]
|
||||||
|
internal extern static bool SetDetectableAutoRepeat(IntPtr display, bool detectable, out bool supported);
|
||||||
|
|
||||||
|
internal static bool IsSupported(IntPtr display)
|
||||||
|
{
|
||||||
|
// The XkbQueryExtension manpage says that we cannot
|
||||||
|
// use XQueryExtension with XKB.
|
||||||
|
int opcode, error, ev;
|
||||||
|
int major = 1;
|
||||||
|
int minor = 0;
|
||||||
|
bool supported = QueryExtension(display, out opcode, out ev, out error, ref major, ref minor);
|
||||||
|
Debug.Print("XKB extension is {0}.", supported ? "supported" : "not supported");
|
||||||
|
if (supported)
|
||||||
|
{
|
||||||
|
Debug.Print("XKB version is {0}.{1}", major, minor);
|
||||||
|
}
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum XkbKeyboardMask
|
||||||
|
{
|
||||||
|
Controls = 1 << 0,
|
||||||
|
ServerMap = 1 << 1,
|
||||||
|
IClientMap = 1 << 2,
|
||||||
|
IndicatorMap = 1 << 3,
|
||||||
|
Names = 1 << 4,
|
||||||
|
CompatibilityMap = 1 << 5,
|
||||||
|
Geometry = 1 << 6,
|
||||||
|
AllComponents = 1 << 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum XkbNamesMask
|
||||||
|
{
|
||||||
|
Keycodes = 1 << 0,
|
||||||
|
Geometry = 1 << 1,
|
||||||
|
Symbols = 1 << 2,
|
||||||
|
PhysSymbols = 1 << 3,
|
||||||
|
Types = 1 << 4,
|
||||||
|
Compat = 1 << 5,
|
||||||
|
KeyType = 1 << 6,
|
||||||
|
KTLevel = 1 << 7,
|
||||||
|
Indicator = 1 << 8,
|
||||||
|
Key = 1 << 9,
|
||||||
|
KeyAliasesMask = 1 << 10,
|
||||||
|
VirtualMod = 1 << 11,
|
||||||
|
Group = 1 << 12,
|
||||||
|
RG = 1 << 13,
|
||||||
|
Component = 0x3f,
|
||||||
|
All = 0x3fff
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct XkbDesc
|
||||||
|
{
|
||||||
|
internal IntPtr dpy;
|
||||||
|
internal ushort flags;
|
||||||
|
internal ushort device_spec;
|
||||||
|
internal KeyCode min_key_code;
|
||||||
|
internal KeyCode max_key_code;
|
||||||
|
|
||||||
|
internal XkbControlsPtr ctrls;
|
||||||
|
internal XkbServerMapPtr server;
|
||||||
|
internal XkbClientMapPtr map;
|
||||||
|
internal XkbIndicatorPtr indicators;
|
||||||
|
internal XkbNames* names;
|
||||||
|
internal XkbCompatMapPtr compat;
|
||||||
|
internal XkbGeometryPtr geom;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct XkbKeyAlias
|
||||||
|
{
|
||||||
|
internal fixed byte real[Xkb.KeyNameLength];
|
||||||
|
internal fixed byte alias[Xkb.KeyNameLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct XkbKeyName
|
||||||
|
{
|
||||||
|
internal fixed byte name[Xkb.KeyNameLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
unsafe struct XkbNames
|
||||||
|
{
|
||||||
|
#region Structs
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct Groups
|
||||||
|
{
|
||||||
|
Atom groups0;
|
||||||
|
Atom groups1;
|
||||||
|
Atom groups2;
|
||||||
|
Atom groups3;
|
||||||
|
internal Atom this[int i]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (i < 0 || i > 3)
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (Atom* ptr = &groups0)
|
||||||
|
{
|
||||||
|
return *(ptr + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct Indicators
|
||||||
|
{
|
||||||
|
Atom indicators0;
|
||||||
|
Atom indicators1;
|
||||||
|
Atom indicators2;
|
||||||
|
Atom indicators3;
|
||||||
|
Atom indicators4;
|
||||||
|
Atom indicators5;
|
||||||
|
Atom indicators6;
|
||||||
|
Atom indicators7;
|
||||||
|
Atom indicators8;
|
||||||
|
Atom indicators9;
|
||||||
|
Atom indicators10;
|
||||||
|
Atom indicators11;
|
||||||
|
Atom indicators12;
|
||||||
|
Atom indicators13;
|
||||||
|
Atom indicators14;
|
||||||
|
Atom indicators15;
|
||||||
|
Atom indicators16;
|
||||||
|
Atom indicators17;
|
||||||
|
Atom indicators18;
|
||||||
|
Atom indicators19;
|
||||||
|
Atom indicators20;
|
||||||
|
Atom indicators21;
|
||||||
|
Atom indicators22;
|
||||||
|
Atom indicators23;
|
||||||
|
Atom indicators24;
|
||||||
|
Atom indicators25;
|
||||||
|
Atom indicators26;
|
||||||
|
Atom indicators27;
|
||||||
|
Atom indicators28;
|
||||||
|
Atom indicators29;
|
||||||
|
Atom indicators30;
|
||||||
|
Atom indicators31;
|
||||||
|
internal Atom this[int i]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (i < 0 || i > 31)
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (Atom* ptr = &indicators0)
|
||||||
|
{
|
||||||
|
return *(ptr + i);
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct VMods
|
||||||
|
{
|
||||||
|
Atom vmods0;
|
||||||
|
Atom vmods1;
|
||||||
|
Atom vmods2;
|
||||||
|
Atom vmods3;
|
||||||
|
Atom vmods4;
|
||||||
|
Atom vmods5;
|
||||||
|
Atom vmods6;
|
||||||
|
Atom vmods7;
|
||||||
|
Atom vmods8;
|
||||||
|
Atom vmods9;
|
||||||
|
Atom vmods10;
|
||||||
|
Atom vmods11;
|
||||||
|
Atom vmods12;
|
||||||
|
Atom vmods13;
|
||||||
|
Atom vmods14;
|
||||||
|
Atom vmods15;
|
||||||
|
internal Atom this[int i]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (i < 0 || i > 15)
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (Atom* ptr = &vmods0)
|
||||||
|
{
|
||||||
|
return *(ptr + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal Atom keycodes;
|
||||||
|
internal Atom geometry;
|
||||||
|
internal Atom symbols;
|
||||||
|
internal Atom types;
|
||||||
|
internal Atom compat;
|
||||||
|
internal VMods vmods;
|
||||||
|
internal Indicators indicators;
|
||||||
|
internal Groups groups;
|
||||||
|
internal XkbKeyName* keys;
|
||||||
|
internal XkbKeyAlias* key_aliases;
|
||||||
|
internal Atom *radio_groups;
|
||||||
|
internal Atom phys_symbols;
|
||||||
|
|
||||||
|
internal byte num_keys;
|
||||||
|
internal byte num_key_aliases;
|
||||||
|
internal byte num_rg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -439,9 +439,6 @@ namespace OpenTK.Platform.X11
|
||||||
[DllImport("libX11", EntryPoint = "XFilterEvent")]
|
[DllImport("libX11", EntryPoint = "XFilterEvent")]
|
||||||
public extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
|
public extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
|
||||||
|
|
||||||
[DllImport("libX11")]
|
|
||||||
public extern static bool XkbSetDetectableAutoRepeat(IntPtr display, bool detectable, out bool supported);
|
|
||||||
|
|
||||||
[DllImport("libX11")]
|
[DllImport("libX11")]
|
||||||
public extern static void XPeekEvent(IntPtr display, ref XEvent xevent);
|
public extern static void XPeekEvent(IntPtr display, ref XEvent xevent);
|
||||||
|
|
||||||
|
|
|
@ -945,7 +945,7 @@ namespace OpenTK.Platform.X11
|
||||||
public byte pad;
|
public byte pad;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum Atom
|
internal enum AtomName
|
||||||
{
|
{
|
||||||
AnyPropertyType = 0,
|
AnyPropertyType = 0,
|
||||||
XA_PRIMARY = 1,
|
XA_PRIMARY = 1,
|
||||||
|
@ -1688,7 +1688,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
public int deviceid;
|
public int deviceid;
|
||||||
public IntPtr name; // byte*
|
public IntPtr name; // byte*
|
||||||
public int use;
|
public XIDeviceType use;
|
||||||
public int attachment;
|
public int attachment;
|
||||||
public Bool enabled;
|
public Bool enabled;
|
||||||
public int num_classes;
|
public int num_classes;
|
||||||
|
|
|
@ -34,7 +34,25 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
class X11Factory : PlatformFactoryBase
|
class X11Factory : PlatformFactoryBase
|
||||||
{
|
{
|
||||||
static IMouseDriver2 MouseDriver;
|
IInputDriver2 input_driver;
|
||||||
|
IInputDriver2 InputDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (input_driver == null)
|
||||||
|
{
|
||||||
|
if (XI2MouseKeyboard.IsSupported(IntPtr.Zero))
|
||||||
|
{
|
||||||
|
input_driver = new XI2Input();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input_driver = new X11Input();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input_driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
|
@ -83,25 +101,17 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
public override IKeyboardDriver2 CreateKeyboardDriver()
|
public override IKeyboardDriver2 CreateKeyboardDriver()
|
||||||
{
|
{
|
||||||
return new X11Keyboard();
|
return InputDriver.KeyboardDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IMouseDriver2 CreateMouseDriver()
|
public override IMouseDriver2 CreateMouseDriver()
|
||||||
{
|
{
|
||||||
lock (this)
|
return InputDriver.MouseDriver;
|
||||||
{
|
|
||||||
MouseDriver =
|
|
||||||
MouseDriver ??
|
|
||||||
(XI2Mouse.IsSupported(IntPtr.Zero) ?
|
|
||||||
(IMouseDriver2)new XI2Mouse() : // Requires xorg 1.7 or higher.
|
|
||||||
(IMouseDriver2)new X11Mouse()); // Always supported.
|
|
||||||
return MouseDriver;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IJoystickDriver2 CreateJoystickDriver()
|
public override IJoystickDriver2 CreateJoystickDriver()
|
||||||
{
|
{
|
||||||
return new X11Joystick();
|
return InputDriver.JoystickDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -109,12 +119,12 @@ namespace OpenTK.Platform.X11
|
||||||
protected override void Dispose(bool manual)
|
protected override void Dispose(bool manual)
|
||||||
{
|
{
|
||||||
base.Dispose(manual);
|
base.Dispose(manual);
|
||||||
if (manual && MouseDriver != null)
|
if (manual)
|
||||||
{
|
{
|
||||||
if (MouseDriver is IDisposable)
|
if (input_driver is IDisposable)
|
||||||
{
|
{
|
||||||
(MouseDriver as IDisposable).Dispose();
|
(input_driver as IDisposable).Dispose();
|
||||||
MouseDriver = null;
|
input_driver = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,8 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
const int _min_width = 30, _min_height = 30;
|
const int _min_width = 30, _min_height = 30;
|
||||||
|
|
||||||
X11WindowInfo window = new X11WindowInfo();
|
readonly X11WindowInfo window = new X11WindowInfo();
|
||||||
|
readonly X11KeyMap KeyMap;
|
||||||
|
|
||||||
// Window manager hints for fullscreen windows.
|
// Window manager hints for fullscreen windows.
|
||||||
// Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which
|
// Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which
|
||||||
|
@ -230,20 +231,26 @@ namespace OpenTK.Platform.X11
|
||||||
Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle));
|
Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle));
|
||||||
Debug.Unindent();
|
Debug.Unindent();
|
||||||
|
|
||||||
// Request that auto-repeat is only set on devices that support it physically.
|
using (new XLock(window.Display))
|
||||||
// This typically means that it's turned off for keyboards (which is what we want).
|
{
|
||||||
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
|
// Request that auto-repeat is only set on devices that support it physically.
|
||||||
// be reset before the program exits.
|
// This typically means that it's turned off for keyboards (which is what we want).
|
||||||
bool supported;
|
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
|
||||||
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out supported);
|
// be reset before the program exits.
|
||||||
|
if (Xkb.IsSupported(window.Display))
|
||||||
|
{
|
||||||
|
bool supported;
|
||||||
|
Xkb.SetDetectableAutoRepeat(window.Display, true, out supported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The XInput2 extension makes keyboard and mouse handling much easier.
|
// The XInput2 extension makes keyboard and mouse handling much easier.
|
||||||
// Check whether it is available.
|
// Check whether it is available.
|
||||||
xi2_supported = XI2Mouse.IsSupported(window.Display);
|
xi2_supported = XI2MouseKeyboard.IsSupported(window.Display);
|
||||||
if (xi2_supported)
|
if (xi2_supported)
|
||||||
{
|
{
|
||||||
xi2_opcode = XI2Mouse.XIOpCode;
|
xi2_opcode = XI2MouseKeyboard.XIOpCode;
|
||||||
xi2_version = XI2Mouse.XIVersion;
|
xi2_version = XI2MouseKeyboard.XIVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
exists = true;
|
exists = true;
|
||||||
|
@ -270,6 +277,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
window.Screen = Functions.XDefaultScreen(window.Display); //API.DefaultScreen;
|
window.Screen = Functions.XDefaultScreen(window.Display); //API.DefaultScreen;
|
||||||
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen); // API.RootWindow;
|
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen); // API.RootWindow;
|
||||||
|
KeyMap = new X11KeyMap(window.Display);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Print("Display: {0}, Screen {1}, Root window: {2}", window.Display, window.Screen,
|
Debug.Print("Display: {0}, Screen {1}, Root window: {2}", window.Display, window.Screen,
|
||||||
|
@ -658,7 +666,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
Functions.XGetWindowProperty(window.Display, window.Handle,
|
Functions.XGetWindowProperty(window.Display, window.Handle,
|
||||||
_atom_net_frame_extents, IntPtr.Zero, new IntPtr(16), false,
|
_atom_net_frame_extents, IntPtr.Zero, new IntPtr(16), false,
|
||||||
(IntPtr)Atom.XA_CARDINAL, out atom, out format, out nitems, out bytes_after, ref prop);
|
(IntPtr)AtomName.XA_CARDINAL, out atom, out format, out nitems, out bytes_after, ref prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop != IntPtr.Zero))
|
if ((prop != IntPtr.Zero))
|
||||||
|
@ -851,7 +859,7 @@ namespace OpenTK.Platform.X11
|
||||||
case XEventName.KeyRelease:
|
case XEventName.KeyRelease:
|
||||||
bool pressed = e.type == XEventName.KeyPress;
|
bool pressed = e.type == XEventName.KeyPress;
|
||||||
Key key;
|
Key key;
|
||||||
if (X11KeyMap.TranslateKey(ref e.KeyEvent, out key))
|
if (KeyMap.TranslateKey(ref e.KeyEvent, out key))
|
||||||
{
|
{
|
||||||
if (pressed)
|
if (pressed)
|
||||||
{
|
{
|
||||||
|
@ -986,6 +994,7 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
Debug.Print("keybard mapping refreshed");
|
Debug.Print("keybard mapping refreshed");
|
||||||
Functions.XRefreshKeyboardMapping(ref e.MappingEvent);
|
Functions.XRefreshKeyboardMapping(ref e.MappingEvent);
|
||||||
|
KeyMap.RefreshKeycodes(window.Display);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1719,7 +1728,6 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
|
|
||||||
window.Dispose();
|
window.Dispose();
|
||||||
window = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
97
Source/OpenTK/Platform/X11/X11Input.cs
Normal file
97
Source/OpenTK/Platform/X11/X11Input.cs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// X11Input.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// thefiddler <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.X11
|
||||||
|
{
|
||||||
|
class X11Input : IInputDriver2
|
||||||
|
{
|
||||||
|
readonly X11Mouse mouse = new X11Mouse();
|
||||||
|
readonly X11Keyboard keyboard = new X11Keyboard();
|
||||||
|
readonly X11Joystick joystick = new X11Joystick();
|
||||||
|
readonly IGamePadDriver gamepad = new MappedGamePadDriver();
|
||||||
|
|
||||||
|
internal X11Input()
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Using X11 core input driver.");
|
||||||
|
Debug.WriteLine("[Warning] Mouse functionality will be significantly reduced.");
|
||||||
|
Debug.WriteLine("[Warning] Copy OpenTK.dll.config to use the XI2 input driver instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IInputDriver2 Members
|
||||||
|
|
||||||
|
public IMouseDriver2 MouseDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mouse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IKeyboardDriver2 KeyboardDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGamePadDriver GamePadDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return gamepad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IJoystickDriver2 JoystickDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return joystick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
joystick.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,30 @@
|
||||||
#region --- License ---
|
#region License
|
||||||
/* Licensed under the MIT/X11 license.
|
//
|
||||||
* Copyright (c) 2006-2008 the OpenTK team.
|
// X11KeyMap.cs
|
||||||
* This notice may not be removed.
|
//
|
||||||
* See license.txt for licensing detailed licensing details.
|
// Author:
|
||||||
*/
|
// Stefanos Apostolopoulos <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
@ -14,9 +35,230 @@ using OpenTK.Input;
|
||||||
|
|
||||||
namespace OpenTK.Platform.X11
|
namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
static class X11KeyMap
|
class X11KeyMap
|
||||||
{
|
{
|
||||||
public static Key GetKey(XKey key)
|
// Keycode lookup table for current layout
|
||||||
|
readonly Key[] keycodes = new Key[256];
|
||||||
|
readonly bool xkb_supported;
|
||||||
|
|
||||||
|
internal X11KeyMap(IntPtr display)
|
||||||
|
{
|
||||||
|
xkb_supported = Xkb.IsSupported(display);
|
||||||
|
if (xkb_supported)
|
||||||
|
{
|
||||||
|
RefreshKeycodes(display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refreshes the keycodes lookup table based
|
||||||
|
// on the current keyboard layout.
|
||||||
|
internal void RefreshKeycodes(IntPtr display)
|
||||||
|
{
|
||||||
|
// Approach inspired by GLFW: http://www.glfw.org/
|
||||||
|
// Huge props to the GLFW team!
|
||||||
|
if (xkb_supported)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
// Xkb.GetKeyboard appears to be broken (multiple bug reports across distros)
|
||||||
|
// so use Xkb.AllocKeyboard with Xkb.GetNames instead.
|
||||||
|
XkbDesc* keyboard = Xkb.AllocKeyboard(display);
|
||||||
|
if (keyboard != null)
|
||||||
|
{
|
||||||
|
Xkb.GetNames(display, XkbNamesMask.All, keyboard);
|
||||||
|
|
||||||
|
for (int i = 0; i < keycodes.Length; i++)
|
||||||
|
{
|
||||||
|
keycodes[i] = Key.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map all alphanumeric keys of this layout
|
||||||
|
// Symbols are handled in GetKey() instead.
|
||||||
|
for (int i = keyboard->min_key_code; i <= keyboard->max_key_code; ++i)
|
||||||
|
{
|
||||||
|
string name = new string((sbyte*)keyboard->names->keys[i].name, 0, Xkb.KeyNameLength);
|
||||||
|
|
||||||
|
Key key = Key.Unknown;
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "TLDE":
|
||||||
|
key = Key.Tilde;
|
||||||
|
break;
|
||||||
|
case "AE01":
|
||||||
|
key = Key.Number1;
|
||||||
|
break;
|
||||||
|
case "AE02":
|
||||||
|
key = Key.Number2;
|
||||||
|
break;
|
||||||
|
case "AE03":
|
||||||
|
key = Key.Number3;
|
||||||
|
break;
|
||||||
|
case "AE04":
|
||||||
|
key = Key.Number4;
|
||||||
|
break;
|
||||||
|
case "AE05":
|
||||||
|
key = Key.Number5;
|
||||||
|
break;
|
||||||
|
case "AE06":
|
||||||
|
key = Key.Number6;
|
||||||
|
break;
|
||||||
|
case "AE07":
|
||||||
|
key = Key.Number7;
|
||||||
|
break;
|
||||||
|
case "AE08":
|
||||||
|
key = Key.Number8;
|
||||||
|
break;
|
||||||
|
case "AE09":
|
||||||
|
key = Key.Number9;
|
||||||
|
break;
|
||||||
|
case "AE10":
|
||||||
|
key = Key.Number0;
|
||||||
|
break;
|
||||||
|
case "AE11":
|
||||||
|
key = Key.Minus;
|
||||||
|
break;
|
||||||
|
case "AE12":
|
||||||
|
key = Key.Plus;
|
||||||
|
break;
|
||||||
|
case "AD01":
|
||||||
|
key = Key.Q;
|
||||||
|
break;
|
||||||
|
case "AD02":
|
||||||
|
key = Key.W;
|
||||||
|
break;
|
||||||
|
case "AD03":
|
||||||
|
key = Key.E;
|
||||||
|
break;
|
||||||
|
case "AD04":
|
||||||
|
key = Key.R;
|
||||||
|
break;
|
||||||
|
case "AD05":
|
||||||
|
key = Key.T;
|
||||||
|
break;
|
||||||
|
case "AD06":
|
||||||
|
key = Key.Y;
|
||||||
|
break;
|
||||||
|
case "AD07":
|
||||||
|
key = Key.U;
|
||||||
|
break;
|
||||||
|
case "AD08":
|
||||||
|
key = Key.I;
|
||||||
|
break;
|
||||||
|
case "AD09":
|
||||||
|
key = Key.O;
|
||||||
|
break;
|
||||||
|
case "AD10":
|
||||||
|
key = Key.P;
|
||||||
|
break;
|
||||||
|
case "AD11":
|
||||||
|
key = Key.BracketLeft;
|
||||||
|
break;
|
||||||
|
case "AD12":
|
||||||
|
key = Key.BracketRight;
|
||||||
|
break;
|
||||||
|
case "AC01":
|
||||||
|
key = Key.A;
|
||||||
|
break;
|
||||||
|
case "AC02":
|
||||||
|
key = Key.S;
|
||||||
|
break;
|
||||||
|
case "AC03":
|
||||||
|
key = Key.D;
|
||||||
|
break;
|
||||||
|
case "AC04":
|
||||||
|
key = Key.F;
|
||||||
|
break;
|
||||||
|
case "AC05":
|
||||||
|
key = Key.G;
|
||||||
|
break;
|
||||||
|
case "AC06":
|
||||||
|
key = Key.H;
|
||||||
|
break;
|
||||||
|
case "AC07":
|
||||||
|
key = Key.J;
|
||||||
|
break;
|
||||||
|
case "AC08":
|
||||||
|
key = Key.K;
|
||||||
|
break;
|
||||||
|
case "AC09":
|
||||||
|
key = Key.L;
|
||||||
|
break;
|
||||||
|
case "AC10":
|
||||||
|
key = Key.Semicolon;
|
||||||
|
break;
|
||||||
|
case "AC11":
|
||||||
|
key = Key.Quote;
|
||||||
|
break;
|
||||||
|
case "AB01":
|
||||||
|
key = Key.Z;
|
||||||
|
break;
|
||||||
|
case "AB02":
|
||||||
|
key = Key.X;
|
||||||
|
break;
|
||||||
|
case "AB03":
|
||||||
|
key = Key.C;
|
||||||
|
break;
|
||||||
|
case "AB04":
|
||||||
|
key = Key.V;
|
||||||
|
break;
|
||||||
|
case "AB05":
|
||||||
|
key = Key.B;
|
||||||
|
break;
|
||||||
|
case "AB06":
|
||||||
|
key = Key.N;
|
||||||
|
break;
|
||||||
|
case "AB07":
|
||||||
|
key = Key.M;
|
||||||
|
break;
|
||||||
|
case "AB08":
|
||||||
|
key = Key.Comma;
|
||||||
|
break;
|
||||||
|
case "AB09":
|
||||||
|
key = Key.Period;
|
||||||
|
break;
|
||||||
|
case "AB10":
|
||||||
|
key = Key.Slash;
|
||||||
|
break;
|
||||||
|
case "BKSL":
|
||||||
|
key = Key.BackSlash;
|
||||||
|
break;
|
||||||
|
case "LSGT":
|
||||||
|
key = Key.Unknown;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
key = Key.Unknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
keycodes[i] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Xkb.FreeKeyboard(keyboard, 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate unknown keys (and symbols) using
|
||||||
|
// regular layout-dependent GetKey()
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
if (keycodes[i] == Key.Unknown)
|
||||||
|
{
|
||||||
|
// TranslateKeyCode expects a XKeyEvent structure
|
||||||
|
// Make one up
|
||||||
|
XKeyEvent e = new XKeyEvent();
|
||||||
|
e.display = display;
|
||||||
|
e.keycode = i;
|
||||||
|
Key key = Key.Unknown;
|
||||||
|
if (TranslateKeyEvent(ref e, out key))
|
||||||
|
{
|
||||||
|
keycodes[i] = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Key TranslateXKey(XKey key)
|
||||||
{
|
{
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
|
@ -371,14 +613,26 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool TranslateKey(ref XKeyEvent e, out Key key)
|
bool TranslateKeyEvent(ref XKeyEvent e, out Key key)
|
||||||
|
{
|
||||||
|
if (xkb_supported)
|
||||||
|
{
|
||||||
|
return TranslateKeyXkb(e.display, e.keycode, out key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TranslateKeyX11(ref e, out key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslateKeyX11(ref XKeyEvent e, out Key key)
|
||||||
{
|
{
|
||||||
XKey keysym = (XKey)API.LookupKeysym(ref e, 0);
|
XKey keysym = (XKey)API.LookupKeysym(ref e, 0);
|
||||||
XKey keysym2 = (XKey)API.LookupKeysym(ref e, 1);
|
XKey keysym2 = (XKey)API.LookupKeysym(ref e, 1);
|
||||||
key = X11KeyMap.GetKey(keysym);
|
key = X11KeyMap.TranslateXKey(keysym);
|
||||||
if (key == Key.Unknown)
|
if (key == Key.Unknown)
|
||||||
{
|
{
|
||||||
key = X11KeyMap.GetKey(keysym2);
|
key = X11KeyMap.TranslateXKey(keysym2);
|
||||||
}
|
}
|
||||||
if (key == Key.Unknown)
|
if (key == Key.Unknown)
|
||||||
{
|
{
|
||||||
|
@ -388,6 +642,59 @@ namespace OpenTK.Platform.X11
|
||||||
return key != Key.Unknown;
|
return key != Key.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslateKeyXkb(IntPtr display, int keycode, out Key key)
|
||||||
|
{
|
||||||
|
if (keycode < 8 || keycode > 255)
|
||||||
|
{
|
||||||
|
key = Key.Unknown;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate the numeric keypad using the secondary group
|
||||||
|
// (equivalent to NumLock = on)
|
||||||
|
XKey keysym = Xkb.KeycodeToKeysym(display, keycode, 0, 1);
|
||||||
|
switch (keysym)
|
||||||
|
{
|
||||||
|
case XKey.KP_0: key = Key.Keypad0; return true;
|
||||||
|
case XKey.KP_1: key = Key.Keypad1; return true;
|
||||||
|
case XKey.KP_2: key = Key.Keypad2; return true;
|
||||||
|
case XKey.KP_3: key = Key.Keypad3; return true;
|
||||||
|
case XKey.KP_4: key = Key.Keypad4; return true;
|
||||||
|
case XKey.KP_5: key = Key.Keypad5; return true;
|
||||||
|
case XKey.KP_6: key = Key.Keypad6; return true;
|
||||||
|
case XKey.KP_7: key = Key.Keypad7; return true;
|
||||||
|
case XKey.KP_8: key = Key.Keypad8; return true;
|
||||||
|
case XKey.KP_9: key = Key.Keypad9; return true;
|
||||||
|
case XKey.KP_Separator:
|
||||||
|
case XKey.KP_Decimal: key = Key.KeypadDecimal; return true;
|
||||||
|
case XKey.KP_Equal: key = Key.Unknown; return false; // Todo: fixme
|
||||||
|
case XKey.KP_Enter: key = Key.KeypadEnter; return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate non-alphanumeric keys using the primary group
|
||||||
|
keysym = Xkb.KeycodeToKeysym(display, keycode, 0, 0);
|
||||||
|
key = TranslateXKey(keysym);
|
||||||
|
return key != Key.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool TranslateKey(int keycode, out Key key)
|
||||||
|
{
|
||||||
|
if (keycode < 0 || keycode > 255)
|
||||||
|
{
|
||||||
|
key = Key.Unknown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key = keycodes[keycode];
|
||||||
|
}
|
||||||
|
return key != Key.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool TranslateKey(ref XKeyEvent e, out Key key)
|
||||||
|
{
|
||||||
|
return TranslateKey(e.keycode, out key);
|
||||||
|
}
|
||||||
|
|
||||||
internal static MouseButton TranslateButton(int button, out float wheelx, out float wheely)
|
internal static MouseButton TranslateButton(int button, out float wheelx, out float wheely)
|
||||||
{
|
{
|
||||||
wheelx = 0;
|
wheelx = 0;
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace OpenTK.Platform.X11
|
||||||
readonly static string name = "Core X11 keyboard";
|
readonly static string name = "Core X11 keyboard";
|
||||||
readonly byte[] keys = new byte[32];
|
readonly byte[] keys = new byte[32];
|
||||||
readonly int KeysymsPerKeycode;
|
readonly int KeysymsPerKeycode;
|
||||||
|
readonly X11KeyMap KeyMap;
|
||||||
KeyboardState state = new KeyboardState();
|
KeyboardState state = new KeyboardState();
|
||||||
|
|
||||||
public X11Keyboard()
|
public X11Keyboard()
|
||||||
|
@ -59,17 +60,15 @@ namespace OpenTK.Platform.X11
|
||||||
ref KeysymsPerKeycode);
|
ref KeysymsPerKeycode);
|
||||||
Functions.XFree(keysym_ptr);
|
Functions.XFree(keysym_ptr);
|
||||||
|
|
||||||
try
|
if (Xkb.IsSupported(display))
|
||||||
{
|
{
|
||||||
// Request that auto-repeat is only set on devices that support it physically.
|
// Request that auto-repeat is only set on devices that support it physically.
|
||||||
// This typically means that it's turned off for keyboards what we want).
|
// This typically means that it's turned off for keyboards what we want).
|
||||||
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
|
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
|
||||||
// be reset before the program exits.
|
// be reset before the program exits.
|
||||||
bool supported;
|
bool supported;
|
||||||
Functions.XkbSetDetectableAutoRepeat(display, true, out supported);
|
Xkb.SetDetectableAutoRepeat(display, true, out supported);
|
||||||
}
|
KeyMap = new X11KeyMap(display);
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,23 +103,13 @@ namespace OpenTK.Platform.X11
|
||||||
using (new XLock(display))
|
using (new XLock(display))
|
||||||
{
|
{
|
||||||
Functions.XQueryKeymap(display, keys);
|
Functions.XQueryKeymap(display, keys);
|
||||||
for (int keycode = 8; keycode < 256; keycode++)
|
for (int keycode = 0; keycode < 256; keycode++)
|
||||||
{
|
{
|
||||||
bool pressed = (keys[keycode >> 3] >> (keycode & 0x07) & 0x01) != 0;
|
bool pressed = (keys[keycode >> 3] >> (keycode & 0x07) & 0x01) != 0;
|
||||||
Key key;
|
Key key;
|
||||||
|
if (KeyMap.TranslateKey(keycode, out key))
|
||||||
for (int mod = 0; mod < KeysymsPerKeycode; mod++)
|
|
||||||
{
|
{
|
||||||
IntPtr keysym = Functions.XKeycodeToKeysym(display, (byte)keycode, mod);
|
state[key] = pressed;
|
||||||
if (keysym != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
key = X11KeyMap.GetKey((XKey)keysym);
|
|
||||||
if (pressed)
|
|
||||||
state.EnableBit((int)key);
|
|
||||||
else
|
|
||||||
state.DisableBit((int)key);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
95
Source/OpenTK/Platform/X11/XI2Input.cs
Normal file
95
Source/OpenTK/Platform/X11/XI2Input.cs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#region License
|
||||||
|
//
|
||||||
|
// XI2Input.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// thefiddler <stapostol@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2014
|
||||||
|
//
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace OpenTK.Platform.X11
|
||||||
|
{
|
||||||
|
class XI2Input : IInputDriver2
|
||||||
|
{
|
||||||
|
readonly XI2MouseKeyboard mouse_keyboard = new XI2MouseKeyboard();
|
||||||
|
readonly X11Joystick joystick = new X11Joystick();
|
||||||
|
readonly IGamePadDriver gamepad = new MappedGamePadDriver();
|
||||||
|
|
||||||
|
internal XI2Input()
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Using XI2 input driver.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IInputDriver2 Members
|
||||||
|
|
||||||
|
public IMouseDriver2 MouseDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mouse_keyboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IKeyboardDriver2 KeyboardDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return mouse_keyboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGamePadDriver GamePadDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return gamepad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IJoystickDriver2 JoystickDriver
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return joystick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
mouse_keyboard.Dispose();
|
||||||
|
joystick.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,10 +34,12 @@ using OpenTK.Input;
|
||||||
|
|
||||||
namespace OpenTK.Platform.X11
|
namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
sealed class XI2Mouse : IMouseDriver2, IDisposable
|
sealed class XI2MouseKeyboard : IKeyboardDriver2, IMouseDriver2, IDisposable
|
||||||
{
|
{
|
||||||
const XEventName ExitEvent = XEventName.LASTEvent + 1;
|
const XEventName ExitEvent = XEventName.LASTEvent + 1;
|
||||||
|
readonly object Sync = new object();
|
||||||
readonly Thread ProcessingThread;
|
readonly Thread ProcessingThread;
|
||||||
|
readonly X11KeyMap KeyMap;
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
|
||||||
class XIMouse
|
class XIMouse
|
||||||
|
@ -48,6 +50,14 @@ namespace OpenTK.Platform.X11
|
||||||
public XIScrollClassInfo ScrollY = new XIScrollClassInfo { number = -1 };
|
public XIScrollClassInfo ScrollY = new XIScrollClassInfo { number = -1 };
|
||||||
public XIValuatorClassInfo MotionX = new XIValuatorClassInfo { number = -1 };
|
public XIValuatorClassInfo MotionX = new XIValuatorClassInfo { number = -1 };
|
||||||
public XIValuatorClassInfo MotionY = new XIValuatorClassInfo { number = -1 };
|
public XIValuatorClassInfo MotionY = new XIValuatorClassInfo { number = -1 };
|
||||||
|
public string Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
class XIKeyboard
|
||||||
|
{
|
||||||
|
public KeyboardState State;
|
||||||
|
public XIDeviceInfo DeviceInfo;
|
||||||
|
public string Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atoms
|
// Atoms
|
||||||
|
@ -66,9 +76,12 @@ namespace OpenTK.Platform.X11
|
||||||
//static readonly IntPtr RelVertWheel;
|
//static readonly IntPtr RelVertWheel;
|
||||||
|
|
||||||
long cursor_x, cursor_y; // For GetCursorState()
|
long cursor_x, cursor_y; // For GetCursorState()
|
||||||
List<XIMouse> devices = new List<XIMouse>(); // List of connected mice
|
List<XIMouse> devices = new List<XIMouse>(); // list of connected mice
|
||||||
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps hardware device ids to XIMouse ids
|
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps hardware device ids to XIMouse ids
|
||||||
|
|
||||||
|
List<XIKeyboard> keyboards = new List<XIKeyboard>(); // list of connected keybords
|
||||||
|
Dictionary<int, int> keyboard_ids = new Dictionary<int, int>(); // maps hardware device ids to XIKeyboard ids
|
||||||
|
|
||||||
internal readonly X11WindowInfo window;
|
internal readonly X11WindowInfo window;
|
||||||
internal static int XIOpCode { get; private set; }
|
internal static int XIOpCode { get; private set; }
|
||||||
internal static int XIVersion { get; private set; }
|
internal static int XIVersion { get; private set; }
|
||||||
|
@ -76,7 +89,7 @@ namespace OpenTK.Platform.X11
|
||||||
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
|
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
|
||||||
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
|
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
|
||||||
|
|
||||||
static XI2Mouse()
|
static XI2MouseKeyboard()
|
||||||
{
|
{
|
||||||
using (new XLock(API.DefaultDisplay))
|
using (new XLock(API.DefaultDisplay))
|
||||||
{
|
{
|
||||||
|
@ -106,9 +119,8 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public XI2Mouse()
|
public XI2MouseKeyboard()
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Using XI2Mouse.");
|
|
||||||
window = new X11WindowInfo();
|
window = new X11WindowInfo();
|
||||||
|
|
||||||
window.Display = Functions.XOpenDisplay(IntPtr.Zero);
|
window.Display = Functions.XOpenDisplay(IntPtr.Zero);
|
||||||
|
@ -117,6 +129,8 @@ namespace OpenTK.Platform.X11
|
||||||
window.Screen = Functions.XDefaultScreen(window.Display);
|
window.Screen = Functions.XDefaultScreen(window.Display);
|
||||||
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen);
|
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen);
|
||||||
window.Handle = window.RootWindow;
|
window.Handle = window.RootWindow;
|
||||||
|
|
||||||
|
KeyMap = new X11KeyMap(window.Display);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSupported(window.Display))
|
if (!IsSupported(window.Display))
|
||||||
|
@ -124,6 +138,8 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
using (XIEventMask mask = new XIEventMask(1,
|
using (XIEventMask mask = new XIEventMask(1,
|
||||||
|
XIEventMasks.RawKeyPressMask |
|
||||||
|
XIEventMasks.RawKeyReleaseMask |
|
||||||
XIEventMasks.RawButtonPressMask |
|
XIEventMasks.RawButtonPressMask |
|
||||||
XIEventMasks.RawButtonReleaseMask |
|
XIEventMasks.RawButtonReleaseMask |
|
||||||
XIEventMasks.RawMotionMask |
|
XIEventMasks.RawMotionMask |
|
||||||
|
@ -132,10 +148,9 @@ namespace OpenTK.Platform.X11
|
||||||
(XIEventMasks)(1 << (int)ExitEvent)))
|
(XIEventMasks)(1 << (int)ExitEvent)))
|
||||||
{
|
{
|
||||||
XI.SelectEvents(window.Display, window.Handle, mask);
|
XI.SelectEvents(window.Display, window.Handle, mask);
|
||||||
|
UpdateDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDevices();
|
|
||||||
|
|
||||||
ProcessingThread = new Thread(ProcessEvents);
|
ProcessingThread = new Thread(ProcessEvents);
|
||||||
ProcessingThread.IsBackground = true;
|
ProcessingThread.IsBackground = true;
|
||||||
ProcessingThread.Start();
|
ProcessingThread.Start();
|
||||||
|
@ -181,127 +196,95 @@ namespace OpenTK.Platform.X11
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDevices()
|
#region IKeyboardDriver2 Members
|
||||||
|
|
||||||
|
KeyboardState IKeyboardDriver2.GetState()
|
||||||
{
|
{
|
||||||
int count;
|
lock (Sync)
|
||||||
unsafe
|
|
||||||
{
|
{
|
||||||
XIDeviceInfo* list = (XIDeviceInfo*)XI.QueryDevice(window.Display, 1, out count);
|
KeyboardState state = new KeyboardState();
|
||||||
|
foreach (XIKeyboard k in keyboards)
|
||||||
Debug.Print("Refreshing mouse device list");
|
|
||||||
Debug.Print("{0} mouse devices detected", count);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
if (devices.Count <= i)
|
state.MergeBits(k.State);
|
||||||
{
|
|
||||||
devices.Add(new XIMouse());
|
|
||||||
}
|
|
||||||
XIMouse d = devices[i];
|
|
||||||
d.DeviceInfo = *(list + i);
|
|
||||||
d.State.SetIsConnected(d.DeviceInfo.enabled);
|
|
||||||
Debug.Print("Device {0} is {1} and has:",
|
|
||||||
i, d.DeviceInfo.enabled ? "enabled" : "disabled");
|
|
||||||
|
|
||||||
// Decode the XIDeviceInfo to axes, buttons and scroll types
|
|
||||||
for (int j = 0; j < d.DeviceInfo.num_classes; j++)
|
|
||||||
{
|
|
||||||
XIAnyClassInfo* class_info = *((XIAnyClassInfo**)d.DeviceInfo.classes + j);
|
|
||||||
switch (class_info->type)
|
|
||||||
{
|
|
||||||
case XIClassType.Button:
|
|
||||||
{
|
|
||||||
XIButtonClassInfo* button = (XIButtonClassInfo*)class_info;
|
|
||||||
Debug.Print("\t{0} buttons", button->num_buttons);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XIClassType.Scroll:
|
|
||||||
{
|
|
||||||
XIScrollClassInfo* scroll = (XIScrollClassInfo*)class_info;
|
|
||||||
switch (scroll->scroll_type)
|
|
||||||
{
|
|
||||||
case XIScrollType.Vertical:
|
|
||||||
Debug.WriteLine("\tSmooth vertical scrolling");
|
|
||||||
d.ScrollY = *scroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XIScrollType.Horizontal:
|
|
||||||
Debug.WriteLine("\tSmooth horizontal scrolling");
|
|
||||||
d.ScrollX = *scroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Debug.Print("\tUnknown scrolling type {0}", scroll->scroll_type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XIClassType.Valuator:
|
|
||||||
{
|
|
||||||
XIValuatorClassInfo* valuator = (XIValuatorClassInfo*)class_info;
|
|
||||||
if (valuator->label == RelX)
|
|
||||||
{
|
|
||||||
Debug.WriteLine("\tRelative X movement");
|
|
||||||
d.MotionX = *valuator;
|
|
||||||
}
|
|
||||||
else if (valuator->label == RelY)
|
|
||||||
{
|
|
||||||
Debug.WriteLine("\tRelative Y movement");
|
|
||||||
d.MotionY = *valuator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map the hardware device id to the current XIMouse id
|
|
||||||
if (!rawids.ContainsKey(d.DeviceInfo.deviceid))
|
|
||||||
{
|
|
||||||
rawids.Add(d.DeviceInfo.deviceid, 0);
|
|
||||||
}
|
|
||||||
rawids[d.DeviceInfo.deviceid] = i;
|
|
||||||
}
|
}
|
||||||
XI.FreeDeviceInfo((IntPtr)list);
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyboardState IKeyboardDriver2.GetState(int index)
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < keyboards.Count)
|
||||||
|
{
|
||||||
|
return keyboards[index].State;
|
||||||
|
}
|
||||||
|
return new KeyboardState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string IKeyboardDriver2.GetDeviceName(int index)
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < keyboards.Count)
|
||||||
|
{
|
||||||
|
return keyboards[index].Name;
|
||||||
|
}
|
||||||
|
return String.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IMouseDriver2 Members
|
#region IMouseDriver2 Members
|
||||||
|
|
||||||
public MouseState GetState()
|
MouseState IMouseDriver2.GetState()
|
||||||
{
|
{
|
||||||
MouseState master = new MouseState();
|
lock (Sync)
|
||||||
foreach (var d in devices)
|
|
||||||
{
|
{
|
||||||
master.MergeBits(d.State);
|
MouseState master = new MouseState();
|
||||||
|
foreach (var d in devices)
|
||||||
|
{
|
||||||
|
master.MergeBits(d.State);
|
||||||
|
}
|
||||||
|
return master;
|
||||||
}
|
}
|
||||||
return master;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MouseState GetState(int index)
|
MouseState IMouseDriver2.GetState(int index)
|
||||||
{
|
{
|
||||||
if (devices.Count > index)
|
lock (Sync)
|
||||||
return devices[index].State;
|
{
|
||||||
else
|
if (index >= 0 && index < devices.Count)
|
||||||
|
{
|
||||||
|
return devices[index].State;
|
||||||
|
}
|
||||||
return new MouseState();
|
return new MouseState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MouseState GetCursorState()
|
MouseState IMouseDriver2.GetCursorState()
|
||||||
{
|
{
|
||||||
MouseState master = GetState();
|
lock (Sync)
|
||||||
master.X = (int)Interlocked.Read(ref cursor_x);
|
{
|
||||||
master.Y = (int)Interlocked.Read(ref cursor_y);
|
MouseState master = (this as IMouseDriver2).GetState();
|
||||||
return master;
|
master.X = (int)Interlocked.Read(ref cursor_x);
|
||||||
|
master.Y = (int)Interlocked.Read(ref cursor_y);
|
||||||
|
return master;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPosition(double x, double y)
|
void IMouseDriver2.SetPosition(double x, double y)
|
||||||
{
|
{
|
||||||
|
// Note: we cannot use window.Display here, because
|
||||||
|
// that will deadlock the input thread, which is
|
||||||
|
// blocking inside XIfEvent
|
||||||
using (new XLock(API.DefaultDisplay))
|
using (new XLock(API.DefaultDisplay))
|
||||||
{
|
{
|
||||||
Functions.XWarpPointer(API.DefaultDisplay,
|
Functions.XWarpPointer(API.DefaultDisplay,
|
||||||
IntPtr.Zero, window.RootWindow, 0, 0, 0, 0, (int)x, (int)y);
|
IntPtr.Zero, window.RootWindow, 0, 0, 0, 0, (int)x, (int)y);
|
||||||
|
Functions.XFlush(API.DefaultDisplay);
|
||||||
Interlocked.Exchange(ref cursor_x, (long)x);
|
Interlocked.Exchange(ref cursor_x, (long)x);
|
||||||
Interlocked.Exchange(ref cursor_y, (long)y);
|
Interlocked.Exchange(ref cursor_y, (long)y);
|
||||||
}
|
}
|
||||||
|
@ -309,6 +292,127 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
void UpdateDevices()
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
|
devices.Clear();
|
||||||
|
keyboards.Clear();
|
||||||
|
|
||||||
|
int count;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
XIDeviceInfo* list = (XIDeviceInfo*)XI.QueryDevice(window.Display,
|
||||||
|
XI.XIAllDevices, out count);
|
||||||
|
|
||||||
|
Debug.Print("Refreshing input device list");
|
||||||
|
Debug.Print("{0} input devices detected", count);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
switch ((list + i)->use)
|
||||||
|
{
|
||||||
|
case XIDeviceType.MasterKeyboard:
|
||||||
|
//case XIDeviceType.SlaveKeyboard:
|
||||||
|
{
|
||||||
|
XIKeyboard k = new XIKeyboard();
|
||||||
|
k.DeviceInfo = *(list + i);
|
||||||
|
k.State.SetIsConnected(k.DeviceInfo.enabled);
|
||||||
|
k.Name = Marshal.PtrToStringAnsi(k.DeviceInfo.name);
|
||||||
|
int id = k.DeviceInfo.deviceid;
|
||||||
|
if (!keyboard_ids.ContainsKey(id))
|
||||||
|
{
|
||||||
|
keyboard_ids.Add(k.DeviceInfo.deviceid, 0);
|
||||||
|
}
|
||||||
|
keyboard_ids[id] = keyboards.Count;
|
||||||
|
keyboards.Add(k);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XIDeviceType.MasterPointer:
|
||||||
|
//case XIDeviceType.SlavePointer:
|
||||||
|
case XIDeviceType.FloatingSlave:
|
||||||
|
{
|
||||||
|
XIMouse d = new XIMouse();
|
||||||
|
d.DeviceInfo = *(list + i);
|
||||||
|
|
||||||
|
d.State.SetIsConnected(d.DeviceInfo.enabled);
|
||||||
|
d.Name = Marshal.PtrToStringAnsi(d.DeviceInfo.name);
|
||||||
|
Debug.Print("Device {0} \"{1}\" is {2} and has:",
|
||||||
|
i, d.Name, d.DeviceInfo.enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
// Decode the XIDeviceInfo to axes, buttons and scroll types
|
||||||
|
for (int j = 0; j < d.DeviceInfo.num_classes; j++)
|
||||||
|
{
|
||||||
|
XIAnyClassInfo* class_info = *((XIAnyClassInfo**)d.DeviceInfo.classes + j);
|
||||||
|
switch (class_info->type)
|
||||||
|
{
|
||||||
|
case XIClassType.Button:
|
||||||
|
{
|
||||||
|
XIButtonClassInfo* button = (XIButtonClassInfo*)class_info;
|
||||||
|
Debug.Print("\t{0} buttons", button->num_buttons);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XIClassType.Scroll:
|
||||||
|
{
|
||||||
|
XIScrollClassInfo* scroll = (XIScrollClassInfo*)class_info;
|
||||||
|
switch (scroll->scroll_type)
|
||||||
|
{
|
||||||
|
case XIScrollType.Vertical:
|
||||||
|
Debug.WriteLine("\tSmooth vertical scrolling");
|
||||||
|
d.ScrollY = *scroll;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XIScrollType.Horizontal:
|
||||||
|
Debug.WriteLine("\tSmooth horizontal scrolling");
|
||||||
|
d.ScrollX = *scroll;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Debug.Print("\tUnknown scrolling type {0}", scroll->scroll_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XIClassType.Valuator:
|
||||||
|
{
|
||||||
|
XIValuatorClassInfo* valuator = (XIValuatorClassInfo*)class_info;
|
||||||
|
if (valuator->label == RelX)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("\tRelative X movement");
|
||||||
|
d.MotionX = *valuator;
|
||||||
|
}
|
||||||
|
else if (valuator->label == RelY)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("\tRelative Y movement");
|
||||||
|
d.MotionY = *valuator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the hardware device id to the current XIMouse id
|
||||||
|
int id = d.DeviceInfo.deviceid;
|
||||||
|
if (!rawids.ContainsKey(id))
|
||||||
|
{
|
||||||
|
rawids.Add(id, 0);
|
||||||
|
}
|
||||||
|
rawids[id] = devices.Count;
|
||||||
|
devices.Add(d);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XI.FreeDeviceInfo((IntPtr)list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessEvents()
|
void ProcessEvents()
|
||||||
{
|
{
|
||||||
while (!disposed)
|
while (!disposed)
|
||||||
|
@ -341,6 +445,8 @@ namespace OpenTK.Platform.X11
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case XIEventType.RawKeyPress:
|
||||||
|
case XIEventType.RawKeyRelease:
|
||||||
case XIEventType.RawMotion:
|
case XIEventType.RawMotion:
|
||||||
case XIEventType.RawButtonPress:
|
case XIEventType.RawButtonPress:
|
||||||
case XIEventType.RawButtonRelease:
|
case XIEventType.RawButtonRelease:
|
||||||
|
@ -360,59 +466,73 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
void ProcessRawEvent(ref XGenericEventCookie cookie)
|
void ProcessRawEvent(ref XGenericEventCookie cookie)
|
||||||
{
|
{
|
||||||
unsafe
|
lock (Sync)
|
||||||
{
|
{
|
||||||
XIRawEvent raw = *(XIRawEvent*)cookie.data;
|
unsafe
|
||||||
|
|
||||||
if (!rawids.ContainsKey(raw.deviceid))
|
|
||||||
{
|
{
|
||||||
Debug.Print("Unknown mouse device {0} encountered, ignoring.", raw.deviceid);
|
XIRawEvent raw = *(XIRawEvent*)cookie.data;
|
||||||
return;
|
XIMouse mouse;
|
||||||
}
|
XIKeyboard keyboard;
|
||||||
|
|
||||||
var d = devices[rawids[raw.deviceid]];
|
switch (raw.evtype)
|
||||||
|
{
|
||||||
|
case XIEventType.RawMotion:
|
||||||
|
if (GetMouseDevice(raw.deviceid, out mouse))
|
||||||
|
{
|
||||||
|
ProcessRawMotion(mouse, ref raw);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
switch (raw.evtype)
|
case XIEventType.RawButtonPress:
|
||||||
{
|
case XIEventType.RawButtonRelease:
|
||||||
case XIEventType.RawMotion:
|
if (GetMouseDevice(raw.deviceid, out mouse))
|
||||||
ProcessRawMotion(d, ref raw);
|
{
|
||||||
break;
|
float dx, dy;
|
||||||
|
MouseButton button = X11KeyMap.TranslateButton(raw.detail, out dx, out dy);
|
||||||
|
mouse.State[button] = raw.evtype == XIEventType.RawButtonPress;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case XIEventType.RawButtonPress:
|
case XIEventType.RawKeyPress:
|
||||||
switch (raw.detail)
|
case XIEventType.RawKeyRelease:
|
||||||
{
|
if (GetKeyboardDevice(raw.deviceid, out keyboard))
|
||||||
case 1: d.State.EnableBit((int)MouseButton.Left); break;
|
{
|
||||||
case 2: d.State.EnableBit((int)MouseButton.Middle); break;
|
Key key;
|
||||||
case 3: d.State.EnableBit((int)MouseButton.Right); break;
|
if (KeyMap.TranslateKey(raw.detail, out key))
|
||||||
case 8: d.State.EnableBit((int)MouseButton.Button1); break;
|
{
|
||||||
case 9: d.State.EnableBit((int)MouseButton.Button2); break;
|
keyboard.State[key] = raw.evtype == XIEventType.RawKeyPress;
|
||||||
case 10: d.State.EnableBit((int)MouseButton.Button3); break;
|
}
|
||||||
case 11: d.State.EnableBit((int)MouseButton.Button4); break;
|
}
|
||||||
case 12: d.State.EnableBit((int)MouseButton.Button5); break;
|
break;
|
||||||
case 13: d.State.EnableBit((int)MouseButton.Button6); break;
|
}
|
||||||
case 14: d.State.EnableBit((int)MouseButton.Button7); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XIEventType.RawButtonRelease:
|
|
||||||
switch (raw.detail)
|
|
||||||
{
|
|
||||||
case 1: d.State.DisableBit((int)MouseButton.Left); break;
|
|
||||||
case 2: d.State.DisableBit((int)MouseButton.Middle); break;
|
|
||||||
case 3: d.State.DisableBit((int)MouseButton.Right); break;
|
|
||||||
case 8: d.State.DisableBit((int)MouseButton.Button1); break;
|
|
||||||
case 9: d.State.DisableBit((int)MouseButton.Button2); break;
|
|
||||||
case 10: d.State.DisableBit((int)MouseButton.Button3); break;
|
|
||||||
case 11: d.State.DisableBit((int)MouseButton.Button4); break;
|
|
||||||
case 12: d.State.DisableBit((int)MouseButton.Button5); break;
|
|
||||||
case 13: d.State.DisableBit((int)MouseButton.Button6); break;
|
|
||||||
case 14: d.State.DisableBit((int)MouseButton.Button7); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetMouseDevice(int deviceid, out XIMouse mouse)
|
||||||
|
{
|
||||||
|
if (!rawids.ContainsKey(deviceid))
|
||||||
|
{
|
||||||
|
Debug.Print("Unknown mouse device {0} encountered, ignoring.", deviceid);
|
||||||
|
mouse = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mouse = devices[rawids[deviceid]];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetKeyboardDevice(int deviceid, out XIKeyboard keyboard)
|
||||||
|
{
|
||||||
|
if (!keyboard_ids.ContainsKey(deviceid))
|
||||||
|
{
|
||||||
|
Debug.Print("Unknown keyboard device {0} encountered, ignoring.", deviceid);
|
||||||
|
keyboard = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
keyboard = keyboards[keyboard_ids[deviceid]];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
unsafe static void ProcessRawMotion(XIMouse d, ref XIRawEvent raw)
|
unsafe static void ProcessRawMotion(XIMouse d, ref XIRawEvent raw)
|
||||||
{
|
{
|
||||||
// Note: we use the raw values here, without pointer
|
// Note: we use the raw values here, without pointer
|
||||||
|
@ -453,6 +573,8 @@ namespace OpenTK.Platform.X11
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
if ((long)e.GenericEventCookie.extension == arg.ToInt64())
|
if ((long)e.GenericEventCookie.extension == arg.ToInt64())
|
||||||
{
|
{
|
||||||
|
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawKeyPress;
|
||||||
|
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawKeyRelease;
|
||||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawMotion;
|
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawMotion;
|
||||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawButtonPress;
|
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawButtonPress;
|
||||||
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease;
|
valid |= e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease;
|
||||||
|
@ -470,6 +592,8 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IDisposable Members
|
#region IDisposable Members
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -496,7 +620,7 @@ namespace OpenTK.Platform.X11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~XI2Mouse()
|
~XI2MouseKeyboard()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
Loading…
Reference in a new issue