From e801660ff747ac8a5ae50f78f665f33d01e9e564 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Wed, 20 Oct 2010 14:33:23 +0000 Subject: [PATCH] * Source/OpenTK/OpenTK.csproj: * Source/OpenTK/Input/Keyboard.cs: * Source/OpenTK/Input/InputDriver.cs: * Source/OpenTK/Input/KeyboardState.cs: * Source/OpenTK/Input/IKeyboardDriver.cs: * Source/OpenTK/Platform/X11/X11Input.cs: * Source/OpenTK/Platform/X11/Functions.cs: * Source/OpenTK/Platform/X11/X11Factory.cs: * Source/OpenTK/Platform/Windows/WMInput.cs: * Source/OpenTK/Platform/X11/X11Keyboard.cs: * Source/OpenTK/Platform/MacOS/CarbonInput.cs: * Source/OpenTK/Platform/Windows/WinGLNative.cs: * Source/OpenTK/Platform/Windows/WinRawInput.cs: * Source/OpenTK/Platform/Windows/WinRawKeyboard.cs: Added initial OpenTK.Input.Keyboard implementation for X11. --- Source/OpenTK/Input/IKeyboardDriver.cs | 13 ++ Source/OpenTK/Input/InputDriver.cs | 10 ++ Source/OpenTK/Input/Keyboard.cs | 17 +-- Source/OpenTK/Input/KeyboardState.cs | 63 +++++++-- Source/OpenTK/OpenTK.csproj | 3 +- Source/OpenTK/Platform/MacOS/CarbonInput.cs | 10 ++ Source/OpenTK/Platform/Windows/WMInput.cs | 10 ++ Source/OpenTK/Platform/Windows/WinGLNative.cs | 12 +- Source/OpenTK/Platform/Windows/WinRawInput.cs | 10 ++ .../OpenTK/Platform/Windows/WinRawKeyboard.cs | 10 ++ Source/OpenTK/Platform/X11/Functions.cs | 6 + Source/OpenTK/Platform/X11/X11Factory.cs | 2 +- Source/OpenTK/Platform/X11/X11Input.cs | 10 ++ Source/OpenTK/Platform/X11/X11Keyboard.cs | 131 ++++++++++++++++++ 14 files changed, 277 insertions(+), 30 deletions(-) create mode 100644 Source/OpenTK/Platform/X11/X11Keyboard.cs diff --git a/Source/OpenTK/Input/IKeyboardDriver.cs b/Source/OpenTK/Input/IKeyboardDriver.cs index e14493f9..b2806917 100644 --- a/Source/OpenTK/Input/IKeyboardDriver.cs +++ b/Source/OpenTK/Input/IKeyboardDriver.cs @@ -19,5 +19,18 @@ namespace OpenTK.Input /// Gets the list of available KeyboardDevices. /// IList Keyboard { get; } + + /// + /// Retrieves the KeyboardState for the default keyboard device. + /// + /// A structure containing the state of the keyboard device. + KeyboardState GetState(); + + /// + /// Retrieves the KeyboardState for the specified keyboard device. + /// + /// The index of the keyboard device. + /// A structure containing the state of the keyboard device. + KeyboardState GetState(int index); } } diff --git a/Source/OpenTK/Input/InputDriver.cs b/Source/OpenTK/Input/InputDriver.cs index a1087842..3c3cf5a5 100644 --- a/Source/OpenTK/Input/InputDriver.cs +++ b/Source/OpenTK/Input/InputDriver.cs @@ -73,6 +73,16 @@ namespace OpenTK get { return inputDriver.Keyboard; } } + public KeyboardState GetState() + { + return inputDriver.GetState(); + } + + public KeyboardState GetState(int index) + { + return inputDriver.GetState(index); + } + #endregion #region --- IMouseDriver Members --- diff --git a/Source/OpenTK/Input/Keyboard.cs b/Source/OpenTK/Input/Keyboard.cs index 562d63af..104a92fd 100644 --- a/Source/OpenTK/Input/Keyboard.cs +++ b/Source/OpenTK/Input/Keyboard.cs @@ -38,17 +38,8 @@ namespace OpenTK.Input { #region Fields - //static IKeyboardDriver driver; - - #endregion - - #region Constructors - - static Keyboard() - { - throw new NotImplementedException(); - //driver = Platform.Factory.Default.CreateKeyboardDriver(); - } + static readonly IKeyboardDriver driver = + Platform.Factory.Default.CreateKeyboardDriver(); #endregion @@ -60,7 +51,7 @@ namespace OpenTK.Input /// A structure containing the state of the keyboard device. public static KeyboardState GetState() { - return new KeyboardState(); + return driver.GetState(); } /// @@ -70,7 +61,7 @@ namespace OpenTK.Input /// A structure containing the state of the keyboard device. public static KeyboardState GetState(int index) { - return new KeyboardState(); + return driver.GetState(index); } #endregion diff --git a/Source/OpenTK/Input/KeyboardState.cs b/Source/OpenTK/Input/KeyboardState.cs index f97c7625..9d05a32a 100644 --- a/Source/OpenTK/Input/KeyboardState.cs +++ b/Source/OpenTK/Input/KeyboardState.cs @@ -26,7 +26,7 @@ #endregion using System; -using System.Collections.Generic; +using System.Collections.Specialized; using System.Text; namespace OpenTK.Input @@ -39,9 +39,8 @@ namespace OpenTK.Input #region Fields const int NumKeys = ((int)Key.LastKey + 16) / 32; - // Todo: The following line triggers bogus CS0214 in gmcs 2.0.1, sigh... - // Need to add a workaround using either ExplicitLayout or another trick. - //unsafe fixed int Keys[NumKeys]; + // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh... + unsafe fixed int Keys[NumKeys]; #endregion @@ -57,7 +56,7 @@ namespace OpenTK.Input /// The to check. public bool IsKeyDown(Key key) { - return ReadBit((int)key) != 0; + return ReadBit((int)key); } /// @@ -66,24 +65,50 @@ namespace OpenTK.Input /// The to check. public bool IsKeyUp(Key key) { - return ReadBit((int)key) == 0; + return !ReadBit((int)key); } #endregion #region Internal Members - internal int ReadBit(int offset) + internal bool ReadBit(int offset) { - return 0; - //unsafe { return (Keys[(offset / 32)] & (1 << (offset % 32))); } + int int_offset = offset / 32; + int bit_offset = offset % 32; + unsafe + { + fixed (int* k = Keys) + { + return (*(k + int_offset) & (1 << bit_offset)) != 0u; + } + } } - internal enum BitValue { Zero = 0, One = 1 } - internal void WriteBit(int offset, BitValue bit) + internal void EnableBit(int offset) { - // Todo: this is completely broken. - //unsafe { Keys[offset / 32] = Keys[offset / 32] ^ (~(int)bit << (offset % 32)); } + int int_offset = offset / 32; + int bit_offset = offset % 32; + unsafe + { + fixed (int* k = Keys) + { + *(k + int_offset) |= 1 << bit_offset; + } + } + } + + internal void DisableBit(int offset) + { + int int_offset = offset / 32; + int bit_offset = offset % 32; + unsafe + { + fixed (int* k = Keys) + { + *(k + int_offset) &= ~(1 << bit_offset); + } + } } #endregion @@ -97,7 +122,17 @@ namespace OpenTK.Input /// True, if both instances are equal; false otherwise. public bool Equals(KeyboardState other) { - throw new NotImplementedException(); + bool equal = true; + unsafe + { + fixed (int* k1 = Keys) + fixed (int* k2 = Keys) + { + for (int i = 0; equal && i < NumKeys; i++) + equal &= *(k1 + i) == *(k2 + i); + } + } + return equal; } #endregion diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index dc177639..0510e48d 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -1,4 +1,4 @@ - + Local @@ -756,6 +756,7 @@ Always + diff --git a/Source/OpenTK/Platform/MacOS/CarbonInput.cs b/Source/OpenTK/Platform/MacOS/CarbonInput.cs index b8d08b51..c9c3b997 100644 --- a/Source/OpenTK/Platform/MacOS/CarbonInput.cs +++ b/Source/OpenTK/Platform/MacOS/CarbonInput.cs @@ -35,6 +35,16 @@ namespace OpenTK.Platform.MacOS get { return dummy_keyboard_list; } } + public KeyboardState GetState() + { + throw new NotImplementedException(); + } + + public KeyboardState GetState(int index) + { + throw new NotImplementedException(); + } + #endregion #region IMouseDriver Members diff --git a/Source/OpenTK/Platform/Windows/WMInput.cs b/Source/OpenTK/Platform/Windows/WMInput.cs index 4015170e..d62b9af6 100644 --- a/Source/OpenTK/Platform/Windows/WMInput.cs +++ b/Source/OpenTK/Platform/Windows/WMInput.cs @@ -246,6 +246,16 @@ namespace OpenTK.Platform.Windows get { return keyboards; } } + public KeyboardState GetState() + { + throw new NotImplementedException(); + } + + public KeyboardState GetState(int index) + { + throw new NotImplementedException(); + } + #endregion #region IMouseDriver Members diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index 6c084f62..cffe637b 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -844,7 +844,7 @@ namespace OpenTK.Platform.Windows public bool CursorVisible { - get { return cursor_visible_count > 0; } + get { return cursor_visible_count > 0; } // Not used set { if (value && cursor_visible_count < 0) @@ -1186,6 +1186,16 @@ namespace OpenTK.Platform.Windows get { return keyboards; } } + public KeyboardState GetState() + { + throw new NotImplementedException(); + } + + public KeyboardState GetState(int index) + { + throw new NotImplementedException(); + } + #endregion #region IMouseDriver Members diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index bd815741..3c3ad291 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -207,6 +207,16 @@ namespace OpenTK.Platform.Windows get { return keyboardDriver.Keyboard; } } + public KeyboardState GetState() + { + throw new NotImplementedException(); + } + + public KeyboardState GetState(int index) + { + throw new NotImplementedException(); + } + #endregion #region IMouseDriver Members diff --git a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs index 4bf8b994..b4012dde 100644 --- a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs +++ b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs @@ -237,6 +237,16 @@ namespace OpenTK.Platform.Windows get { return keyboards; } } + public KeyboardState GetState() + { + throw new NotImplementedException(); + } + + public KeyboardState GetState(int index) + { + throw new NotImplementedException(); + } + #endregion #region --- IDisposable Members --- diff --git a/Source/OpenTK/Platform/X11/Functions.cs b/Source/OpenTK/Platform/X11/Functions.cs index 1cbf5f97..88a53e40 100644 --- a/Source/OpenTK/Platform/X11/Functions.cs +++ b/Source/OpenTK/Platform/X11/Functions.cs @@ -176,6 +176,12 @@ namespace OpenTK.Platform.X11 [DllImport("libX11", EntryPoint = "XTranslateCoordinates")] public extern static bool XTranslateCoordinates(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return); + [DllImport("libX11", EntryPoint = "XGrabKeyboard")] + public extern static int XGrabKeyboard(IntPtr display, IntPtr window, bool owner_events, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr timestamp); + + [DllImport("libX11", EntryPoint = "XUngrabKeyboard")] + public extern static int XUngrabKeyboard(IntPtr display, IntPtr timestamp); + [DllImport("libX11", EntryPoint = "XGetGeometry")] public extern static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth); diff --git a/Source/OpenTK/Platform/X11/X11Factory.cs b/Source/OpenTK/Platform/X11/X11Factory.cs index 97ddf3e2..16dbaafe 100644 --- a/Source/OpenTK/Platform/X11/X11Factory.cs +++ b/Source/OpenTK/Platform/X11/X11Factory.cs @@ -80,7 +80,7 @@ namespace OpenTK.Platform.X11 public virtual OpenTK.Input.IKeyboardDriver CreateKeyboardDriver() { - throw new NotImplementedException(); + return new X11Keyboard(null); } #endregion diff --git a/Source/OpenTK/Platform/X11/X11Input.cs b/Source/OpenTK/Platform/X11/X11Input.cs index ae4473b1..b34e0601 100644 --- a/Source/OpenTK/Platform/X11/X11Input.cs +++ b/Source/OpenTK/Platform/X11/X11Input.cs @@ -219,6 +219,16 @@ namespace OpenTK.Platform.X11 get { return dummy_keyboard_list; }//return keyboardDriver.Keyboard; } + public KeyboardState GetState() + { + throw new NotImplementedException(); + } + + public KeyboardState GetState(int index) + { + throw new NotImplementedException(); + } + #endregion #region public IList Mouse diff --git a/Source/OpenTK/Platform/X11/X11Keyboard.cs b/Source/OpenTK/Platform/X11/X11Keyboard.cs new file mode 100644 index 00000000..96422b71 --- /dev/null +++ b/Source/OpenTK/Platform/X11/X11Keyboard.cs @@ -0,0 +1,131 @@ + #region License + // + // The Open Toolkit Library License + // + // Copyright (c) 2006 - 2010 the Open Toolkit library. + // + // 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.Collections.Generic; +using OpenTK.Input; + +namespace OpenTK.Platform.X11 +{ + // Standard keyboard driver that relies on xlib input events. + // Only one keyboard supported. + sealed class X11Keyboard : IKeyboardDriver + { + readonly X11WindowInfo window = new X11WindowInfo(); + readonly X11KeyMap keymap = new X11KeyMap(); + KeyboardState state = new KeyboardState(); + + // Can either attach itself to the specified window or can hook the root window. + public X11Keyboard(X11WindowInfo win) + { + if (win != null) + { + window = win; + } + else + { + using (new XLock(API.DefaultDisplay)) + { + window.Display = API.DefaultDisplay; + window.Screen = Functions.XDefaultScreen(window.Display); + window.RootWindow = Functions.XRootWindow(window.Display, window.Screen); + window.WindowHandle = window.RootWindow; + window.EventMask =EventMask.KeyPressMask | EventMask.KeyReleaseMask | EventMask.KeymapStateMask; + + Functions.XGrabKeyboard(window.Display, window.RootWindow, true, + GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, IntPtr.Zero); + Functions.XSelectInput(window.Display, window.RootWindow, new IntPtr((int)window.EventMask)); + } + } + } + + // Todo: remove this + public IList Keyboard { get { throw new NotSupportedException(); } } + + public KeyboardState GetState() + { + ProcessEvents(); + return state; + } + + public KeyboardState GetState(int index) + { + ProcessEvents(); + return state; + } + + void ProcessEvents() + { + XEvent e = new XEvent(); + + while (true) + { + using (new XLock(window.Display)) + { + if (!Functions.XCheckWindowEvent(window.Display, window.WindowHandle, window.EventMask, ref e)) + break; + + switch (e.type) + { + case XEventName.KeyPress: + case XEventName.KeyRelease: + bool pressed = e.type == XEventName.KeyPress; + + IntPtr keysym = API.LookupKeysym(ref e.KeyEvent, 0); + IntPtr keysym2 = API.LookupKeysym(ref e.KeyEvent, 1); + + if (keymap.ContainsKey((XKey)keysym)) + { + if (pressed) + state.EnableBit((int)keymap[(XKey)keysym]); + else + state.DisableBit((int)keymap[(XKey)keysym]); + } + else if (keymap.ContainsKey((XKey)keysym2)) + { + if (pressed) + state.EnableBit((int)keymap[(XKey)keysym2]); + else + state.DisableBit((int)keymap[(XKey)keysym2]); + } + else + { + System.Diagnostics.Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", + e.KeyEvent.keycode, (XKey)keysym, (XKey)keysym2); + } + break; + + case XEventName.KeymapNotify: + System.Diagnostics.Debug.Print("Keymap event: {0}", e.KeymapEvent.key_vector0); + break; + } + } + } + } + } +} +