ManaPlus
sdlinput.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2011-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 /* _______ __ __ __ ______ __ __ _______ __ __
23  * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
24  * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
25  * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
26  * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
27  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
28  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
29  *
30  * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson
31  * Copyright (C) 2007-2010 The Mana World Development Team
32  *
33  * Js_./
34  * Per Larsson a.k.a finalman _RqZ{a<^_aa
35  * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a//
36  * _Qhm`] _f "'c 1!5m
37  * Visit: http://guichan.darkbits.org )Qk<P ` _: :+' .' "{[
38  * .)j(] .d_/ '-( P . S
39  * License: (BSD) <Td/Z <fP"5(\"??"\a. .L
40  * Redistribution and use in source and _dV>ws?a-?' ._/L #'
41  * binary forms, with or without )4d[#7r, . ' )d`)[
42  * modification, are permitted provided _Q-5'5W..j/?' -?!\‍)cam'
43  * that the following conditions are met: j<<WP+k/);. _W=j f
44  * 1. Redistributions of source code must .$%w\/]Q . ."' . mj$
45  * retain the above copyright notice, ]E.pYY(Q]>. a J@\
46  * this list of conditions and the j(]1u<sE"L,. . ./^ ]{a
47  * following disclaimer. 4'_uomm\. )L);-4 (3=
48  * 2. Redistributions in binary form must )_]X{Z('a_"a7'<a"a, ]"[
49  * reproduce the above copyright notice, #}<]m7`Za??4,P-"'7. ).m
50  * this list of conditions and the ]d2e)Q(<Q( ?94 b- LQ/
51  * following disclaimer in the <B!</]C)d_, '(<' .f. =C+m
52  * documentation and/or other materials .Z!=J ]e []('-4f _ ) -.)m]'
53  * provided with the distribution. .w[5]' _[ /.)_-"+? _/ <W"
54  * 3. Neither the name of Guichan nor the :$we` _! + _/ . j?
55  * names of its contributors may be used =3)= _f (_yQmWW$#( "
56  * to endorse or promote products derived - W, sQQQQmZQ#Wwa]..
57  * from this software without specific (js, \[QQW$QWW#?!V"".
58  * prior written permission. ]y:.<\.. .
59  * -]n w/ ' [.
60  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT )/ )/ !
61  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY < (; sac , '
62  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ]^ .- %
63  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF c < r
64  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR aga< <La
65  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 5% )P'-3L
66  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR _bQf` y`..)a
67  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ,J?4P'.P"_(\?d'.,
68  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES _Pa,)!f/<[]/ ?"
69  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT _2-..:. .r+_,.. .
70  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ?a.<%"' " -'.a_ _,
71  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ^
72  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
73  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
74  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
75  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
76  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77  */
78 
79 #include "sdlshared.h"
80 
81 #include "input/inputmanager.h"
82 
83 #include "gui/gui.h"
84 #include "gui/sdlinput.h"
85 
86 #include "render/graphics.h"
87 
88 PRAGMA48(GCC diagnostic push)
89 PRAGMA48(GCC diagnostic ignored "-Wshadow")
90 #include <SDL_timer.h>
91 PRAGMA48(GCC diagnostic pop)
92 
93 #include "debug.h"
94 
95 #ifdef __SWITCH__
96 bool keyboardClosed = false;
97 #endif
98 
99 extern volatile time_t cur_time;
100 
101 SDLInput *guiInput = nullptr;
102 
104  mKeyInputQueue(),
105  mMouseInputQueue(),
106  mMouseMoveTime(0),
107  mMouseDown(false),
108  mMouseInWindow(true)
109 {
110 }
111 
113 {
114  if (mKeyInputQueue.empty())
115  return KeyInput();
116 
117  KeyInput keyInput = mKeyInputQueue.front();
118  mKeyInputQueue.pop();
119 
120  return keyInput;
121 }
122 
124 {
125  MouseInput mouseInput;
126 
127  if (mMouseInputQueue.empty())
128  return MouseInput();
129 
130  mouseInput = mMouseInputQueue.front();
131  mMouseInputQueue.pop();
132 
133  return mouseInput;
134 }
135 
136 void SDLInput::pushInput(const SDL_Event &event)
137 {
138  BLOCK_START("SDLInput::pushInput")
139  KeyInput keyInput;
140  MouseInput mouseInput;
141 
142 #ifdef __SWITCH__
143  // send an enter/select key on keyboard dismiss event
144  bool visible = SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE;
145  if (visible)
146  {
147  keyboardClosed = false;
148  }
149  else if (!keyboardClosed)
150  {
152  keyboardClosed = true;
153  }
154 #endif
155 
156  switch (event.type)
157  {
158  case SDL_KEYDOWN:
159  {
160  keyInput.setType(KeyEventType::PRESSED);
161  convertKeyEventToKey(event, keyInput);
162  mKeyInputQueue.push(keyInput);
163  break;
164  }
165 
166  case SDL_KEYUP:
167  {
169  convertKeyEventToKey(event, keyInput);
170  mKeyInputQueue.push(keyInput);
171  break;
172  }
173 
174 #ifdef USE_SDL2
175  case SDL_TEXTINPUT:
176  keyInput.setType(KeyEventType::PRESSED);
177  keyInput.setKey(Key(KeyValue::TEXTINPUT));
178  keyInput.setText(event.text.text);
179  mKeyInputQueue.push(keyInput);
180  break;
181 
182  case SDL_MOUSEWHEEL:
183  {
184  const int y = event.wheel.y;
185  if (y)
186  {
187  mouseInput.setX(gui->getLastMouseX());
188  mouseInput.setY(gui->getLastMouseY());
189 #ifdef ANDROID
190  mouseInput.setReal(0, 0);
191 #endif // ANDROID
192 
193  mouseInput.setButton(MouseButton::WHEEL);
194  if (y > 0)
196  else
198  mouseInput.setTimeStamp(SDL_GetTicks());
199  mMouseInputQueue.push(mouseInput);
200  }
201 
202  break;
203  }
204 #endif // USE_SDL2
205 
206 #ifdef ANDROID
207 #ifndef USE_SDL2
208  case SDL_ACCELEROMETER:
209  break;
210 #endif // USE_SDL2
211 #endif // ANDROID
212 
213  case SDL_MOUSEBUTTONDOWN:
214  {
215  mMouseDown = true;
216  const int scale = mainGraphics->getScale();
217  const int x = event.button.x / scale;
218  const int y = event.button.y / scale;
219  mouseInput.setX(x);
220  mouseInput.setY(y);
221 #ifdef ANDROID
222 #ifdef USE_SDL2
223  mouseInput.setReal(x, y);
224 #else // USE_SDL2
225 
226  mouseInput.setReal(event.button.realx / scale,
227  event.button.realy / scale);
228 #endif // USE_SDL2
229 #endif // ANDROID
230 
231  mouseInput.setButton(convertMouseButton(event.button.button));
232 
233 #ifndef USE_SDL2
234  if (event.button.button == SDL_BUTTON_WHEELDOWN)
236  else if (event.button.button == SDL_BUTTON_WHEELUP)
238  else
239 #endif // USE_SDL2
240  mouseInput.setType(MouseEventType::PRESSED);
241  mouseInput.setTimeStamp(SDL_GetTicks());
242  mMouseInputQueue.push(mouseInput);
243  break;
244  }
245  case SDL_MOUSEBUTTONUP:
246  {
247  mMouseDown = false;
248  const int scale = mainGraphics->getScale();
249  const int x = event.button.x / scale;
250  const int y = event.button.y / scale;
251  mouseInput.setX(x);
252  mouseInput.setY(y);
253 #ifdef ANDROID
254 #ifdef USE_SDL2
255  mouseInput.setReal(x, y);
256 #else // USE_SDL2
257 
258  mouseInput.setReal(event.button.realx / scale,
259  event.button.realy / scale);
260 #endif // USE_SDL2
261 #endif // ANDROID
262 
263  mouseInput.setButton(convertMouseButton(event.button.button));
264  mouseInput.setType(MouseEventType::RELEASED);
265  mouseInput.setTimeStamp(SDL_GetTicks());
266  mMouseInputQueue.push(mouseInput);
267  break;
268  }
269  case SDL_MOUSEMOTION:
270  {
271  const int scale = mainGraphics->getScale();
272  const int x = event.motion.x / scale;
273  const int y = event.motion.y / scale;
274  mouseInput.setX(x);
275  mouseInput.setY(y);
276 #ifdef ANDROID
277 #ifdef USE_SDL2
278  mouseInput.setReal(x, y);
279 #else // USE_SDL2
280 
281  mouseInput.setReal(event.motion.realx / scale,
282  event.motion.realy / scale);
283 #endif // USE_SDL2
284 #endif // ANDROID
285 
286  mouseInput.setButton(MouseButton::EMPTY);
287  mouseInput.setType(MouseEventType::MOVED);
288  mouseInput.setTimeStamp(SDL_GetTicks());
289  mMouseInputQueue.push(mouseInput);
291  break;
292  }
293 #ifndef USE_SDL2
294  case SDL_ACTIVEEVENT:
295  /*
296  * This occurs when the mouse leaves the window and the Gui-chan
297  * application loses its mousefocus.
298  */
299  if ((event.active.state & SDL_APPMOUSEFOCUS) != 0 &&
300  event.active.gain == 0U)
301  {
302  mMouseInWindow = false;
303 
304  if (!mMouseDown)
305  {
306  mouseInput.setX(-1);
307  mouseInput.setY(-1);
308  mouseInput.setButton(MouseButton::EMPTY);
309  mouseInput.setType(MouseEventType::MOVED);
310  mMouseInputQueue.push(mouseInput);
312  }
313  }
314 
315  if ((event.active.state & SDL_APPMOUSEFOCUS) != 0 &&
316  event.active.gain != 0U)
317  {
318  mMouseInWindow = true;
319  }
320  break;
321 #endif // USE_SDL2
322 
323  default:
324  break;
325  } // end switch
326  BLOCK_END("SDLInput::pushInput")
327 }
328 
329 void SDLInput::convertKeyEventToKey(const SDL_Event &event, KeyInput &keyInput)
330 {
331  keyInput.setKey(Key(convertKeyCharacter(event)));
332  const InputActionT actionId = inputManager.getActionByKey(event);
333  if (actionId > InputAction::NO_VALUE)
334  keyInput.setActionId(actionId);
335 }
336 
338 {
339  switch (button)
340  {
341  case SDL_BUTTON_LEFT:
342  return MouseButton::LEFT;
343  case SDL_BUTTON_RIGHT:
344  return MouseButton::RIGHT;
345  case SDL_BUTTON_MIDDLE:
346  return MouseButton::MIDDLE;
347 #ifndef USE_SDL2
348  case SDL_BUTTON_WHEELUP:
349  case SDL_BUTTON_WHEELDOWN:
350  return MouseButton::EMPTY;
351 #endif // USE_SDL2
352 
353  default:
354  // We have an unknown mouse type which is ignored.
355  logger->log("unknown button type: %d", button);
356  return MouseButton::EMPTY;
357  }
358 }
359 
360 void SDLInput::simulateMouseClick(const int x, const int y,
361  const MouseButtonT button)
362 {
363  MouseInput mouseInput;
364  mouseInput.setX(x);
365  mouseInput.setY(y);
366  mouseInput.setReal(x, y);
367  mouseInput.setButton(MouseButton::EMPTY);
368  mouseInput.setType(MouseEventType::MOVED);
369  mouseInput.setTimeStamp(SDL_GetTicks());
370  mMouseInputQueue.push(mouseInput);
371  mouseInput.setButton(button);
372  mouseInput.setType(MouseEventType::PRESSED);
373  mouseInput.setTimeStamp(SDL_GetTicks());
374  mMouseInputQueue.push(mouseInput);
375  mouseInput.setType(MouseEventType::RELEASED);
376  mouseInput.setTimeStamp(SDL_GetTicks());
377  mMouseInputQueue.push(mouseInput);
378 }
379 
381 {
382  if (gui == nullptr)
383  return;
384 
385  if (mMouseMoveTime == cur_time)
386  return;
387 
389  int x;
390  int y;
392 
393  MouseInput mouseInput;
394  mouseInput.setX(x);
395  mouseInput.setY(y);
396  mouseInput.setReal(x, y);
397  mouseInput.setButton(MouseButton::EMPTY);
398  mouseInput.setType(MouseEventType::MOVED);
399  mouseInput.setTimeStamp(SDL_GetTicks());
400  mMouseInputQueue.push(mouseInput);
401 }
402 
403 void SDLInput::simulateKey(const int guiKey,
404  const InputActionT actionId)
405 {
406  KeyInput keyInput;
407  keyInput.setType(KeyEventType::PRESSED);
408 #ifdef USE_SDL2
409  char str[2];
410  str[0] = CAST_S8(guiKey);
411  str[1] = 0;
412 
413  keyInput.setKey(Key(KeyValue::TEXTINPUT));
414  keyInput.setText(str);
415  if (guiKey >= 32)
416  mKeyInputQueue.push(keyInput);
417 #endif // USE_SDL2
418 
419  keyInput.setKey(Key(guiKey));
420  if (actionId > InputAction::NO_VALUE)
421  keyInput.setActionId(actionId);
422  mKeyInputQueue.push(keyInput);
424  mKeyInputQueue.push(keyInput);
425 }
#define CAST_S8
Definition: cast.h:26
int getScale() const
Definition: graphics.h:366
static uint8_t getMouseState(int &x, int &y)
Definition: gui.cpp:1171
int getLastMouseX() const
Definition: gui.h:224
int getLastMouseY() const
Definition: gui.h:227
InputActionT getActionByKey(const SDL_Event &event) const
void setKey(const Key &key)
Definition: keyinput.h:128
void setType(KeyEventTypeT type)
Definition: keyinput.h:118
void setActionId(const InputActionT n)
Definition: keyinput.h:138
Definition: key.h:81
void log(const char *const log_text,...)
Definition: logger.cpp:269
void setY(int y)
Definition: mouseinput.h:154
void setButton(MouseButtonT button)
Definition: mouseinput.h:124
void setReal(const int x, const int y)
Definition: mouseinput.h:164
void setTimeStamp(int timeStamp)
Definition: mouseinput.h:139
void setX(int x)
Definition: mouseinput.h:144
void setType(MouseEventTypeT type)
Definition: mouseinput.h:114
static MouseButtonT convertMouseButton(const int button)
Definition: sdlinput.cpp:337
bool mMouseDown
Definition: sdlinput.h:384
static int convertKeyCharacter(const SDL_Event &event)
Definition: sdlinput.h:157
static void convertKeyEventToKey(const SDL_Event &event, KeyInput &keyInput)
Definition: sdlinput.cpp:329
void simulateKey(const int guiKey, const InputActionT actionId)
Definition: sdlinput.cpp:403
time_t mMouseMoveTime
Definition: sdlinput.h:382
void simulateMouseClick(const int x, const int y, const MouseButtonT button)
Definition: sdlinput.cpp:360
std::queue< KeyInput > mKeyInputQueue
Definition: sdlinput.h:380
MouseInput dequeueMouseInput()
Definition: sdlinput.cpp:123
std::queue< MouseInput > mMouseInputQueue
Definition: sdlinput.h:381
bool mMouseInWindow
Definition: sdlinput.h:385
void simulateMouseMove()
Definition: sdlinput.cpp:380
KeyInput dequeueKeyInput()
Definition: sdlinput.cpp:112
void pushInput(const SDL_Event &event)
Definition: sdlinput.cpp:136
Graphics * mainGraphics
Definition: graphics.cpp:109
Gui * gui
Definition: gui.cpp:111
InputAction ::T InputActionT
Definition: inputaction.h:717
InputManager inputManager
#define PRAGMA48(str)
Definition: localconsts.h:199
Logger * logger
Definition: logger.cpp:89
MouseButton ::T MouseButtonT
Definition: mousebutton.h:78
@ ENTER
Definition: keyvalue.h:83
@ TEXTINPUT
Definition: keyvalue.h:128
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
SDLInput * guiInput
Definition: sdlinput.cpp:101
volatile time_t cur_time
Definition: timer.cpp:58