using System; using System.Diagnostics; using System.Reflection; using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using MLEM.Formatting.Codes; namespace MLEM.Misc { /// /// MlemPlatform is a wrapper around some of MonoGame's platform-dependent behavior to allow for MLEM to stay platform-independent. /// See , and for information on the specific platforms. /// The MLEM demos' main classes also make use of this functionality: and . /// public abstract class MlemPlatform { /// /// The current MLEM platform /// Set this value before starting your game if you want to use platform-dependent MLEM features. /// /// public static MlemPlatform Current; /// /// Opens the on-screen keyboard if one is required by the platform. /// Note that, if no on-screen keyboard is required, a null string should be returned. /// /// Title of the dialog box. /// Description of the dialog box. /// Default text displayed in the input area. /// If password mode is enabled, the characters entered are not displayed. /// Text entered by the player. Null if back was used. public abstract Task OpenOnScreenKeyboard(string title, string description, string defaultText, bool usePasswordMode); /// /// Adds a text input listener to this platform, if supported. /// The supplied listener will be called whenever a character is input. /// /// The game's window /// The callback that should be called whenever a character is pressed public abstract void AddTextInputListener(GameWindow window, TextInputCallback callback); /// /// A method that should be executed to open a link in the browser or a file explorer. /// This method is currently used only by MLEM.Ui's implementation of the formatting code. /// public abstract void OpenLinkOrFile(string link); /// /// Ensures that is set to a valid value by throwing an exception if is null. /// /// If is null public static void EnsureExists() { if (Current == null) throw new InvalidOperationException("MlemPlatform was not initialized. For more information, see the MlemPlatform class or https://mlem.ellpeck.de/api/MLEM.Misc.MlemPlatform"); } /// /// A delegate method that can be used for /// /// The object that sent the event. The used in most cases. /// The key that was pressed /// The character that corresponds to that key public delegate void TextInputCallback(object sender, Keys key, char character); /// /// The MLEM DesktopGL platform. /// This platform uses the built-in MonoGame TextInput event, which makes this listener work with any keyboard localization natively. /// This platform is initialized as follows: /// /// MlemPlatform.Current = new MlemPlatform.DesktopGl<TextInputEventArgs>((w, c) => w.TextInput += c); /// /// /// public class DesktopGl : MlemPlatform { private FieldInfo key; private FieldInfo character; private readonly Action> addListener; /// /// Creates a new DesktopGL-based platform /// See class documentation for more detailed information. /// /// The function that is used to add a text input listener public DesktopGl(Action> addListener) { this.addListener = addListener; } /// public override Task OpenOnScreenKeyboard(string title, string description, string defaultText, bool usePasswordMode) { return Task.FromResult(null); } /// public override void AddTextInputListener(GameWindow window, TextInputCallback callback) { this.addListener(window, (sender, args) => { if (this.key == null) this.key = args.GetType().GetField("Key"); if (this.character == null) this.character = args.GetType().GetField("Character"); callback.Invoke(sender, (Keys) this.key.GetValue(args), (char) this.character.GetValue(args)); }); } /// public override void OpenLinkOrFile(string link) { Process.Start(new ProcessStartInfo(link) {UseShellExecute = true}); } } /// /// The MLEM platform for mobile platforms as well as consoles. /// This platform opens an on-screen keyboard using the KeyboardInput class on mobile devices. /// Additionally, it starts a new activity whenever is called. /// This listener is initialized as follows in the game's Activity class: /// /// MlemPlatform.Current = new MlemPlatform.Mobile(KeyboardInput.Show, l => this.StartActivity(new Intent(Intent.ActionView, Uri.Parse(l)))); /// /// public class Mobile : MlemPlatform { private readonly OpenOnScreenKeyboardDelegate openOnScreenKeyboard; private readonly Action openLink; /// /// Creates a new mobile- and console-based platform. /// See class documentation for more detailed information. /// /// The function that is used to display the on-screen keyboard /// The action that is invoked to open a link in the browser, which is used for public Mobile(OpenOnScreenKeyboardDelegate openOnScreenKeyboard, Action openLink = null) { this.openOnScreenKeyboard = openOnScreenKeyboard; this.openLink = openLink; } /// public override Task OpenOnScreenKeyboard(string title, string description, string defaultText, bool usePasswordMode) { return this.openOnScreenKeyboard(title, description, defaultText, usePasswordMode); } /// public override void AddTextInputListener(GameWindow window, TextInputCallback callback) { } /// public override void OpenLinkOrFile(string link) { this.openLink?.Invoke(link); } /// /// A delegate method used for /// /// Title of the dialog box. /// Description of the dialog box. /// Default text displayed in the input area. /// If password mode is enabled, the characters entered are not displayed. /// Text entered by the player. Null if back was used. public delegate Task OpenOnScreenKeyboardDelegate(string title, string description, string defaultText, bool usePasswordMode); } /// /// A MLEM platform implementation that does nothing. /// This can be used if no platform-dependent code is required for the game. /// public class None : MlemPlatform { /// public override Task OpenOnScreenKeyboard(string title, string description, string defaultText, bool usePasswordMode) { return Task.FromResult(null); } /// public override void AddTextInputListener(GameWindow window, TextInputCallback callback) { } /// public override void OpenLinkOrFile(string link) { } } } }