1 /** 2 * Defines the static Input class, which is responsible for handling all keyboard/mouse/controller interactions. 3 */ 4 module utility.input; 5 import utility.config, utility.filepath, utility.output; 6 7 import yaml; 8 import std.typecons, std.conv; 9 10 final abstract class Input 11 { 12 public static: 13 /** 14 * Function called when key event triggers. 15 */ 16 alias void delegate( uint, bool ) KeyEvent; 17 alias void delegate( uint ) KeyStateEvent; 18 19 /** 20 * Processes Config/Input.yml and pulls input string bindings. 21 */ 22 final void initialize() 23 { 24 auto bindings = Config.loadYaml( FilePath.Resources.InputBindings ); 25 26 foreach( key; keyBindings.keys ) 27 keyBindings.remove( key ); 28 29 foreach( string name, Node bind; bindings ) 30 { 31 log( OutputType.Info, "Binding ", name ); 32 33 if( bind.isScalar ) 34 { 35 keyBindings[ name ] = bind.get!Keyboard; 36 } 37 else if( bind.isSequence ) 38 { 39 foreach( Node child; bind ) 40 { 41 try 42 { 43 keyBindings[ name ] = child.get!Keyboard; 44 } 45 catch 46 { 47 log( OutputType.Error, "Failed to parse keybinding for input ", name ); 48 } 49 } 50 } 51 else if( bind.isMapping ) 52 { 53 foreach( string type, Node value; bind ) 54 { 55 final switch( type ) 56 { 57 case "Keyboard": 58 try 59 { 60 keyBindings[ name ] = value.get!Keyboard; 61 } 62 catch 63 { 64 try 65 { 66 keyBindings[ name ] = value.get!string.to!Keyboard; 67 } 68 catch 69 { 70 log( OutputType.Error, "Failed to parse keybinding for input ", name ); 71 } 72 } 73 74 break; 75 } 76 } 77 } 78 } 79 } 80 81 /** 82 * Updates the key states, and calls all key events. 83 */ 84 final void update() 85 { 86 auto diff = staging - current; 87 88 previous = current; 89 current = staging; 90 staging.reset(); 91 92 foreach( state; diff ) 93 if( auto keyEvent = state[ 0 ] in keyEvents ) 94 foreach( event; *keyEvent ) 95 event( state[ 0 ], state[ 1 ] ); 96 } 97 98 /** 99 * Add an event to be fired when the given key changes. 100 * 101 * Params: 102 * keyCode = The code of the key to add the event to. 103 * func = The function to call when the key state changes. 104 */ 105 final void addKeyEvent( uint keyCode, KeyEvent func ) 106 { 107 keyEvents[ keyCode ] ~= func; 108 } 109 110 /** 111 * Add a key event only when the key is down. 112 */ 113 final void addKeyDownEvent( uint keyCode, KeyStateEvent func ) 114 { 115 keyEvents[ keyCode ] ~= ( uint keyCode, bool newState ) { if( newState ) func( newState ); }; 116 } 117 118 /** 119 * Add a key event only when the key is up. 120 */ 121 final void addKeyUpEvent( uint keyCode, KeyStateEvent func ) 122 { 123 keyEvents[ keyCode ] ~= ( uint keyCode, bool newState ) { if( !newState ) func( keyCode ); }; 124 } 125 126 /** 127 * Check if a given key is down. 128 * 129 * Params: 130 * keyCode = The code of the key to check. 131 * checkPrevious = Whether or not to make sure the key was down last frame. 132 */ 133 final bool isKeyDown( uint keyCode, bool checkPrevious = false ) 134 { 135 return current[ keyCode ] && ( !checkPrevious || previous[ keyCode ] ); 136 } 137 138 /** 139 * Check if a given key is up. 140 * 141 * Params: 142 * keyCode = The code of the key to check. 143 * checkPrevious = Whether or not to make sure the key was up last frame. 144 */ 145 final bool isKeyUp( uint keyCode, bool checkPrevious = false ) 146 { 147 return !current[ keyCode ] && ( !checkPrevious || !previous[ keyCode ] ); 148 } 149 150 /** 151 * Sets the state of the key to be assigned at the beginning of next frame. 152 * Should only be called from a window controller. 153 */ 154 final void setKeyState( uint keyCode, bool newState ) 155 { 156 staging[ keyCode ] = newState; 157 } 158 159 /** 160 * Gets the state of a string-bound input. 161 * 162 * Params: 163 * input = The input to check for. 164 * checkPrevious = Whether or not to make sure the key was up last frame. 165 */ 166 final T getState( T = bool )( string input, bool checkPrevious = false ) if( is( T == bool ) /*|| is( T == float )*/ ) 167 { 168 static if( is( T == bool ) ) 169 { 170 if( input in keyBindings ) 171 { 172 return isKeyDown( keyBindings[ input ], checkPrevious ); 173 } 174 else 175 { 176 throw new Exception( "Input " ~ input ~ " not bound." ); 177 } 178 } 179 /*else static if( is( T == float ) ) 180 { 181 182 }*/ 183 } 184 185 private: 186 Keyboard[ string ] keyBindings; 187 188 KeyEvent[][ uint ] keyEvents; 189 190 KeyState current; 191 KeyState previous; 192 KeyState staging; 193 194 struct KeyState 195 { 196 public: 197 enum TotalSize = 256u; 198 enum ElementSize = uint.sizeof; 199 enum Split = TotalSize / ElementSize; 200 201 uint[ Split ] keys; 202 203 ref KeyState opAssign( const ref KeyState other ) 204 { 205 for( uint ii = 0; ii < Split; ++ii ) 206 keys[ ii ] = other.keys[ ii ]; 207 208 return this; 209 } 210 211 bool opIndex( size_t keyCode ) const 212 { 213 return ( keys[ keyCode / ElementSize ] & getBitAtIndex( keyCode ) ) != 0; 214 } 215 216 bool opIndexAssign( bool newValue, size_t keyCode ) 217 { 218 keys[ keyCode / ElementSize ] = getBitAtIndex( keyCode ) & uint.max; 219 return newValue; 220 } 221 222 Tuple!( uint, bool )[] opBinary( string Op : "-" )( const ref KeyState other ) 223 { 224 Tuple!( uint, bool )[] differences; 225 226 for( uint ii = 0; ii < TotalSize; ++ii ) 227 if( this[ ii ] != other[ ii ] ) 228 differences ~= Tuple!( uint, bool )( ii, this[ ii ] ); 229 230 return differences; 231 } 232 233 void reset() 234 { 235 for( uint ii = 0; ii < Split; ++ii ) 236 keys[ ii ] = 0; 237 } 238 239 private: 240 static uint getBitAtIndex( size_t keyCode ) 241 { 242 return 1 << ( keyCode % Split ); 243 } 244 } 245 } 246 247 /** 248 * Virtual key codes. 249 * 250 * From: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx 251 */ 252 enum Keyboard: uint 253 { 254 MouseLeft = 0x01, /// Left mouse button 255 MouseRight = 0x02, /// Right mouse button 256 Cancel = 0x03, /// Control-break 257 MouseMiddle = 0x04, /// Middle mouse button 258 XButton1 = 0x05, /// X1 mouse button 259 XButton2 = 0x06, /// X2 mouse button 260 //Unused = 0x07, 261 Backspace = 0x08, /// Backspace key 262 Tab = 0x09, /// Tab key 263 //Reserved = 0x0A-0x0B, 264 Clear = 0x0C, /// Clear key 265 Return = 0x0D, /// Enter key 266 //Undefined = 0x0E-0x0F 267 Shift = 0x10, /// Shift key 268 Control = 0x11, /// Control key 269 Alt = 0x12, /// Menu/alt key 270 Pause = 0x13, /// Pause key 271 CapsLock = 0x14, /// Capital/Caps Lock key 272 //Who Cares = 0x15-0x1A, 273 Escape = 0x1B, /// Escape key 274 //Who Cares = 0x1C-0x1F 275 Space = 0x20, /// Space bar 276 PageUp = 0x21, /// Page Up/Prior key 277 PageDown = 0x22, /// Page Down/Next key 278 End = 0x23, /// End key 279 Home = 0x24, /// Home key 280 Left = 0x25, /// Left arrow key 281 Up = 0x26, /// Up arrow key 282 Right = 0x27, /// Right arrow key 283 Down = 0x28, /// Down arrow key 284 Select = 0x29, /// Select key 285 Print = 0x2A, /// Print key 286 Execute = 0x2B, /// Execute key 287 PrintScreen = 0x2C, /// Print Screen/Snapshot key 288 Insert = 0x2D, /// Insert key 289 Delete = 0x2E, /// Delete key 290 Help = 0x2F, /// Help key 291 Keyboard0 = 0x30, /// 0 key 292 Keyboard1 = 0x31, /// 1 key 293 Keyboard2 = 0x32, /// 2 key 294 Keyboard3 = 0x33, /// 3 key 295 Keyboard4 = 0x34, /// 4 key 296 Keyboard5 = 0x35, /// 5 key 297 Keyboard6 = 0x36, /// 6 key 298 Keyboard7 = 0x37, /// 7 key 299 Keyboard8 = 0x38, /// 8 key 300 Keyboard9 = 0x39, /// 9 key 301 //Unused = 0x3A-0x40 302 A = 0x41, /// A key 303 B = 0x42, /// B key 304 C = 0x43, /// C key 305 D = 0x44, /// D key 306 E = 0x45, /// E key 307 F = 0x46, /// F key 308 G = 0x47, /// G key 309 H = 0x48, /// H key 310 I = 0x49, /// I key 311 J = 0x4A, /// J key 312 K = 0x4B, /// K key 313 L = 0x4C, /// L key 314 M = 0x4D, /// M key 315 N = 0x4E, /// N key 316 O = 0x4F, /// O key 317 P = 0x50, /// P key 318 Q = 0x51, /// Q key 319 R = 0x52, /// R key 320 S = 0x53, /// S key 321 T = 0x54, /// T key 322 U = 0x55, /// U key 323 V = 0x56, /// V key 324 W = 0x57, /// W key 325 X = 0x58, /// X key 326 Y = 0x59, /// Y key 327 Z = 0x5A, /// Z key 328 WindowsLeft = 0x5B, /// Left windows key 329 WindowsRight= 0x5C, /// Right windows key 330 Apps = 0x5D, /// Applications key 331 //Reserved = 0x5E 332 Sleep = 0x5F, /// Sleep key 333 Numpad0 = 0x60, /// 0 key 334 Numpad1 = 0x61, /// 1 key 335 Numpad2 = 0x62, /// 2 key 336 Numpad3 = 0x63, /// 3 key 337 Numpad4 = 0x64, /// 4 key 338 Numpad5 = 0x65, /// 5 key 339 Numpad6 = 0x66, /// 6 key 340 Numpad7 = 0x67, /// 7 key 341 Numpad8 = 0x68, /// 8 key 342 Numpad9 = 0x69, /// 9 key 343 Multiply = 0x6A, /// Multiply key 344 Add = 0x6B, /// Addition key 345 Separator = 0x6C, /// Seperator key 346 Subtract = 0x6D, /// Subtraction key 347 Decimal = 0x6E, /// Decimal key 348 Divide = 0x6F, /// Division key 349 F1 = 0x70, /// Function 1 key 350 F2 = 0x71, /// Function 2 key 351 F3 = 0x72, /// Function 3 key 352 F4 = 0x73, /// Function 4 key 353 F5 = 0x74, /// Function 5 key 354 F6 = 0x75, /// Function 6 key 355 F7 = 0x76, /// Function 7 key 356 F8 = 0x77, /// Function 8 key 357 F9 = 0x78, /// Function 9 key 358 F10 = 0x79, /// Function 10 key 359 F11 = 0x7A, /// Function 11 key 360 F12 = 0x7B, /// Function 12 key 361 F13 = 0x7C, /// Function 13 key 362 F14 = 0x7D, /// Function 14 key 363 F15 = 0x7E, /// Function 15 key 364 F16 = 0x7F, /// Function 16 key 365 F17 = 0x80, /// Function 17 key 366 F18 = 0x81, /// Function 18 key 367 F19 = 0x82, /// Function 19 key 368 F20 = 0x83, /// Function 20 key 369 F21 = 0x84, /// Function 21 key 370 F22 = 0x85, /// Function 22 key 371 F23 = 0x86, /// Function 23 key 372 F24 = 0x87, /// Function 24 key 373 //Unused = 0x88-0x8F, 374 NumLock = 0x90, /// Num Lock key 375 ScrollLock = 0x91, /// Scroll Lock key 376 //OEM = 0x92-0x96, 377 //Unused = 0x97-0x9F, 378 ShiftLeft = 0xA0, /// Left shift key 379 ShiftRight = 0xA1, /// Right shift key 380 ControlLeft = 0xA2, /// Left control key 381 ControlRight= 0xA3, /// Right control key 382 AltLeft = 0xA4, /// Left Alt key 383 AltRight = 0xA5, /// Right Alt key 384 }