int2 EventPosition(Sdl2PlatformWindow device, int x, int y) { // On Windows and Linux (X11) events are given in surface coordinates // These must be scaled to our effective window coordinates if (Platform.CurrentPlatform != PlatformType.OSX && device.WindowSize != device.SurfaceSize) { return(new int2((int)(x / device.WindowScale), (int)(y / device.WindowScale))); } return(new int2(x, y)); }
public Sdl2GraphicsContext(Sdl2PlatformWindow window) { this.window = window; // SDL requires us to create the GL context on the main thread to avoid various platform-specific issues. // We must then release it from the main thread before we rebind it to the render thread (in InitializeOpenGL below). context = SDL.SDL_GL_CreateContext(window.Window); if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window.Window, IntPtr.Zero) < 0) { throw new InvalidOperationException($"Can not create OpenGL context. (Error: {SDL.SDL_GetError()})"); } }
int2 EventPosition(Sdl2PlatformWindow device, int x, int y) { // On Windows and Linux (X11) events are given in surface coordinates // These must be scaled to our effective window coordinates // Round fractional components up to avoid rounding small deltas to 0 if (Platform.CurrentPlatform != PlatformType.OSX && device.EffectiveWindowSize != device.SurfaceSize) { var s = 1 / device.EffectiveWindowScale; return(new int2((int)(Math.Sign(x) / 2f + x * s), (int)(Math.Sign(x) / 2f + y * s))); } // On macOS we must still account for the user-requested scale modifier if (Platform.CurrentPlatform == PlatformType.OSX && device.EffectiveWindowScale != device.NativeWindowScale) { var s = device.NativeWindowScale / device.EffectiveWindowScale; return(new int2((int)(Math.Sign(x) / 2f + x * s), (int)(Math.Sign(x) / 2f + y * s))); } return(new int2(x, y)); }
public Sdl2GraphicsContext(Sdl2PlatformWindow window) { this.window = window; }
public void PumpInput(Sdl2PlatformWindow device, IInputHandler inputHandler) { var mods = MakeModifiers((int)SDL.SDL_GetModState()); var scrollDelta = 0; inputHandler.ModifierKeys(mods); MouseInput?pendingMotion = null; SDL.SDL_Event e; while (SDL.SDL_PollEvent(out e) != 0) { switch (e.type) { case SDL.SDL_EventType.SDL_QUIT: Game.Exit(); break; case SDL.SDL_EventType.SDL_WINDOWEVENT: { switch (e.window.windowEvent) { case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST: Game.HasInputFocus = false; break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED: Game.HasInputFocus = true; break; // Triggered when moving between displays with different DPI settings case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED: device.WindowSizeChanged(); break; } break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: { if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } var button = MakeButton(e.button.button); lastButtonBits |= button; var pos = EventPosition(device, e.button.x, e.button.y); inputHandler.OnMouseInput(new MouseInput( MouseInputEvent.Down, button, scrollDelta, pos, mods, MultiTapDetection.DetectFromMouse(e.button.button, pos))); break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: { if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } var button = MakeButton(e.button.button); lastButtonBits &= ~button; var pos = EventPosition(device, e.button.x, e.button.y); inputHandler.OnMouseInput(new MouseInput( MouseInputEvent.Up, button, scrollDelta, pos, mods, MultiTapDetection.InfoFromMouse(e.button.button))); break; } case SDL.SDL_EventType.SDL_MOUSEMOTION: { var pos = EventPosition(device, e.motion.x, e.motion.y); pendingMotion = new MouseInput( MouseInputEvent.Move, lastButtonBits, scrollDelta, pos, mods, 0); break; } case SDL.SDL_EventType.SDL_MOUSEWHEEL: { int x, y; SDL.SDL_GetMouseState(out x, out y); scrollDelta = e.wheel.y; inputHandler.OnMouseInput(new MouseInput(MouseInputEvent.Scroll, MouseButton.None, scrollDelta, new int2(x, y), mods, 0)); break; } case SDL.SDL_EventType.SDL_TEXTINPUT: { var rawBytes = new byte[SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE]; unsafe { Marshal.Copy((IntPtr)e.text.text, rawBytes, 0, SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE); } inputHandler.OnTextInput(Encoding.UTF8.GetString(rawBytes, 0, Array.IndexOf(rawBytes, (byte)0))); break; } case SDL.SDL_EventType.SDL_KEYDOWN: case SDL.SDL_EventType.SDL_KEYUP: { var keyCode = (Keycode)e.key.keysym.sym; var type = e.type == SDL.SDL_EventType.SDL_KEYDOWN ? KeyInputEvent.Down : KeyInputEvent.Up; var tapCount = e.type == SDL.SDL_EventType.SDL_KEYDOWN ? MultiTapDetection.DetectFromKeyboard(keyCode) : MultiTapDetection.InfoFromKeyboard(keyCode); var keyEvent = new KeyInput { Event = type, Key = keyCode, Modifiers = mods, UnicodeChar = (char)e.key.keysym.sym, MultiTapCount = tapCount, IsRepeat = e.key.repeat != 0 }; // Special case workaround for windows users if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_F4 && mods.HasModifier(Modifiers.Alt) && Platform.CurrentPlatform == PlatformType.Windows) { Game.Exit(); } else { inputHandler.OnKeyInput(keyEvent); } break; } } } if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } }
public void PumpInput(Sdl2PlatformWindow device, IInputHandler inputHandler, int2?lockedMousePosition) { var mods = MakeModifiers((int)SDL.SDL_GetModState()); inputHandler.ModifierKeys(mods); MouseInput?pendingMotion = null; while (SDL.SDL_PollEvent(out var e) != 0) { switch (e.type) { case SDL.SDL_EventType.SDL_QUIT: // On macOS, we'd like to restrict Cmd + Q from suddenly exiting the game. if (Platform.CurrentPlatform != PlatformType.OSX || !mods.HasModifier(Modifiers.Meta)) { Game.Exit(); } break; case SDL.SDL_EventType.SDL_WINDOWEVENT: { switch (e.window.windowEvent) { case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST: device.HasInputFocus = false; break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED: device.HasInputFocus = true; break; // Triggered when moving between displays with different DPI settings case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED: device.WindowSizeChanged(); break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_HIDDEN: case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MINIMIZED: device.IsSuspended = true; break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_EXPOSED: case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SHOWN: case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MAXIMIZED: case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESTORED: device.IsSuspended = false; break; } break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: { if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } var button = MakeButton(e.button.button); lastButtonBits |= button; var input = lockedMousePosition ?? new int2(e.button.x, e.button.y); var pos = EventPosition(device, input.X, input.Y); inputHandler.OnMouseInput(new MouseInput( MouseInputEvent.Down, button, pos, int2.Zero, mods, MultiTapDetection.DetectFromMouse(e.button.button, pos))); break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: { if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } var button = MakeButton(e.button.button); lastButtonBits &= ~button; var input = lockedMousePosition ?? new int2(e.button.x, e.button.y); var pos = EventPosition(device, input.X, input.Y); inputHandler.OnMouseInput(new MouseInput( MouseInputEvent.Up, button, pos, int2.Zero, mods, MultiTapDetection.InfoFromMouse(e.button.button))); break; } case SDL.SDL_EventType.SDL_MOUSEMOTION: { var mousePos = new int2(e.motion.x, e.motion.y); var input = lockedMousePosition ?? mousePos; var pos = EventPosition(device, input.X, input.Y); var delta = lockedMousePosition == null ? EventPosition(device, e.motion.xrel, e.motion.yrel) : mousePos - lockedMousePosition.Value; pendingMotion = new MouseInput( MouseInputEvent.Move, lastButtonBits, pos, delta, mods, 0); break; } case SDL.SDL_EventType.SDL_MOUSEWHEEL: { SDL.SDL_GetMouseState(out var x, out var y); var pos = EventPosition(device, x, y); inputHandler.OnMouseInput(new MouseInput(MouseInputEvent.Scroll, MouseButton.None, pos, new int2(0, e.wheel.y), mods, 0)); break; } case SDL.SDL_EventType.SDL_TEXTINPUT: { var rawBytes = new byte[SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE]; unsafe { Marshal.Copy((IntPtr)e.text.text, rawBytes, 0, SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE); } inputHandler.OnTextInput(Encoding.UTF8.GetString(rawBytes, 0, Array.IndexOf(rawBytes, (byte)0))); break; } case SDL.SDL_EventType.SDL_KEYDOWN: case SDL.SDL_EventType.SDL_KEYUP: { var keyCode = (Keycode)e.key.keysym.sym; var type = e.type == SDL.SDL_EventType.SDL_KEYDOWN ? KeyInputEvent.Down : KeyInputEvent.Up; var tapCount = e.type == SDL.SDL_EventType.SDL_KEYDOWN ? MultiTapDetection.DetectFromKeyboard(keyCode, mods) : MultiTapDetection.InfoFromKeyboard(keyCode, mods); var keyEvent = new KeyInput { Event = type, Key = keyCode, Modifiers = mods, UnicodeChar = (char)e.key.keysym.sym, MultiTapCount = tapCount, IsRepeat = e.key.repeat != 0 }; // Special case workaround for windows users if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_F4 && mods.HasModifier(Modifiers.Alt) && Platform.CurrentPlatform == PlatformType.Windows) { Game.Exit(); } else { inputHandler.OnKeyInput(keyEvent); } break; } } } if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } }