From 984e30cc4c037f7c0a9997384b5c4aa994d62ee0 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Thu, 25 Mar 2021 15:57:26 -0700 Subject: [PATCH] add system for text input --- src/Game.cs | 40 ++++++++++++++++++++++++++++++++++++++++ src/Input/Input.cs | 11 +++++++++++ src/Input/Keyboard.cs | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/src/Game.cs b/src/Game.cs index 8c528eaf..fa9d3be9 100644 --- a/src/Game.cs +++ b/src/Game.cs @@ -4,6 +4,7 @@ using MoonWorks.Audio; using MoonWorks.Graphics; using MoonWorks.Input; using MoonWorks.Window; +using System.Text; namespace MoonWorks { @@ -107,6 +108,10 @@ namespace MoonWorks case SDL.SDL_EventType.SDL_QUIT: quit = true; break; + + case SDL.SDL_EventType.SDL_TEXTINPUT: + HandleTextInput(_event); + break; } } } @@ -114,5 +119,40 @@ namespace MoonWorks protected abstract void Update(double dt); protected abstract void Draw(double dt, double alpha); + + private void HandleTextInput(SDL2.SDL.SDL_Event evt) + { + // Based on the SDL2# LPUtf8StrMarshaler + unsafe + { + int bytes = MeasureStringLength(evt.text.text); + if (bytes > 0) + { + /* UTF8 will never encode more characters + * than bytes in a string, so bytes is a + * suitable upper estimate of size needed + */ + char* charsBuffer = stackalloc char[bytes]; + int chars = Encoding.UTF8.GetChars( + evt.text.text, + bytes, + charsBuffer, + bytes + ); + + for (int i = 0; i < chars; i += 1) + { + Inputs.OnTextInput(charsBuffer[i]); + } + } + } + } + + private unsafe static int MeasureStringLength(byte* ptr) + { + int bytes; + for (bytes = 0; *ptr != 0; ptr += 1, bytes += 1); + return bytes; + } } } diff --git a/src/Input/Input.cs b/src/Input/Input.cs index 5111acff..43baf60b 100644 --- a/src/Input/Input.cs +++ b/src/Input/Input.cs @@ -1,4 +1,5 @@ using SDL2; +using System; using System.Collections.Generic; namespace MoonWorks.Input @@ -10,6 +11,8 @@ namespace MoonWorks.Input List gamepads = new List(); + public static event Action TextInput; + internal Inputs() { Keyboard = new Keyboard(); @@ -45,5 +48,13 @@ namespace MoonWorks.Input { return gamepads[slot]; } + + internal static void OnTextInput(char c) + { + if (TextInput != null) + { + TextInput(c); + } + } } } diff --git a/src/Input/Keyboard.cs b/src/Input/Keyboard.cs index efe928bc..3fcc45d2 100644 --- a/src/Input/Keyboard.cs +++ b/src/Input/Keyboard.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using SDL2; @@ -9,6 +10,28 @@ namespace MoonWorks.Input private ButtonState[] Keys { get; } private int numKeys; + private static readonly char[] TextInputCharacters = new char[] + { + (char) 2, // Home + (char) 3, // End + (char) 8, // Backspace + (char) 9, // Tab + (char) 13, // Enter + (char) 127, // Delete + (char) 22 // Ctrl+V (Paste) + }; + + private static readonly Dictionary TextInputBindings = new Dictionary() + { + { Keycode.Home, 0 }, + { Keycode.End, 1 }, + { Keycode.Backspace, 2 }, + { Keycode.Tab, 3 }, + { Keycode.Return, 4 }, + { Keycode.Delete, 5 } + // Ctrl+V is special! + }; + internal Keyboard() { SDL.SDL_GetKeyboardState(out numKeys); @@ -28,6 +51,18 @@ namespace MoonWorks.Input { var keyDown = Marshal.ReadByte(keyboardState, keycode); Keys[keycode].Update(Conversions.ByteToBool(keyDown)); + + if (Conversions.ByteToBool(keyDown)) + { + if (TextInputBindings.TryGetValue((Keycode)keycode, out var textIndex)) + { + Inputs.OnTextInput(TextInputCharacters[(textIndex)]); + } + else if (IsDown(Keycode.LeftControl) && (Keycode)keycode == Keycode.V) + { + Inputs.OnTextInput(TextInputCharacters[6]); + } + } } }