private void SdlRunLoop() { Sdl.Event ev; while (Sdl.PollEvent(out ev) == 1) { switch (ev.Type) { case Sdl.EventType.Quit: _isExiting++; break; case Sdl.EventType.JoyDeviceAdded: Joystick.AddDevice(ev.JoystickDevice.Which); break; case Sdl.EventType.JoyDeviceRemoved: Joystick.RemoveDevice(ev.JoystickDevice.Which); break; case Sdl.EventType.ControllerDeviceRemoved: GamePad.RemoveDevice(ev.ControllerDevice.Which); break; case Sdl.EventType.ControllerButtonUp: case Sdl.EventType.ControllerButtonDown: case Sdl.EventType.ControllerAxisMotion: GamePad.UpdatePacketInfo(ev.ControllerDevice.Which, ev.ControllerDevice.TimeStamp); break; case Sdl.EventType.MouseWheel: const int wheelDelta = 120; Mouse.ScrollY += ev.Wheel.Y * wheelDelta; Mouse.ScrollX += ev.Wheel.X * wheelDelta; break; case Sdl.EventType.MouseMotion: Window.MouseState.X = ev.Motion.X; Window.MouseState.Y = ev.Motion.Y; break; case Sdl.EventType.KeyDown: { var key = KeyboardUtil.ToXna(ev.Key.Keysym.Sym); if (!_keys.Contains(key)) { _keys.Add(key); } char character = (char)ev.Key.Keysym.Sym; _view.OnKeyDown(new InputKeyEventArgs(key)); if (char.IsControl(character)) { _view.OnTextInput(new TextInputEventArgs(character, key)); } break; } case Sdl.EventType.KeyUp: { var key = KeyboardUtil.ToXna(ev.Key.Keysym.Sym); _keys.Remove(key); _view.OnKeyUp(new InputKeyEventArgs(key)); break; } case Sdl.EventType.TextInput: if (_view.IsTextInputHandled) { int len = 0; int utf8character = 0; // using an int to encode multibyte characters longer than 2 bytes byte currentByte = 0; int charByteSize = 0; // UTF8 char lenght to decode int remainingShift = 0; unsafe { while ((currentByte = Marshal.ReadByte((IntPtr)ev.Text.Text, len)) != 0) { // we're reading the first UTF8 byte, we need to check if it's multibyte if (charByteSize == 0) { if (currentByte < 192) { charByteSize = 1; } else if (currentByte < 224) { charByteSize = 2; } else if (currentByte < 240) { charByteSize = 3; } else { charByteSize = 4; } utf8character = 0; remainingShift = 4; } // assembling the character utf8character <<= 8; utf8character |= currentByte; charByteSize--; remainingShift--; if (charByteSize == 0) // finished decoding the current character { utf8character <<= remainingShift * 8; // shifting it to full UTF8 scope // SDL returns UTF8-encoded characters while C# char type is UTF16-encoded (and limited to the 0-FFFF range / does not support surrogate pairs) // so we need to convert it to Unicode codepoint and check if it's within the supported range int codepoint = UTF8ToUnicode(utf8character); if (codepoint >= 0 && codepoint < 0xFFFF) { _view.OnTextInput(new TextInputEventArgs((char)codepoint, KeyboardUtil.ToXna(codepoint))); // UTF16 characters beyond 0xFFFF are not supported (and would require a surrogate encoding that is not supported by the char type) } } len++; } } } break; case Sdl.EventType.WindowEvent: switch (ev.Window.EventID) { case Sdl.Window.EventId.Resized: case Sdl.Window.EventId.SizeChanged: _view.ClientResize(ev.Window.Data1, ev.Window.Data2); break; case Sdl.Window.EventId.FocusGained: IsActive = true; break; case Sdl.Window.EventId.FocusLost: IsActive = false; break; case Sdl.Window.EventId.Moved: _view.Moved(); break; case Sdl.Window.EventId.Close: _isExiting++; break; } break; } } }
private void SdlRunLoop() { Sdl.Event ev; while (Sdl.PollEvent(out ev) == 1) { if (ev.Type == Sdl.EventType.Quit) { _isExiting++; } else if (ev.Type == Sdl.EventType.JoyDeviceAdded) { Joystick.AddDevice(ev.JoystickDevice.Which); } else if (ev.Type == Sdl.EventType.ControllerDeviceRemoved) { GamePad.RemoveDevice(ev.ControllerDevice.Which); } else if (ev.Type == Sdl.EventType.JoyDeviceRemoved) { Joystick.RemoveDevice(ev.JoystickDevice.Which); } else if (ev.Type == Sdl.EventType.MouseWheel) { const int wheelDelta = 120; Mouse.ScrollY += ev.Wheel.Y * wheelDelta; Mouse.ScrollX += ev.Wheel.X * wheelDelta; } else if (ev.Type == Sdl.EventType.MouseMotion) { Window.MouseState.X = ev.Motion.X; Window.MouseState.Y = ev.Motion.Y; } else if (ev.Type == Sdl.EventType.KeyDown) { var key = KeyboardUtil.ToXna(ev.Key.Keysym.Sym); if (!_keys.Contains(key)) { _keys.Add(key); } char character = (char)ev.Key.Keysym.Sym; if (char.IsControl(character)) { _view.CallTextInput(character, key); } } else if (ev.Type == Sdl.EventType.KeyUp) { var key = KeyboardUtil.ToXna(ev.Key.Keysym.Sym); _keys.Remove(key); } else if (ev.Type == Sdl.EventType.TextInput) { int len = 0; string text = String.Empty; unsafe { while (Marshal.ReadByte((IntPtr)ev.Text.Text, len) != 0) { len++; } var buffer = new byte[len]; Marshal.Copy((IntPtr)ev.Text.Text, buffer, 0, len); text = System.Text.Encoding.UTF8.GetString(buffer); } if (text.Length == 0) { continue; } foreach (var c in text) { var key = KeyboardUtil.ToXna((int)c); _view.CallTextInput(c, key); } } else if (ev.Type == Sdl.EventType.DropFile) { _view.CallFileDrop(Sdl.GetString(ev.Drop.File)); } else if (ev.Type == Sdl.EventType.WindowEvent) { if (ev.Window.WindowID == _view.Id) { if (ev.Window.EventID == Sdl.Window.EventId.Resized || ev.Window.EventID == Sdl.Window.EventId.SizeChanged) { _view.ClientResize(ev.Window.Data1, ev.Window.Data2); } else if (ev.Window.EventID == Sdl.Window.EventId.FocusGained) { IsActive = true; } else if (ev.Window.EventID == Sdl.Window.EventId.FocusLost) { IsActive = false; } else if (ev.Window.EventID == Sdl.Window.EventId.Moved) { _view.Moved(); } else if (ev.Window.EventID == Sdl.Window.EventId.Close) { _isExiting++; } } } } }
private void PollSDLEvents() { Span <char> textEditingBuffer = stackalloc char[SDL.Keyboard.TextEditingEvent.TextSize]; while (SDL.PollEvent(out SDL.Event ev) == 1) { switch (ev.Type) { case SDL.EventType.Quit: Interlocked.Increment(ref _isExiting); break; #region Joystick case SDL.EventType.JoyDeviceAdded: Joystick.AddDevice(ev.JoystickDevice.Which); break; case SDL.EventType.JoyDeviceRemoved: Joystick.RemoveDevice(ev.JoystickDevice.Which); break; #endregion #region GameController case SDL.EventType.ControllerDeviceRemoved: GamePad.RemoveDevice(ev.ControllerDevice.Which); break; case SDL.EventType.ControllerButtonUp: case SDL.EventType.ControllerButtonDown: case SDL.EventType.ControllerAxisMotion: GamePad.UpdatePacketInfo(ev.ControllerDevice.Which, ev.ControllerDevice.TimeStamp); break; #endregion #region Mouse case SDL.EventType.MouseWheel: _window.Mouse.ScrollX += ev.MouseWheel.X * MouseWheelDelta; _window.Mouse.ScrollY += ev.MouseWheel.Y * MouseWheelDelta; break; case SDL.EventType.MouseMotion: _window.Mouse.State.X = ev.MouseMotion.X; _window.Mouse.State.Y = ev.MouseMotion.Y; break; #endregion #region Keyboard case SDL.EventType.KeyDown: { bool hasMapping = KeyboardUtil.ToXna(ev.KeyboardKey.Keysym.Sym, out var key); if (hasMapping) { if (!Keyboard._keysDown.Contains(key)) { Keyboard._keysDown.Add(key); } } // TODO: validate rune? Rune.TryCreate(ev.KeyboardKey.Keysym.Sym, out var rune); var inputEv = new TextInputEventArgs(rune, hasMapping ? key : (Keys?)null); _window.OnKeyDown(inputEv); break; } case SDL.EventType.KeyUp: { bool hasMapping = KeyboardUtil.ToXna(ev.KeyboardKey.Keysym.Sym, out var key); if (hasMapping) { Keyboard._keysDown.Remove(key); } // TODO: validate rune? Rune.TryCreate(ev.KeyboardKey.Keysym.Sym, out var rune); _window.OnKeyUp(new TextInputEventArgs(rune, hasMapping ? key : (Keys?)null)); break; } #endregion #region Text-Input/Editing case SDL.EventType.TextInput: unsafe { var utf8 = new Span <byte>(ev.TextInput.Text, SDL.Keyboard.TextInputEvent.TextSize); utf8 = SliceToNullTerminator(utf8); while (!utf8.IsEmpty) { var status = Rune.DecodeFromUtf8(utf8, out Rune rune, out int bytesConsumed); if (status != OperationStatus.Done) { // This should never occur if SDL gives use valid data. throw new InvalidDataException("Failed to decode UTF-8 text input: " + status); } utf8 = utf8[bytesConsumed..];