#region License // // NativeWindowBase.cs // // Author: // Stefanos A. // // Copyright (c) 2006-2014 Stefanos Apostolopoulos // // 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.ComponentModel; using System.Diagnostics; using System.Drawing; using OpenTK.Input; namespace OpenTK.Platform { // Common base class for all INativeWindow implementations abstract class NativeWindowBase : INativeWindow { readonly LegacyInputDriver LegacyInputDriver; readonly MouseButtonEventArgs MouseDownArgs = new MouseButtonEventArgs(); readonly MouseButtonEventArgs MouseUpArgs = new MouseButtonEventArgs(); readonly MouseMoveEventArgs MouseMoveArgs = new MouseMoveEventArgs(); readonly MouseWheelEventArgs MouseWheelArgs = new MouseWheelEventArgs(); readonly KeyboardKeyEventArgs KeyDownArgs = new KeyboardKeyEventArgs(); readonly KeyboardKeyEventArgs KeyUpArgs = new KeyboardKeyEventArgs(); readonly KeyPressEventArgs KeyPressArgs = new KeyPressEventArgs((char)0); // In order to simplify mouse event implementation, // we can store the current mouse state here. protected MouseState MouseState = new MouseState(); protected KeyboardState KeyboardState = new KeyboardState(); MouseState PreviousMouseState = new MouseState(); internal NativeWindowBase() { LegacyInputDriver = new LegacyInputDriver(this); MouseState.SetIsConnected(true); KeyboardState.SetIsConnected(true); PreviousMouseState.SetIsConnected(true); } #region Protected Members protected void OnMove(EventArgs e) { Move(this, e); } protected void OnResize(EventArgs e) { Resize(this, e); } protected void OnClosing(CancelEventArgs e) { Closing(this, e); } protected void OnClosed(EventArgs e) { Closed(this, e); } protected void OnDisposed(EventArgs e) { Disposed(this, e); } protected void OnIconChanged(EventArgs e) { IconChanged(this, e); } protected void OnTitleChanged(EventArgs e) { TitleChanged(this, e); } protected void OnVisibleChanged(EventArgs e) { VisibleChanged(this, e); } protected void OnFocusedChanged(EventArgs e) { FocusedChanged(this, e); } protected void OnWindowBorderChanged(EventArgs e) { WindowBorderChanged(this, e); } protected void OnWindowStateChanged(EventArgs e) { WindowStateChanged(this, e); } protected void OnKeyDown(Key key, bool repeat) { KeyboardState.SetKeyState(key, true); var e = KeyDownArgs; e.Keyboard = KeyboardState; e.Key = key; e.IsRepeat = repeat; KeyDown(this, e); } protected void OnKeyPress(char c) { var e = KeyPressArgs; e.KeyChar = c; KeyPress(this, e); } protected void OnKeyUp(Key key) { KeyboardState.SetKeyState(key, false); var e = KeyUpArgs; e.Keyboard = KeyboardState; e.Key = key; e.IsRepeat = false; KeyUp(this, e); } /// \internal /// /// Call this method to simulate KeyDown/KeyUp events /// on platforms that do not generate key events for /// modifier flags (e.g. Mac/Cocoa). /// Note: this method does not distinguish between the /// left and right variants of modifier keys. /// /// Mods. protected void UpdateModifierFlags(KeyModifiers mods) { bool alt = (mods & KeyModifiers.Alt) != 0; bool control = (mods & KeyModifiers.Control) != 0; bool shift = (mods & KeyModifiers.Shift) != 0; if (alt) { OnKeyDown(Key.AltLeft, KeyboardState[Key.AltLeft]); OnKeyDown(Key.AltRight, KeyboardState[Key.AltLeft]); } else { if (KeyboardState[Key.AltLeft]) { OnKeyUp(Key.AltLeft); } if (KeyboardState[Key.AltRight]) { OnKeyUp(Key.AltRight); } } if (control) { OnKeyDown(Key.ControlLeft, KeyboardState[Key.AltLeft]); OnKeyDown(Key.ControlRight, KeyboardState[Key.AltLeft]); } else { if (KeyboardState[Key.ControlLeft]) { OnKeyUp(Key.ControlLeft); } if (KeyboardState[Key.ControlRight]) { OnKeyUp(Key.ControlRight); } } if (shift) { OnKeyDown(Key.ShiftLeft, KeyboardState[Key.AltLeft]); OnKeyDown(Key.ShiftRight, KeyboardState[Key.AltLeft]); } else { if (KeyboardState[Key.ShiftLeft]) { OnKeyUp(Key.ShiftLeft); } if (KeyboardState[Key.ShiftRight]) { OnKeyUp(Key.ShiftRight); } } } protected void OnMouseLeave(EventArgs e) { MouseLeave(this, e); } protected void OnMouseEnter(EventArgs e) { MouseEnter(this, e); } protected void OnMouseDown(MouseButton button) { MouseState[button] = true; var e = MouseDownArgs; e.Mouse = MouseState; MouseDown(this, e); } protected void OnMouseUp(MouseButton button) { MouseState[button] = false; var e = MouseUpArgs; e.Mouse = MouseState; MouseUp(this, e); } protected void OnMouseMove(int x, int y) { MouseState.X = x; MouseState.Y = y; var e = MouseMoveArgs; e.Mouse = MouseState; e.XDelta = MouseState.X - PreviousMouseState.X; e.YDelta = MouseState.Y - PreviousMouseState.Y; if (e.XDelta == 0 && e.YDelta == 0) { Debug.WriteLine("OnMouseMove called without moving the mouse"); return; } PreviousMouseState = MouseState; MouseMove(this, e); } protected void OnMouseWheel(float dx, float dy) { MouseState.SetScrollRelative(dx, dy); var e = MouseWheelArgs; e.Mouse = MouseState; e.DeltaPrecise = MouseState.Scroll.Y - PreviousMouseState.Scroll.Y; if (dx == 0 && dy == 0) { Debug.WriteLine("OnMouseWheel called without moving the mouse wheel."); return; } PreviousMouseState = MouseState; MouseWheel(this, e); } #endregion #region INativeWindow Members public event EventHandler Move = delegate { }; public event EventHandler Resize = delegate { }; public event EventHandler Closing = delegate { }; public event EventHandler Closed = delegate { }; public event EventHandler Disposed = delegate { }; public event EventHandler IconChanged = delegate { }; public event EventHandler TitleChanged = delegate { }; public event EventHandler VisibleChanged = delegate { }; public event EventHandler FocusedChanged = delegate { }; public event EventHandler WindowBorderChanged = delegate { }; public event EventHandler WindowStateChanged = delegate { }; public event EventHandler KeyDown = delegate { }; public event EventHandler KeyPress = delegate { }; public event EventHandler KeyUp = delegate { }; public event EventHandler MouseLeave = delegate { }; public event EventHandler MouseEnter = delegate { }; public event EventHandler MouseDown = delegate { }; public event EventHandler MouseUp = delegate { }; public event EventHandler MouseMove = delegate { }; public event EventHandler MouseWheel = delegate { }; public abstract void Close(); public virtual void ProcessEvents() { if (!Focused) { // Clear keyboard state, otherwise KeyUp // events may be missed resulting in stuck // keys. for (Key key = 0; key < Key.LastKey; key++) { if (KeyboardState[key]) { OnKeyUp(key); } } } } public abstract Point PointToClient(Point point); public abstract Point PointToScreen(Point point); public abstract Icon Icon { get; set; } public abstract string Title { get; set; } public abstract bool Focused { get; } public abstract bool Visible { get; set; } public abstract bool Exists { get; } public abstract IWindowInfo WindowInfo { get; } public abstract WindowState WindowState { get; set; } public abstract WindowBorder WindowBorder { get; set; } public abstract Rectangle Bounds { get; set; } public virtual Point Location { get { return Bounds.Location; } set { Bounds = new Rectangle(value, Bounds.Size); } } public virtual Size Size { get { return Bounds.Size; } set { Bounds = new Rectangle(Bounds.Location, value); } } public int X { get { return Bounds.X; } set { Rectangle old = Bounds; Bounds = new Rectangle(value, old.Y, old.Width, old.Height); } } public int Y { get { return Bounds.Y; } set { Rectangle old = Bounds; Bounds = new Rectangle(old.X, value, old.Width, old.Height); } } public int Width { get { return ClientSize.Width; } set { Rectangle old = ClientRectangle; ClientRectangle = new Rectangle(old.X, old.Y, value, old.Height); } } public int Height { get { return ClientSize.Height; } set { Rectangle old = ClientRectangle; Bounds = new Rectangle(old.X, old.Y, old.Width, value); } } public Rectangle ClientRectangle { get { return new Rectangle(Point.Empty, ClientSize); } set { ClientSize = value.Size; } } public abstract Size ClientSize { get; set; } public virtual IInputDriver InputDriver { get { return LegacyInputDriver; } } public abstract bool CursorVisible { get; set; } public abstract MouseCursor Cursor { get; set; } #endregion #region IDisposable Members public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected abstract void Dispose(bool disposing); ~NativeWindowBase() { Debug.Print("NativeWindowBase leaked, did you forget to call Dispose()?"); Dispose(false); } #endregion } }