1 module prova.input.binding; 2 3 import prova.input, 4 prova.math, 5 prova.util; 6 7 /// Allows representation of input from multiple sources in a uniform way 8 class Binding 9 { 10 private Controller controller; 11 private Input input; 12 private LinkedList!(Key)[int] boundKeyButtons; 13 private LinkedList!(ControllerButton)[int] boundControllerButtons; 14 private LinkedList!(Key[4])[int] boundKeySticks; 15 private LinkedList!(ThumbStick)[int] boundControllerSticks; 16 17 /// Forward of deadzone on Controller 18 @property float deadzone() 19 { 20 return controller.deadzone; 21 } 22 23 /// Forward of deadzone on Controller 24 @property void deadzone(float deadzone) 25 { 26 controller.deadzone = deadzone; 27 } 28 29 /// Must be called before using any other method 30 void bindInput(Input input) 31 { 32 if(!input) 33 throw new Exception("Input is null. Did you bind in a constructor rather than during setup()?"); 34 35 this.input = input; 36 } 37 38 /// 39 void bindController(int index) 40 { 41 if(!input) 42 throw new Exception("Input has not been binded yet"); 43 44 controller = input.getController(index); 45 } 46 47 /// 48 void bindButton(int button, Key key) 49 { 50 if(!(button in boundKeyButtons)) 51 boundKeyButtons[button] = new LinkedList!(Key); 52 53 boundKeyButtons[button].insertBack(key); 54 } 55 56 /// 57 void bindButton(int button, ControllerButton controllerButton) 58 { 59 if(!(button in boundControllerButtons)) 60 boundControllerButtons[button] = new LinkedList!(ControllerButton); 61 62 boundControllerButtons[button].insertBack(controllerButton); 63 } 64 65 /** 66 * Simulates a joystick using four keys 67 * 68 * Uses a WASD format for ordering directions 69 */ 70 void bindStick(int stick, Key up, Key left, Key down, Key right) 71 { 72 if(!(stick in boundKeySticks)) 73 boundKeySticks[stick] = new LinkedList!(Key[4]); 74 75 Key[4] simulatedStick = [up, left, down, right]; 76 boundKeySticks[stick].insertBack(simulatedStick); 77 } 78 79 /// 80 void bindStick(int stick, ThumbStick joystick) 81 { 82 if(!(stick in boundControllerSticks)) 83 boundControllerSticks[stick] = new LinkedList!(ThumbStick); 84 85 boundControllerSticks[stick].insertBack(joystick); 86 } 87 88 /// 89 bool isButtonDown(int button) 90 { 91 if(!input) 92 throw new Exception("Input has not been binded yet"); 93 94 return isKeyDown(button) || isControllerButtonDown(button); 95 } 96 97 private bool isKeyDown(int button) 98 { 99 if(!(button in boundKeyButtons)) 100 return false; 101 102 // loop through bound keys and return true if just pressed 103 LinkedList!Key keyButtons = boundKeyButtons[button]; 104 105 foreach(Key keyButton; keyButtons) 106 if(input.isKeyDown(keyButton)) 107 return true; 108 109 return false; 110 } 111 112 private bool isControllerButtonDown(int button) 113 { 114 // do not test controller bindings if the controller isn't set 115 // or if there are no buttons bound 116 if(!controller || !(button in boundControllerButtons)) 117 return false; 118 119 // loop through bound buttons and return true if just pressed 120 LinkedList!ControllerButton controllerButtons = boundControllerButtons[button]; 121 122 foreach(ControllerButton controllerButton; controllerButtons) 123 if(controller.isButtonDown(controllerButton)) 124 return true; 125 126 return false; 127 } 128 129 /// 130 bool isButtonUp(int button) 131 { 132 return !isButtonDown(button); 133 } 134 135 /// 136 bool buttonJustPressed(int button) 137 { 138 if(!input) 139 throw new Exception("Input has not been binded yet"); 140 141 return keyJustPressed(button) || controllerButtonJustPressed(button); 142 } 143 144 private bool keyJustPressed(int button) 145 { 146 if(!(button in boundKeyButtons)) 147 return false; 148 149 // loop through bound keys and return true if just pressed 150 LinkedList!Key keyButtons = boundKeyButtons[button]; 151 152 foreach(Key keyButton; keyButtons) 153 if(input.keyJustPressed(keyButton)) 154 return true; 155 156 return false; 157 } 158 159 private bool controllerButtonJustPressed(int button) 160 { 161 // do not test controller bindings if the controller isn't set 162 // or if there are no buttons bound 163 if(!controller || !(button in boundControllerButtons)) 164 return false; 165 166 // loop through bound buttons and return true if just pressed 167 LinkedList!ControllerButton controllerButtons = boundControllerButtons[button]; 168 169 foreach(ControllerButton controllerButton; controllerButtons) 170 if(controller.buttonJustPressed(controllerButton)) 171 return true; 172 173 return false; 174 } 175 176 /// 177 Vector2 getStick(int stick) 178 { 179 if(!input) 180 throw new Exception("Input has not been binded yet"); 181 182 Vector2 result; 183 Vector2 zero; 184 185 result = getSimulatedStick(stick); 186 187 if(result != zero) 188 return result; 189 190 result = getJoyStick(stick); 191 192 if(result != zero) 193 return result; 194 195 return zero; 196 } 197 198 private Vector2 getSimulatedStick(int stick) 199 { 200 Vector2 zero; 201 202 if(!(stick in boundKeySticks)) 203 return zero; 204 205 // loop through bound sticks and return only if it does not equal zero 206 LinkedList!(Key[4]) keySticks = boundKeySticks[stick]; 207 208 foreach(Key[4] keyStick; keySticks) { 209 Vector2 vector = input.simulateStick( 210 keyStick[0], keyStick[1], keyStick[2], keyStick[3] 211 ); 212 213 if(vector != zero) 214 return vector; 215 } 216 217 return zero; 218 } 219 220 private Vector2 getJoyStick(int stick) 221 { 222 Vector2 zero; 223 224 // do not test controller bindings if the controller isn't set, 225 // or if there are no sticks bound to the controller 226 if(!controller || !(stick in boundControllerSticks)) 227 return zero; 228 229 // loop through bound sticks and return only if it does not equal zero 230 LinkedList!ThumbStick thumbsticks = boundControllerSticks[stick]; 231 232 foreach(ThumbStick thumbstick; thumbsticks) { 233 Vector2 vector = controller.getStick(thumbstick); 234 235 if(vector != zero) 236 return vector; 237 } 238 239 return zero; 240 } 241 }