From f30e7f6df8951bb2fe93461a8d6e5f42db505f76 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 6 Aug 2007 09:22:04 +0000 Subject: [PATCH] Major updates to shutdown sequence (should correct bug where GameWindow hangs on exit). Enhanced the IGameWindow interface by adding the Keyboard and IsExiting properties. Fully implemented keyboard on X11. Renamed some OpenTK keys. --- Source/OpenTK/GameWindow.cs | 128 ++++++++++++------ Source/OpenTK/Input/Keyboard.cs | 2 +- Source/OpenTK/Platform/IGameWindow.cs | 3 + Source/OpenTK/Platform/INativeGLWindow.cs | 2 +- Source/OpenTK/Platform/Windows/WinGLNative.cs | 25 ++-- .../OpenTK/Platform/Windows/WinRawKeyboard.cs | 2 +- Source/OpenTK/Platform/X11/X11GLNative.cs | 31 ++--- Source/OpenTK/Platform/X11/X11Input.cs | 31 ----- Source/OpenTK/Platform/X11/X11Keyboard.cs | 92 ++++++------- 9 files changed, 157 insertions(+), 159 deletions(-) diff --git a/Source/OpenTK/GameWindow.cs b/Source/OpenTK/GameWindow.cs index d08839fb..5465446d 100644 --- a/Source/OpenTK/GameWindow.cs +++ b/Source/OpenTK/GameWindow.cs @@ -10,6 +10,8 @@ using System.Text; using System.Diagnostics; using OpenTK.Platform; +using OpenTK.Input; +using System.Threading; namespace OpenTK { @@ -23,6 +25,9 @@ namespace OpenTK private InputDriver driver; + private bool isExiting; + private bool disposed; + #endregion #region --- Contructors --- @@ -70,38 +75,10 @@ namespace OpenTK #endregion - #region --- Public Properties --- - - #region public IList Keyboard - - /// - /// Gets the list of available Keyboard devices. - /// - public IList Keyboard - { - get - { - return InputDriver.Keyboard; - } - } - - #endregion + #region --- Internal Properties --- #region public IList Input - /// - /// Gets the list of available InputDevices. - /// - public IList Input - { - get - { - return InputDriver.InputDevices; - } - } - - #endregion - internal InputDriver InputDriver { get @@ -117,6 +94,8 @@ namespace OpenTK #endregion + #endregion + #region --- INativeGLWindow Members --- #region public void CreateWindow(DisplayMode mode) @@ -128,7 +107,7 @@ namespace OpenTK /// Occurs when a render window already exists. public void CreateWindow(DisplayMode mode) { - if (!Created) + if (!Exists) { glWindow.CreateWindow(mode); } @@ -144,10 +123,15 @@ namespace OpenTK /// /// Gracefully exits the current GameWindow. + /// Override if you want to provide yor own exit sequence. + /// If you override this method, place a call to base.Exit(), to ensure + /// proper OpenTK shutdown. /// - public void Exit() + public virtual void Exit() { - glWindow.Exit(); + isExiting = true; + //glWindow.Exit(); + //this.Dispose(); } #endregion @@ -202,7 +186,7 @@ namespace OpenTK { get { - if (!glWindow.Created) + if (!glWindow.Exists) { Debug.WriteLine("WARNING: OpenGL Context accessed before creating a render window. This may indicate a programming error. Force-creating a render window."); mode = new DisplayMode(640, 480); @@ -214,14 +198,14 @@ namespace OpenTK #endregion - #region public bool Created + #region public bool Exists /// - /// Gets a value indicating whether a render window has been created. + /// Gets a value indicating whether a render window has been exists. /// - public bool Created + public bool Exists { - get { return glWindow.Created; } + get { return glWindow.Exists; } } #endregion @@ -258,12 +242,18 @@ namespace OpenTK /// public virtual void Run() { - while (!this.Quit) + while (!this.Quit && !IsExiting) { this.ProcessEvents(); this.OnUpdateFrame(); this.OnRenderFrame(); } + + glWindow.Exit(); + while (glWindow.Exists) + { + this.ProcessEvents(); + } } #endregion @@ -315,7 +305,7 @@ namespace OpenTK /// public virtual void OnRenderFrame() { - if (!this.Created) + if (!this.Exists) { Debug.Print("WARNING: RenderFrame event raised, without a valid render window. This may indicate a programming error. Creating render window."); mode = new DisplayMode(640, 480); @@ -338,7 +328,7 @@ namespace OpenTK /// public virtual void OnUpdateFrame() { - if (!this.Created) + if (!this.Exists) { Debug.Print("WARNING: UpdateFrame event raised, without a valid render window. This may indicate a programming error. Creating render window."); mode = new DisplayMode(640, 480); @@ -360,6 +350,36 @@ namespace OpenTK /// public event RenderFrameEvent RenderFrame; + #region public bool IsExiting + + /// + /// Gets a value indicating whether the shutdown sequence has been initiated + /// for this window, by calling GameWindow.Exit() or hitting the 'close' button. + /// If this property is true, it is no longer safe to use any OpenTK.Input or + /// OpenTK.OpenGL functions or properties. + /// + public bool IsExiting + { + get { return isExiting; } + } + + #endregion + + #region public IList Keyboard + + /// + /// Gets the list of available Keyboard devices. + /// + public IList Keyboard + { + get + { + return InputDriver.Keyboard; + } + } + + #endregion + #endregion #region --- IResizable Members --- @@ -438,8 +458,32 @@ namespace OpenTK public void Dispose() { - glWindow.Dispose(); - glWindow = null; + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manual) + { + if (!disposed) + { + // Is this safe? Maybe 'Debug' has been disposed, too... + Debug.Print("{0} disposing GameWindow.", manual ? "Manually" : "Automatically"); + + if (manual) + { + if (glWindow != null) + { + glWindow.Dispose(); + glWindow = null; + } + } + disposed = true; + } + } + + ~GameWindow() + { + Dispose(false); } #endregion diff --git a/Source/OpenTK/Input/Keyboard.cs b/Source/OpenTK/Input/Keyboard.cs index bfc9f0df..b9b070c9 100644 --- a/Source/OpenTK/Input/Keyboard.cs +++ b/Source/OpenTK/Input/Keyboard.cs @@ -141,7 +141,7 @@ namespace OpenTK.Input Escape, Space, Tab, - Backspace, + BackSpace, Insert, Delete, PageUp, diff --git a/Source/OpenTK/Platform/IGameWindow.cs b/Source/OpenTK/Platform/IGameWindow.cs index b3c8a6dd..fbf4d917 100644 --- a/Source/OpenTK/Platform/IGameWindow.cs +++ b/Source/OpenTK/Platform/IGameWindow.cs @@ -14,6 +14,9 @@ namespace OpenTK.Platform event UpdateFrameEvent UpdateFrame; event RenderFrameEvent RenderFrame; + + bool IsExiting { get; } + IList Keyboard { get; } } public delegate void UpdateFrameEvent(EventArgs e); diff --git a/Source/OpenTK/Platform/INativeGLWindow.cs b/Source/OpenTK/Platform/INativeGLWindow.cs index a4d07a00..febbb819 100644 --- a/Source/OpenTK/Platform/INativeGLWindow.cs +++ b/Source/OpenTK/Platform/INativeGLWindow.cs @@ -13,7 +13,7 @@ namespace OpenTK.Platform void ProcessEvents(); void Exit(); - bool Created { get; } + bool Exists { get; } bool Quit { get; } IWindowInfo WindowInfo { get; } } diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index dc20cfac..7b3a6ad4 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -31,7 +31,7 @@ namespace OpenTK.Platform.Windows private bool fullscreen = false; private bool disposed; private bool quit; - private bool created; + private bool exists; private WindowInfo info; #endregion @@ -94,27 +94,18 @@ namespace OpenTK.Platform.Windows // Raise the Create event this.OnCreate(EventArgs.Empty); - - // Raise the resize event: - //resizeEventArgs.Width = width; - //resizeEventArgs.Height = height; - //this.OnResize(resizeEventArgs); return; - //case API.Constants.WM_KEYDOWN: // Legacy input events - //case API.Constants.WM_KEYUP: - // break; - case API.Constants.WM_CLOSE: - //this.Exit(); - //return; - break; + this.Exit(); + return; case API.Constants.WM_DESTROY: if (this.Handle != IntPtr.Zero) { Debug.Print("Window handle {0} destroyed.", this.Handle); this.DestroyHandle(); + exists = false; } API.PostQuitMessage(0); return; @@ -174,7 +165,7 @@ namespace OpenTK.Platform.Windows if (this.Handle != IntPtr.Zero && glContext != null) { Debug.WriteLine("Window creation was succesful."); - created = true; + exists = true; } else { @@ -281,14 +272,14 @@ namespace OpenTK.Platform.Windows #endregion - #region public bool Created + #region public bool Exists /// /// Returns true if a render window/context exists. /// - public bool Created + public bool Exists { - get { return created; } + get { return exists; } } #endregion diff --git a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs index 74398dac..ce723f51 100644 --- a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs +++ b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs @@ -71,7 +71,7 @@ namespace OpenTK.Platform.Windows KeyMap.Add(API.VirtualKeys.RCONTROL, Input.Key.ControlRight); KeyMap.Add(API.VirtualKeys.RSHIFT, Input.Key.ShiftRight); KeyMap.Add(API.VirtualKeys.RETURN, Input.Key.Enter); - KeyMap.Add(API.VirtualKeys.BACK, Input.Key.Backspace); + KeyMap.Add(API.VirtualKeys.BACK, Input.Key.BackSpace); KeyMap.Add(API.VirtualKeys.OEM_1, Input.Key.Semicolon); // Varies by keyboard, ;: on Win2K/US KeyMap.Add(API.VirtualKeys.OEM_2, Input.Key.Slash); // Varies by keyboard, /? on Win2K/US diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 6b6f2e6c..43605f26 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -103,7 +103,7 @@ namespace OpenTK.Platform.X11 XSetWindowAttributes attributes = new XSetWindowAttributes(); attributes.colormap = glContext.colormap; - attributes.event_mask = (IntPtr)(EventMask.StructureNotifyMask); + attributes.event_mask = (IntPtr)(EventMask.StructureNotifyMask | EventMask.ExposureMask); SetWindowValuemask mask = SetWindowValuemask.ColorMap | SetWindowValuemask.EventMask; @@ -163,13 +163,12 @@ namespace OpenTK.Platform.X11 public void Exit() { - /*Event e = new Event(); - X11Api.SendEvent( - display, - window, - false, - 0,*/ - //quit = true; + Debug.WriteLine("X11GLNative shutdown sequence initiated."); + quit = true; + Functions.XDestroyWindow(window.Display, window.Handle); + window = null; + glContext.Dispose(); + glContext = null; } #endregion @@ -181,7 +180,6 @@ namespace OpenTK.Platform.X11 // Process all pending events while (true) { - //pending = Functions.XPending(info.Display); pending = Functions.XPending(window.Display); if (pending == 0) @@ -201,15 +199,14 @@ namespace OpenTK.Platform.X11 break; case XEventName.CreateNotify: - // A child was created - nothing to do + // A child was exists - nothing to do break; case XEventName.DestroyNotify: - glContext.Dispose(); - Functions.XDestroyWindow(window.Display, window.Handle); - window = null; - glContext = null; - quit = true; + //glContext.Dispose(); + //window = null; + //glContext = null; + //quit = true; Debug.WriteLine("Window destroyed, shutting down."); break; @@ -257,12 +254,12 @@ namespace OpenTK.Platform.X11 #endregion - #region public bool Created + #region public bool Exists /// /// Returns true if a render window/context exists. /// - public bool Created + public bool Exists { get { return created; } } diff --git a/Source/OpenTK/Platform/X11/X11Input.cs b/Source/OpenTK/Platform/X11/X11Input.cs index 52841cd4..9eb14753 100644 --- a/Source/OpenTK/Platform/X11/X11Input.cs +++ b/Source/OpenTK/Platform/X11/X11Input.cs @@ -126,39 +126,8 @@ namespace OpenTK.Platform.X11 { while (API.CheckMaskEvent(window.Display, EventMask.KeyReleaseMask | EventMask.KeyPressMask, ref e)) { - Debug.Print("Input window received {0} event... ", e.type.ToString()); keyboardDriver.ProcessKeyboardEvent(e.KeyEvent); } - /* - try - { - while (API.CheckIfEvent(window.Display, ref e, check, IntPtr.Zero)) - { - Debug.Print("Input window received {0} event... ", e.type.ToString()); - keyboardDriver.ProcessKeyboardEvent(e.KeyEvent); - } - } - catch (Exception e) - { - Debug.Print("DANGER: Possible callback exception: {0}", e.ToString()); - } - */ - } - - API.CheckEventPredicate check = KeyEventPredicate; - - private static bool KeyEventPredicate(IntPtr display, ref XEvent @event, IntPtr arg) - { - bool ret = false; - try - { - ret = (@event.type == XEventName.KeyRelease || @event.type == XEventName.KeyPress); - } - catch (Exception e) - { - Debug.Print("DANGER: Exception caught during unmanaged callback: {0}", e.ToString()); - } - return ret; } #endregion diff --git a/Source/OpenTK/Platform/X11/X11Keyboard.cs b/Source/OpenTK/Platform/X11/X11Keyboard.cs index c74c4c48..ec8214b1 100644 --- a/Source/OpenTK/Platform/X11/X11Keyboard.cs +++ b/Source/OpenTK/Platform/X11/X11Keyboard.cs @@ -41,6 +41,11 @@ namespace OpenTK.Platform.X11 { if (!keymapExists) { + keymap.Add(XKey.Escape, Key.Escape); + keymap.Add(XKey.Return, Key.Enter); + keymap.Add(XKey.space, Key.Space); + keymap.Add(XKey.BackSpace, Key.BackSpace); + keymap.Add(XKey.Shift_L, Key.ShiftLeft); keymap.Add(XKey.Shift_R, Key.ShiftRight); keymap.Add(XKey.Alt_L, Key.AltLeft); @@ -57,22 +62,21 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.minus, Key.Minus); keymap.Add(XKey.plus, Key.Plus); keymap.Add(XKey.equal, Key.Plus); - //keymap.Add keymap.Add(XKey.Caps_Lock, Key.CapsLock); keymap.Add(XKey.Num_Lock, Key.NumLock); - for (int i = (int)XKey.F1; i < (int)XKey.F35; i++) + for (int i = (int)XKey.F1; i <= (int)XKey.F35; i++) { keymap.Add((XKey)i, (Key)((int)Key.F1 + (i - (int)XKey.F1))); } - for (int i = (int)XKey.a; i < (int)XKey.z; i++) + for (int i = (int)XKey.a; i <= (int)XKey.z; i++) { keymap.Add((XKey)i, (Key)((int)Key.A + (i - (int)XKey.a))); } - for (int i = (int)XKey.A; i < (int)XKey.Z; i++) + for (int i = (int)XKey.A; i <= (int)XKey.Z; i++) { keymap.Add((XKey)i, (Key)((int)Key.A + (i - (int)XKey.A))); } @@ -94,6 +98,8 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.Print, Key.PrintScreen); keymap.Add(XKey.Sys_Req, Key.PrintScreen); + keymap.Add(XKey.backslash, Key.BackSlash); + keymap.Add(XKey.bar, Key.BackSlash); keymap.Add(XKey.braceleft, Key.BracketLeft); keymap.Add(XKey.bracketleft, Key.BracketLeft); keymap.Add(XKey.braceright, Key.BracketRight); @@ -102,6 +108,8 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.semicolon, Key.Semicolon); keymap.Add(XKey.quoteright, Key.Quote); keymap.Add(XKey.quotedbl, Key.Quote); + keymap.Add(XKey.quoteleft, Key.Tilde); + keymap.Add(XKey.asciitilde, Key.Tilde); keymap.Add(XKey.comma, Key.Comma); keymap.Add(XKey.less, Key.Comma); @@ -110,6 +118,35 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.slash, Key.Slash); keymap.Add(XKey.question, Key.Slash); + keymap.Add(XKey.Left, Key.Left); + keymap.Add(XKey.Down, Key.Down); + keymap.Add(XKey.Right, Key.Right); + keymap.Add(XKey.Up, Key.Up); + + keymap.Add(XKey.Delete, Key.Delete); + keymap.Add(XKey.Home, Key.Home); + keymap.Add(XKey.End, Key.End); + //keymap.Add(XKey.Prior, Key.PageUp); // XKey.Prior == XKey.Page_Up + keymap.Add(XKey.Page_Up, Key.PageUp); + keymap.Add(XKey.Page_Down, Key.PageDown); + //keymap.Add(XKey.Next, Key.PageDown); // XKey.Next == XKey.Page_Down + + keymap.Add(XKey.KP_Add, Key.KeypadAdd); + keymap.Add(XKey.KP_Subtract, Key.KeypadSubtract); + keymap.Add(XKey.KP_Multiply, Key.KeypadMultiply); + keymap.Add(XKey.KP_Divide, Key.KeypadDivide); + keymap.Add(XKey.KP_Decimal, Key.KeypadDecimal); + keymap.Add(XKey.KP_Insert, Key.Keypad0); + keymap.Add(XKey.KP_End, Key.Keypad1); + keymap.Add(XKey.KP_Down, Key.Keypad2); + keymap.Add(XKey.KP_Page_Down, Key.Keypad3); + keymap.Add(XKey.KP_Left, Key.Keypad4); + keymap.Add(XKey.KP_Right, Key.Keypad6); + keymap.Add(XKey.KP_Home, Key.Keypad7); + keymap.Add(XKey.KP_Up, Key.Keypad8); + keymap.Add(XKey.KP_Page_Up, Key.Keypad9); + keymap.Add(XKey.KP_Delete, Key.KeypadDecimal); + keymap.Add(XKey.KP_Enter, Key.Enter); keymapExists = true; } @@ -139,6 +176,7 @@ namespace OpenTK.Platform.X11 kb.Description = "Default X11 keyboard"; kb.NumberOfKeys = lastKeyCode - firstKeyCode + 1; keyboards.Add(kb); + Debug.Print("Keyboard added: {0}", kb.ToString()); } #region internal bool ProcessKeyboardEvent(X11.KeyEvent e) @@ -171,55 +209,11 @@ namespace OpenTK.Platform.X11 else { Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.keycode, (XKey)keysym, (XKey)keysym2); + return false; } return true; } - - return false; - /*API.e.keycode - switch (rin.Header.Type) - { - case API.RawInputDeviceType.KEYBOARD: - bool pressed = - rin.Data.Keyboard.Message == API.Constants.WM_KEYDOWN || - rin.Data.Keyboard.Message == API.Constants.WM_SYSKEYDOWN; - - // Generic control, shift, alt keys may be sent instead of left/right. - // It seems you have to explicitly register left/right events. - switch (rin.Data.Keyboard.VKey) - { - case API.VirtualKeys.SHIFT: - keyboards[0][Input.Key.ShiftLeft] = keyboards[0][Input.Key.ShiftRight] = pressed; - return false; - - case API.VirtualKeys.CONTROL: - keyboards[0][Input.Key.ControlLeft] = keyboards[0][Input.Key.ControlRight] = pressed; - return false; - - case API.VirtualKeys.MENU: - keyboards[0][Input.Key.AltLeft] = keyboards[0][Input.Key.AltRight] = pressed; - return false; - - default: - if (!WinRawKeyboard.KeyMap.ContainsKey(rin.Data.Keyboard.VKey)) - { - Debug.Print("Virtual key {0} not mapped.", rin.Data.Keyboard.VKey); - OpenTK.OpenGL.GL.ClearColor(1.0f, 0.3f, 0.3f, 0.0f); - } - else - { - keyboards[0][WinRawKeyboard.KeyMap[rin.Data.Keyboard.VKey]] = pressed; - OpenTK.OpenGL.GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - } - break; - } - break; - - default: - throw new ApplicationException("Windows raw keyboard driver received invalid data."); - } - return false;*/ } #endregion