A game framework written with osu! in mind.
at master 8.6 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using Foundation; 6using osu.Framework.Input.Handlers; 7using osu.Framework.Input.StateChanges; 8using osu.Framework.Platform; 9using osuTK.Input; 10using UIKit; 11 12namespace osu.Framework.iOS.Input 13{ 14 public class IOSKeyboardHandler : InputHandler 15 { 16 private readonly IOSGameView view; 17 18 public IOSKeyboardHandler(IOSGameView view) 19 { 20 this.view = view; 21 view.KeyboardTextField.HandleShouldChangeCharacters += handleShouldChangeCharacters; 22 view.KeyboardTextField.HandleShouldReturn += handleShouldReturn; 23 view.KeyboardTextField.HandleKeyCommand += handleKeyCommand; 24 } 25 26 private void handleShouldChangeCharacters(NSRange range, string text) 27 { 28 if (!IsActive) 29 return; 30 31 if (text.Length == 0) 32 { 33 Key key = range.Location < IOSGameView.HiddenTextField.CURSOR_POSITION ? Key.BackSpace : Key.Delete; 34 35 // NOTE: this makes the assumption that Key.AltLeft triggers the WordPrevious platform action 36 if (range.Length > 1) 37 PendingInputs.Enqueue(new KeyboardKeyInput(Key.AltLeft, true)); 38 39 if (range.Length > 0) 40 { 41 PendingInputs.Enqueue(new KeyboardKeyInput(key, true)); 42 PendingInputs.Enqueue(new KeyboardKeyInput(key, false)); 43 } 44 45 if (range.Length > 1) 46 PendingInputs.Enqueue(new KeyboardKeyInput(Key.AltLeft, false)); 47 48 return; 49 } 50 51 foreach (char c in text) 52 { 53 Key? key = keyForString(char.ToString(c), out bool upper); 54 55 if (!key.HasValue) continue; 56 57 if (upper) 58 PendingInputs.Enqueue(new KeyboardKeyInput(Key.LShift, true)); 59 60 PendingInputs.Enqueue(new KeyboardKeyInput(key.Value, true)); 61 PendingInputs.Enqueue(new KeyboardKeyInput(key.Value, false)); 62 63 if (upper) 64 PendingInputs.Enqueue(new KeyboardKeyInput(Key.LShift, false)); 65 } 66 } 67 68 private void handleShouldReturn() 69 { 70 if (!IsActive) 71 return; 72 73 PendingInputs.Enqueue(new KeyboardKeyInput(Key.Enter, true)); 74 PendingInputs.Enqueue(new KeyboardKeyInput(Key.Enter, false)); 75 } 76 77 private void handleKeyCommand(UIKeyCommand cmd) 78 { 79 if (!IsActive) 80 return; 81 82 Key? key; 83 bool upper = false; 84 85 // UIKeyCommand constants are not actually constants, so we can't use a switch 86 if (cmd.Input == UIKeyCommand.LeftArrow) 87 key = Key.Left; 88 else if (cmd.Input == UIKeyCommand.RightArrow) 89 key = Key.Right; 90 else if (cmd.Input == UIKeyCommand.UpArrow) 91 key = Key.Up; 92 else if (cmd.Input == UIKeyCommand.DownArrow) 93 key = Key.Down; 94 else 95 key = keyForString(cmd.Input, out upper); 96 97 if (!key.HasValue) return; 98 99 bool shiftHeld = (cmd.ModifierFlags & UIKeyModifierFlags.Shift) > 0 || upper; 100 bool superHeld = (cmd.ModifierFlags & UIKeyModifierFlags.Command) > 0; 101 bool ctrlHeld = (cmd.ModifierFlags & UIKeyModifierFlags.Control) > 0; 102 bool optionHeld = (cmd.ModifierFlags & UIKeyModifierFlags.Alternate) > 0; 103 104 if (shiftHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LShift, true)); 105 if (superHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LWin, true)); 106 if (ctrlHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LControl, true)); 107 if (optionHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LAlt, true)); 108 109 PendingInputs.Enqueue(new KeyboardKeyInput(key.Value, true)); 110 PendingInputs.Enqueue(new KeyboardKeyInput(key.Value, false)); 111 112 if (optionHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LAlt, false)); 113 if (ctrlHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LControl, false)); 114 if (superHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LWin, false)); 115 if (shiftHeld) PendingInputs.Enqueue(new KeyboardKeyInput(Key.LShift, false)); 116 } 117 118 private Key? keyForString(string str, out bool upper) 119 { 120 upper = false; 121 if (str.Length == 0) 122 return null; 123 124 char c = str[0]; 125 126 switch (c) 127 { 128 case ' ': 129 return Key.Space; 130 131 case '\t': 132 return Key.Tab; 133 134 case '1': 135 case '!': 136 upper = !char.IsDigit(c); 137 return Key.Number1; 138 139 case '2': 140 case '@': 141 upper = !char.IsDigit(c); 142 return Key.Number2; 143 144 case '3': 145 case '#': 146 upper = !char.IsDigit(c); 147 return Key.Number3; 148 149 case '4': 150 case '$': 151 upper = !char.IsDigit(c); 152 return Key.Number4; 153 154 case '5': 155 case '%': 156 upper = !char.IsDigit(c); 157 return Key.Number5; 158 159 case '6': 160 case '^': 161 upper = !char.IsDigit(c); 162 return Key.Number6; 163 164 case '7': 165 case '&': 166 upper = !char.IsDigit(c); 167 return Key.Number7; 168 169 case '8': 170 case '*': 171 upper = !char.IsDigit(c); 172 return Key.Number8; 173 174 case '9': 175 case '(': 176 upper = !char.IsDigit(c); 177 return Key.Number9; 178 179 case '0': 180 case ')': 181 upper = !char.IsDigit(c); 182 return Key.Number0; 183 184 case '-': 185 case '_': 186 upper = c == '_'; 187 return Key.Minus; 188 189 case '=': 190 case '+': 191 upper = c == '+'; 192 return Key.Plus; 193 194 case '`': 195 case '~': 196 upper = c == '~'; 197 return Key.Tilde; 198 199 case '[': 200 case '{': 201 upper = c == '{'; 202 return Key.BracketLeft; 203 204 case ']': 205 case '}': 206 upper = c == '}'; 207 return Key.BracketRight; 208 209 case '\\': 210 case '|': 211 upper = c == '|'; 212 return Key.BackSlash; 213 214 case ';': 215 case ':': 216 upper = c == ':'; 217 return Key.Semicolon; 218 219 case '\'': 220 case '\"': 221 upper = c == '\"'; 222 return Key.Quote; 223 224 case ',': 225 case '<': 226 upper = c == '<'; 227 return Key.Comma; 228 229 case '.': 230 case '>': 231 upper = c == '>'; 232 return Key.Period; 233 234 case '/': 235 case '?': 236 upper = c == '?'; 237 return Key.Slash; 238 239 default: 240 if (char.IsLetter(c)) 241 { 242 string keyName = c.ToString().ToUpper(); 243 if (Enum.TryParse(keyName, out Key result)) 244 return result; 245 } 246 247 return null; 248 } 249 } 250 251 internal bool KeyboardActive; 252 public override bool IsActive => KeyboardActive; 253 254 protected override void Dispose(bool disposing) 255 { 256 view.KeyboardTextField.HandleShouldChangeCharacters -= handleShouldChangeCharacters; 257 view.KeyboardTextField.HandleShouldReturn -= handleShouldReturn; 258 view.KeyboardTextField.HandleKeyCommand -= handleKeyCommand; 259 base.Dispose(disposing); 260 } 261 262 public override bool Initialize(GameHost host) => true; 263 } 264}