1 module gbaid.input; 2 3 import derelict.sdl2.sdl; 4 5 import gbaid.util; 6 7 import gbaid.gba.keypad; 8 9 public interface InputSource { 10 public void create(); 11 12 public void destroy(); 13 14 public void poll(); 15 16 @property public KeypadState keypadState(); 17 18 @property public bool quickSave(); 19 20 @property public uint lastDigit(); 21 } 22 23 public class Keyboard : InputSource { 24 private static enum int[10] DIGIT_CODES = [ 25 SDL_SCANCODE_0, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, 26 SDL_SCANCODE_5, SDL_SCANCODE_6, SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9 27 ]; 28 private int[10] buttonCodeMap = [ 29 SDL_SCANCODE_P, 30 SDL_SCANCODE_L, 31 SDL_SCANCODE_TAB, 32 SDL_SCANCODE_RETURN, 33 SDL_SCANCODE_D, 34 SDL_SCANCODE_A, 35 SDL_SCANCODE_W, 36 SDL_SCANCODE_S, 37 SDL_SCANCODE_RSHIFT, 38 SDL_SCANCODE_LSHIFT 39 ]; 40 private int quickSaveKey = SDL_SCANCODE_Q; 41 private KeypadState state; 42 private bool save = false; 43 private uint digit = 0; 44 45 public void map(Button button, int key) { 46 buttonCodeMap[button] = key; 47 } 48 49 public override void create() { 50 } 51 52 public override void destroy() { 53 } 54 55 public override void poll() { 56 state.clear(); 57 const ubyte* keyboard = SDL_GetKeyboardState(null); 58 foreach (buttonIndex, buttonCode; buttonCodeMap) { 59 state.setPressed(cast(Button) buttonIndex, cast(bool) keyboard[buttonCode]); 60 } 61 save = cast(bool) keyboard[quickSaveKey]; 62 foreach (uint i, digitCode; DIGIT_CODES) { 63 if (cast(bool) keyboard[digitCode]) { 64 digit = i; 65 break; 66 } 67 } 68 } 69 70 @property public override KeypadState keypadState() { 71 return state; 72 } 73 74 @property public override bool quickSave() { 75 return save; 76 } 77 78 @property public override uint lastDigit() { 79 return digit; 80 } 81 } 82 83 public class Controller : InputSource { 84 private SDL_GameController* controller = null; 85 private int[10] buttonCodeMap = [ 86 SDL_CONTROLLER_BUTTON_A, 87 SDL_CONTROLLER_BUTTON_B, 88 SDL_CONTROLLER_BUTTON_BACK, 89 SDL_CONTROLLER_BUTTON_START, 90 SDL_CONTROLLER_BUTTON_DPAD_RIGHT, 91 SDL_CONTROLLER_BUTTON_DPAD_LEFT, 92 SDL_CONTROLLER_BUTTON_DPAD_UP, 93 SDL_CONTROLLER_BUTTON_DPAD_DOWN, 94 SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, 95 SDL_CONTROLLER_BUTTON_LEFTSHOULDER 96 ]; 97 private StickMapping[10] stickMap = [ 98 StickMapping(), 99 StickMapping(), 100 StickMapping(), 101 StickMapping(), 102 StickMapping(SDL_CONTROLLER_AXIS_LEFTX, 0x4000, true), 103 StickMapping(SDL_CONTROLLER_AXIS_LEFTX, 0x4000, false), 104 StickMapping(SDL_CONTROLLER_AXIS_LEFTY, 0x4000, false), 105 StickMapping(SDL_CONTROLLER_AXIS_LEFTY, 0x4000, true), 106 StickMapping(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0x3000, true), 107 StickMapping(SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0x3000, true) 108 ]; 109 private int quickSaveButton = SDL_CONTROLLER_BUTTON_X; 110 private KeypadState state; 111 private bool save = false; 112 113 public void map(Button button, int controllerButton) { 114 buttonCodeMap[button] = controllerButton; 115 } 116 117 public void map(Button button, int controllerAxis, float percent, bool direction) { 118 int threshold = cast(int) ((percent < 0 ? 0 : percent > 1 ? 1 : percent) * 0xFFFF - 0x8000); 119 stickMap[button] = StickMapping(controllerAxis, threshold, direction); 120 } 121 122 public override void create() { 123 if (controller) { 124 return; 125 } 126 if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { 127 if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) { 128 throw new Exception("Failed to initialize the SDL controller system", toDString(SDL_GetError())); 129 } 130 } 131 foreach (i; 0 .. SDL_NumJoysticks()) { 132 if (SDL_IsGameController(i)) { 133 controller = SDL_GameControllerOpen(i); 134 if (!controller) { 135 throw new Exception("Could not open controller", toDString(SDL_GetError())); 136 } 137 return; 138 } 139 } 140 throw new Exception("No controller found"); 141 } 142 143 public override void destroy() { 144 if (controller) { 145 SDL_GameControllerClose(controller); 146 } 147 } 148 149 public override void poll() { 150 if (!controller) { 151 return; 152 } 153 state.clear(); 154 foreach (buttonIndex, buttonCode; buttonCodeMap) { 155 if (buttonCode == SDL_CONTROLLER_BUTTON_INVALID) { 156 continue; 157 } 158 state.setPressed(cast(Button) buttonIndex, cast(bool) SDL_GameControllerGetButton(controller, buttonCode)); 159 } 160 foreach (buttonIndex, stick; stickMap) { 161 if (stick.axis == SDL_CONTROLLER_AXIS_INVALID) { 162 continue; 163 } 164 auto amplitude = cast(int) SDL_GameControllerGetAxis(controller, stick.axis); 165 if ((stick.direction ? amplitude : -amplitude) >= stick.threshold) { 166 state.setPressed(cast(Button) buttonIndex); 167 } 168 } 169 save = cast(bool) SDL_GameControllerGetButton(controller, quickSaveButton); 170 } 171 172 @property public override KeypadState keypadState() { 173 return state; 174 } 175 176 @property public override bool quickSave() { 177 return save; 178 } 179 180 @property public override uint lastDigit() { 181 return 0; 182 } 183 184 private static struct StickMapping { 185 private int axis = SDL_CONTROLLER_AXIS_INVALID; 186 private int threshold; 187 private bool direction; 188 } 189 }