19 using std::make_shared;
26 : eventDistributor(eventDistributor_)
27 , globalSettings(globalSettings_)
29 commandController,
"grabinput",
30 "This setting controls if openMSX takes over mouse and keyboard input",
32 , escapeGrabCmd(commandController)
33 , escapeGrabState(ESCAPE_GRAB_WAIT_CMD)
38 osdControlButtonsState = unsigned(~0);
40 #ifndef SDL_JOYSTICK_DISABLED
41 SDL_JoystickEventState(SDL_ENABLE);
53 if (!SDL_WasInit(SDL_INIT_VIDEO)) {
57 if (SDL_WaitEvent(
nullptr)) {
93 SDL_Event event1, event2;
98 while (SDL_PollEvent(curr)) {
101 if ((prev->type == SDL_KEYDOWN) && (curr->type == SDL_TEXTINPUT)) {
102 const char*
utf8 = curr->text.text;
104 handleKeyDown(prev->key, unicode);
113 if (curr->type == SDL_KEYDOWN) {
115 std::swap(curr, prev);
125 void InputEventGenerator::setNewOsdControlButtonState(
126 unsigned newState,
const EventPtr& origEvent)
128 unsigned deltaState = osdControlButtonsState ^ newState;
131 if (deltaState & (1 << i)) {
132 if (newState & (1 << i)) {
134 make_shared<OsdControlReleaseEvent>(
138 make_shared<OsdControlPressEvent>(
143 osdControlButtonsState = newState;
146 void InputEventGenerator::triggerOsdControlEventsFromJoystickAxisMotion(
147 unsigned axis,
int value,
const EventPtr& origEvent)
149 auto [neg_button, pos_button] = [&] {
160 return std::pair{0u, 0u};
166 setNewOsdControlButtonState(
167 (osdControlButtonsState | neg_button) & ~pos_button,
169 }
else if (value < 0) {
171 setNewOsdControlButtonState(
172 (osdControlButtonsState | pos_button) & ~neg_button,
176 setNewOsdControlButtonState(
177 osdControlButtonsState | neg_button | pos_button,
182 void InputEventGenerator::triggerOsdControlEventsFromJoystickHat(
183 int value,
const EventPtr& origEvent)
192 setNewOsdControlButtonState(ab | dir, origEvent);
195 void InputEventGenerator::osdControlChangeButton(
196 bool up,
unsigned changedButtonMask,
const EventPtr& origEvent)
198 auto newButtonState = up
199 ? osdControlButtonsState | changedButtonMask
200 : osdControlButtonsState & ~changedButtonMask;
201 setNewOsdControlButtonState(newButtonState, origEvent);
204 void InputEventGenerator::triggerOsdControlEventsFromJoystickButtonEvent(
205 unsigned button,
bool up,
const EventPtr& origEvent)
207 osdControlChangeButton(
214 void InputEventGenerator::triggerOsdControlEventsFromKeyEvent(
217 unsigned buttonMask = [&] {
231 osdControlChangeButton(!up, buttonMask, origEvent);
233 osdControlChangeButton(up, buttonMask, origEvent);
237 static Uint16 normalizeModifier(SDL_Keycode sym, Uint16 mod)
244 return (sym ==
one_of(SDLK_LCTRL, SDLK_LSHIFT, SDLK_LALT, SDLK_LGUI,
245 SDLK_RCTRL, SDLK_RSHIFT, SDLK_RALT, SDLK_RGUI,
251 void InputEventGenerator::handleKeyDown(
const SDL_KeyboardEvent& key, uint32_t unicode)
265 auto mod = normalizeModifier(key.keysym.sym, key.keysym.mod);
267 key.keysym.sym, mod, key.keysym.scancode,
false);
268 event = make_shared<KeyDownEvent>(keyCode, scanCode, unicode);
269 triggerOsdControlEventsFromKeyEvent(keyCode,
false, key.repeat, event);
274 void InputEventGenerator::handleText(
const char*
utf8)
278 if (unicode == 0)
return;
284 void InputEventGenerator::handle(
const SDL_Event& evt)
307 auto mod = normalizeModifier(evt.key.keysym.sym, evt.key.keysym.mod);
309 evt.key.keysym.sym, mod, evt.key.keysym.scancode,
true);
310 event = make_shared<KeyUpEvent>(keyCode, scanCode);
312 triggerOsdControlEventsFromKeyEvent(keyCode,
true,
repeat, event);
316 handleKeyDown(evt.key, 0);
319 case SDL_MOUSEBUTTONUP:
320 event = make_shared<MouseButtonUpEvent>(evt.button.button);
322 case SDL_MOUSEBUTTONDOWN:
323 event = make_shared<MouseButtonDownEvent>(evt.button.button);
325 case SDL_MOUSEWHEEL: {
328 if (evt.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
333 event = make_shared<MouseWheelEvent>(
x, y);
336 case SDL_MOUSEMOTION:
337 event = make_shared<MouseMotionEvent>(
338 evt.motion.xrel, evt.motion.yrel,
339 evt.motion.x, evt.motion.y);
342 case SDL_JOYBUTTONUP:
343 event = make_shared<JoystickButtonUpEvent>(
344 evt.jbutton.which, evt.jbutton.button);
345 triggerOsdControlEventsFromJoystickButtonEvent(
346 evt.jbutton.button,
true, event);
348 case SDL_JOYBUTTONDOWN:
349 event = make_shared<JoystickButtonDownEvent>(
350 evt.jbutton.which, evt.jbutton.button);
351 triggerOsdControlEventsFromJoystickButtonEvent(
352 evt.jbutton.button,
false, event);
354 case SDL_JOYAXISMOTION: {
356 int threshold = (setting.getInt() * 32768) / 100;
357 auto value = (evt.jaxis.value < -threshold) ? evt.jaxis.value
358 : (evt.jaxis.value > threshold) ? evt.jaxis.value
360 event = make_shared<JoystickAxisMotionEvent>(
361 evt.jaxis.which, evt.jaxis.axis, value);
362 triggerOsdControlEventsFromJoystickAxisMotion(
363 evt.jaxis.axis, value, event);
366 case SDL_JOYHATMOTION:
367 event = make_shared<JoystickHatEvent>(
368 evt.jhat.which, evt.jhat.hat, evt.jhat.value);
369 triggerOsdControlEventsFromJoystickHat(evt.jhat.value, event);
373 handleText(evt.text.text);
376 case SDL_WINDOWEVENT:
377 switch (evt.window.event) {
378 case SDL_WINDOWEVENT_FOCUS_GAINED:
379 event = make_shared<FocusEvent>(
true);
381 case SDL_WINDOWEVENT_FOCUS_LOST:
382 event = make_shared<FocusEvent>(
false);
384 case SDL_WINDOWEVENT_RESIZED:
385 event = make_shared<ResizeEvent>(
386 evt.window.data1, evt.window.data2);
388 case SDL_WINDOWEVENT_EXPOSED:
398 SDL_free(evt.drop.file);
402 event = make_shared<QuitEvent>();
411 std::cerr <<
"SDL event converted to: " <<
event->toString() <<
'\n';
413 std::cerr <<
"SDL event was of unknown type, not converted to an openMSX event\n";
423 escapeGrabState = ESCAPE_GRAB_WAIT_CMD;
427 int InputEventGenerator::signalEvent(
const std::shared_ptr<const Event>& event)
429 const auto& focusEvent = checked_cast<const FocusEvent&>(*event);
430 switch (escapeGrabState) {
431 case ESCAPE_GRAB_WAIT_CMD:
434 case ESCAPE_GRAB_WAIT_LOST:
435 if (!focusEvent.getGain()) {
436 escapeGrabState = ESCAPE_GRAB_WAIT_GAIN;
439 case ESCAPE_GRAB_WAIT_GAIN:
440 if (focusEvent.getGain()) {
441 escapeGrabState = ESCAPE_GRAB_WAIT_CMD;
451 void InputEventGenerator::setGrabInput(
bool grab)
453 SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
471 return SDL_JoystickNumButtons(joystick);
478 case 0:
return androidButtonA;
479 case 1:
return androidButtonB;
483 return SDL_JoystickGetButton(joystick, button) != 0;
490 InputEventGenerator::EscapeGrabCmd::EscapeGrabCmd(
492 :
Command(commandController_,
"escape_grab")
496 void InputEventGenerator::EscapeGrabCmd::execute(
499 auto& inputEventGenerator =
OUTER(InputEventGenerator, escapeGrabCmd);
500 if (inputEventGenerator.grabInput.getBoolean()) {
501 inputEventGenerator.escapeGrabState =
502 InputEventGenerator::ESCAPE_GRAB_WAIT_LOST;
503 inputEventGenerator.setGrabInput(
false);
507 string InputEventGenerator::EscapeGrabCmd::help(
508 const vector<string>& )
const
510 return "Temporarily release input grab.";