ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

resvm-sdl-events.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/scummsys.h"
00024 
00025 #if defined(SDL_BACKEND)
00026 
00027 #include "backends/events/sdl/resvm-sdl-events.h"
00028 #include "backends/graphics/sdl/resvm-sdl-graphics.h"
00029 #include "engines/engine.h"
00030 #include "gui/gui-manager.h"
00031 #include "common/config-manager.h"
00032 
00033 #if defined(ENABLE_VKEYBD) && SDL_VERSION_ATLEAST(2, 0, 0)
00034 #define CONTROLLER_BUT_VKEYBOARD SDL_CONTROLLER_BUTTON_BACK
00035 #endif
00036 
00037 // FIXME move joystick defines out and replace with confile file options
00038 // we should really allow users to map any key to a joystick button
00039 
00040 // #define JOY_INVERT_Y
00041 #define JOY_XAXIS 0
00042 #define JOY_YAXIS 1
00043 // buttons
00044 #define JOY_BUT_LMOUSE 0
00045 #define JOY_BUT_RMOUSE 2
00046 #define JOY_BUT_ESCAPE 3
00047 #define JOY_BUT_PERIOD 1
00048 #define JOY_BUT_SPACE 4
00049 #define JOY_BUT_F5 5
00050 #ifdef ENABLE_VKEYBD
00051 #define JOY_BUT_VKEYBOARD 7
00052 #endif
00053 
00054 ResVmSdlEventSource::ResVmSdlEventSource() {
00055     // Reset mouse state
00056     memset(&_km, 0, sizeof(_km));
00057 
00058     ConfMan.registerDefault("kbdmouse_speed", 3);
00059     ConfMan.registerDefault("joystick_deadzone", 3);
00060 }
00061 
00062 bool ResVmSdlEventSource::processMouseEvent(Common::Event &event, int x, int y, int relx, int rely) {
00063     event.relMouse.x = relx;
00064     event.relMouse.y = rely;
00065 
00066     return SdlEventSource::processMouseEvent(event, x, y);
00067 }
00068 
00069 bool ResVmSdlEventSource::pollEvent(Common::Event &event) {
00070     bool state = SdlEventSource::pollEvent(event);
00071 
00072     // Handle mouse control via analog joystick and keyboard
00073     if (!state && handleKbdMouse(event)) {
00074         return true;
00075     }
00076 
00077     return state;
00078 }
00079 
00080 bool ResVmSdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
00081     // update KbdMouse
00082     _km.x = ev.motion.x * MULTIPLIER;
00083     _km.y = ev.motion.y * MULTIPLIER;
00084 
00085     return SdlEventSource::handleMouseMotion(ev, event);
00086 }
00087 
00088 bool ResVmSdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
00089     // update KbdMouse
00090     _km.x = ev.motion.x * MULTIPLIER;
00091     _km.y = ev.motion.y * MULTIPLIER;
00092 
00093     return SdlEventSource::handleMouseButtonDown(ev, event);
00094 }
00095 
00096 bool ResVmSdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
00097     // update KbdMouse
00098     _km.x = ev.motion.x * MULTIPLIER;
00099     _km.y = ev.motion.y * MULTIPLIER;
00100 
00101     return SdlEventSource::handleMouseButtonUp(ev, event);
00102 }
00103 
00104 bool ResVmSdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
00105     if (shouldGenerateMouseEvents()) {
00106         if (ev.jbutton.button == JOY_BUT_LMOUSE) {
00107             event.type = Common::EVENT_LBUTTONDOWN;
00108             return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
00109         } else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
00110             event.type = Common::EVENT_RBUTTONDOWN;
00111             return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
00112         }
00113     }
00114 
00115     return SdlEventSource::handleJoyButtonDown(ev, event);
00116 }
00117 
00118 bool ResVmSdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
00119     if (shouldGenerateMouseEvents()) {
00120         if (ev.jbutton.button == JOY_BUT_LMOUSE) {
00121             event.type = Common::EVENT_LBUTTONUP;
00122             return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
00123         } else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
00124             event.type = Common::EVENT_RBUTTONUP;
00125             return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
00126         }
00127     }
00128 
00129     return SdlEventSource::handleJoyButtonUp(ev, event);
00130 }
00131 
00132 bool ResVmSdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
00133     if (shouldGenerateMouseEvents()) {
00134         if (ev.jaxis.axis == JOY_XAXIS) {
00135             _km.joy_x = ev.jaxis.value;
00136             return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
00137         } else if (ev.jaxis.axis == JOY_YAXIS) {
00138             _km.joy_y = ev.jaxis.value;
00139             return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
00140         }
00141     }
00142 
00143     return SdlEventSource::handleJoyAxisMotion(ev, event);
00144 }
00145 
00146 #if SDL_VERSION_ATLEAST(2, 0, 0)
00147 
00148 static int mapSDLControllerButtonToResVM(Uint8 sdlButton) {
00149     Common::JoystickButton resvmButtons[] = {
00150         Common::JOYSTICK_BUTTON_A,
00151         Common::JOYSTICK_BUTTON_B,
00152         Common::JOYSTICK_BUTTON_X,
00153         Common::JOYSTICK_BUTTON_Y,
00154         Common::JOYSTICK_BUTTON_BACK,
00155         Common::JOYSTICK_BUTTON_GUIDE,
00156         Common::JOYSTICK_BUTTON_START,
00157         Common::JOYSTICK_BUTTON_LEFT_STICK,
00158         Common::JOYSTICK_BUTTON_RIGHT_STICK,
00159         Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
00160         Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
00161         Common::JOYSTICK_BUTTON_DPAD_UP,
00162         Common::JOYSTICK_BUTTON_DPAD_DOWN,
00163         Common::JOYSTICK_BUTTON_DPAD_LEFT,
00164         Common::JOYSTICK_BUTTON_DPAD_RIGHT,
00165     };
00166 
00167     if (sdlButton >= ARRAYSIZE(resvmButtons)) {
00168         return -1;
00169     }
00170 
00171     return resvmButtons[sdlButton];
00172 }
00173 
00174 bool ResVmSdlEventSource::handleControllerButton(const SDL_Event &ev, Common::Event &event, bool buttonUp) {
00175     if (shouldGenerateMouseEvents()) {
00176         return SdlEventSource::handleControllerButton(ev, event, buttonUp);
00177     } else {
00178 #ifdef ENABLE_VKEYBD
00179         // Trigger virtual keyboard on long press of more than 1 second of configured button
00180         const uint32 vkeybdTime = 1000;
00181         static uint32 vkeybdThen = 0;
00182 
00183         if (ev.cbutton.button == CONTROLLER_BUT_VKEYBOARD) {
00184             if (!buttonUp) {
00185                 vkeybdThen = g_system->getMillis();
00186             } else if ((vkeybdThen > 0) && (g_system->getMillis() - vkeybdThen >= vkeybdTime)) {
00187                 vkeybdThen = 0;
00188                 event.type = Common::EVENT_VIRTUAL_KEYBOARD;
00189                 return true;
00190             }
00191         }
00192 #endif
00193         int button = mapSDLControllerButtonToResVM(ev.cbutton.button);
00194         if (button == -1) {
00195             return false;
00196         }
00197 
00198         event.type = buttonUp ? Common::EVENT_JOYBUTTON_UP : Common::EVENT_JOYBUTTON_DOWN;
00199         event.joystick.button = button;
00200         return true;
00201     }
00202 }
00203 
00204 bool ResVmSdlEventSource::handleControllerAxisMotion(const SDL_Event &ev, Common::Event &event) {
00205     if (shouldGenerateMouseEvents()) {
00206         if (ev.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX) {
00207             _km.joy_x = ev.caxis.value;
00208             return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
00209         } else if (ev.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY) {
00210             _km.joy_y = ev.caxis.value;
00211             return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
00212         }
00213         return SdlEventSource::handleControllerAxisMotion(ev, event);
00214     } else {
00215         // Indicates if L2/R2 are currently pushed or not
00216         static bool l2Pushed = false, r2Pushed = false;
00217         // Simulate buttons from left and right triggers (needed for EMI)
00218         if (ev.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) {
00219             bool pushed = (ev.caxis.value > 0);
00220             if (l2Pushed == pushed)
00221                 return false;
00222             event.type = (pushed) ? Common::EVENT_JOYBUTTON_DOWN : Common::EVENT_JOYBUTTON_UP;
00223             event.joystick.button = Common::JOYSTICK_BUTTON_LEFT_TRIGGER;
00224             l2Pushed = pushed;
00225             return true;
00226         } else if (ev.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {
00227             bool pushed = (ev.caxis.value > 0);
00228             if (r2Pushed == pushed)
00229                 return false;
00230             event.type = (pushed) ? Common::EVENT_JOYBUTTON_DOWN : Common::EVENT_JOYBUTTON_UP;
00231             event.joystick.button = Common::JOYSTICK_BUTTON_RIGHT_TRIGGER;
00232             r2Pushed = pushed;
00233             return true;
00234         } else {
00235             event.type = Common::EVENT_JOYAXIS_MOTION;
00236             event.joystick.axis = ev.caxis.axis;
00237             event.joystick.position = ev.caxis.value;
00238             return true;
00239         }
00240     }
00241 }
00242 #endif
00243 
00244 bool ResVmSdlEventSource::shouldGenerateMouseEvents() {
00245     // Engine doesn't support joystick -> emulate mouse events
00246     if (g_engine && !g_engine->hasFeature(Engine::kSupportsJoystick)) {
00247         return true;
00248     }
00249 
00250     // Even if engine supports joystick, emulate mouse events if in GUI or in virtual keyboard
00251     if (g_gui.isActive() || g_engine->isPaused()) {
00252         return true;
00253     }
00254 
00255     return false;
00256 }
00257 
00258 bool ResVmSdlEventSource::handleKbdMouse(Common::Event &event) {
00259     // The ResidualVM version of this method handles relative mouse
00260     // movement, as required by Myst III.
00261 
00262     int32 oldKmX = _km.x;
00263     int32 oldKmY = _km.y;
00264 
00265     updateKbdMouse();
00266 
00267     if (_km.x != oldKmX || _km.y != oldKmY) {
00268         ResVmSdlGraphicsManager *graphicsManager = dynamic_cast<ResVmSdlGraphicsManager *>(_graphicsManager);
00269 
00270         int32 relX = _km.x - oldKmX;
00271         int32 relY = _km.y - oldKmY;
00272 
00273         if (graphicsManager) {
00274             if (graphicsManager->isMouseLocked()) {
00275                 _km.x = oldKmX;
00276                 _km.y = oldKmY;
00277             } else {
00278                 // warpMouseInWindow causes SDL to generate mouse events. Don't use it when the mouse is locked
00279                 // to avoid inconsistent events that would cause crazy camera movement in Myst III.
00280                 graphicsManager->getWindow()->warpMouseInWindow((Uint16)(_km.x / MULTIPLIER), (Uint16)(_km.y / MULTIPLIER));
00281             }
00282         }
00283 
00284         event.type = Common::EVENT_MOUSEMOVE;
00285         return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER, relX / MULTIPLIER, relY / MULTIPLIER);
00286     }
00287 
00288     return false;
00289 }
00290 
00291 bool ResVmSdlEventSource::handleAxisToMouseMotion(int16 xAxis, int16 yAxis) {
00292 #ifdef JOY_INVERT_Y
00293     yAxis = -yAxis;
00294 #endif
00295 
00296     // conversion factor between keyboard mouse and joy axis value
00297     int vel_to_axis = (1500 / MULTIPLIER);
00298 
00299     // radial and scaled deadzone
00300 
00301     float analogX = (float)xAxis;
00302     float analogY = (float)yAxis;
00303     float deadZone = (float)ConfMan.getInt("joystick_deadzone") * 1000.0f;
00304 
00305     float magnitude = sqrt(analogX * analogX + analogY * analogY);
00306 
00307     if (magnitude >= deadZone) {
00308         _km.x_down_count = 0;
00309         _km.y_down_count = 0;
00310         float scalingFactor = 1.0f / magnitude * (magnitude - deadZone) / (32769.0f - deadZone);
00311         _km.x_vel = (int16)(analogX * scalingFactor * 32768.0f / vel_to_axis);
00312         _km.y_vel = (int16)(analogY * scalingFactor * 32768.0f / vel_to_axis);
00313     } else {
00314         _km.x_vel = 0;
00315         _km.y_vel = 0;
00316     }
00317 
00318     return false;
00319 }
00320 
00321 void ResVmSdlEventSource::resetKeyboardEmulation(int16 x_max, int16 y_max) {
00322     _km.x_max = x_max;
00323     _km.y_max = y_max;
00324     _km.delay_time = 12;
00325     _km.last_time = 0;
00326     _km.modifier = false;
00327     _km.joy_x = 0;
00328     _km.joy_y = 0;
00329 }
00330 
00331 void ResVmSdlEventSource::updateKbdMouse() {
00332     uint32 curTime = g_system->getMillis(true);
00333     if (curTime < _km.last_time + _km.delay_time) {
00334         return;
00335     }
00336 
00337     _km.last_time = curTime;
00338     if (_km.x_down_count == 1) {
00339         _km.x_down_time = curTime;
00340         _km.x_down_count = 2;
00341     }
00342     if (_km.y_down_count == 1) {
00343         _km.y_down_time = curTime;
00344         _km.y_down_count = 2;
00345     }
00346 
00347     if (_km.x_vel || _km.y_vel) {
00348         if (_km.x_down_count) {
00349             if (curTime > _km.x_down_time + 300) {
00350                 if (_km.x_vel > 0)
00351                     _km.x_vel += MULTIPLIER;
00352                 else
00353                     _km.x_vel -= MULTIPLIER;
00354             } else if (curTime > _km.x_down_time + 200) {
00355                 if (_km.x_vel > 0)
00356                     _km.x_vel = 5 * MULTIPLIER;
00357                 else
00358                     _km.x_vel = -5 * MULTIPLIER;
00359             }
00360         }
00361         if (_km.y_down_count) {
00362             if (curTime > _km.y_down_time + 300) {
00363                 if (_km.y_vel > 0)
00364                     _km.y_vel += MULTIPLIER;
00365                 else
00366                     _km.y_vel -= MULTIPLIER;
00367             } else if (curTime > _km.y_down_time + 200) {
00368                 if (_km.y_vel > 0)
00369                     _km.y_vel = 5 * MULTIPLIER;
00370                 else
00371                     _km.y_vel = -5 * MULTIPLIER;
00372             }
00373         }
00374 
00375         int16 speedFactor = computeJoystickMouseSpeedFactor();
00376 
00377         // - The modifier key makes the mouse movement slower
00378         // - The extra factor "delay/speedFactor" ensures velocities
00379         // are independent of the kbdMouse update rate
00380         // - all velocities were originally chosen
00381         // at a delay of 25, so that is the reference used here
00382         // - note: operator order is important to avoid overflow
00383         if (_km.modifier) {
00384             _km.x += ((_km.x_vel / 10) * ((int16)_km.delay_time)) / speedFactor;
00385             _km.y += ((_km.y_vel / 10) * ((int16)_km.delay_time)) / speedFactor;
00386         } else {
00387             _km.x += (_km.x_vel * ((int16)_km.delay_time)) / speedFactor;
00388             _km.y += (_km.y_vel * ((int16)_km.delay_time)) / speedFactor;
00389         }
00390 
00391         if (_km.x < 0) {
00392             _km.x = 0;
00393             _km.x_vel = -1 * MULTIPLIER;
00394             _km.x_down_count = 1;
00395         } else if (_km.x > _km.x_max * MULTIPLIER) {
00396             _km.x = _km.x_max * MULTIPLIER;
00397             _km.x_vel = 1 * MULTIPLIER;
00398             _km.x_down_count = 1;
00399         }
00400 
00401         if (_km.y < 0) {
00402             _km.y = 0;
00403             _km.y_vel = -1 * MULTIPLIER;
00404             _km.y_down_count = 1;
00405         } else if (_km.y > _km.y_max * MULTIPLIER) {
00406             _km.y = _km.y_max * MULTIPLIER;
00407             _km.y_vel = 1 * MULTIPLIER;
00408             _km.y_down_count = 1;
00409         }
00410     }
00411 }
00412 
00413 int16 ResVmSdlEventSource::computeJoystickMouseSpeedFactor() const {
00414     int16 speedFactor;
00415 
00416     switch (ConfMan.getInt("kbdmouse_speed")) {
00417     // 0.25 keyboard pointer speed
00418     case 0:
00419         speedFactor = 100;
00420         break;
00421     // 0.5 speed
00422     case 1:
00423         speedFactor = 50;
00424         break;
00425     // 0.75 speed
00426     case 2:
00427         speedFactor = 33;
00428         break;
00429     // 1.0 speed
00430     case 3:
00431         speedFactor = 25;
00432         break;
00433     // 1.25 speed
00434     case 4:
00435         speedFactor = 20;
00436         break;
00437     // 1.5 speed
00438     case 5:
00439         speedFactor = 17;
00440         break;
00441     // 1.75 speed
00442     case 6:
00443         speedFactor = 14;
00444         break;
00445     // 2.0 speed
00446     case 7:
00447         speedFactor = 12;
00448         break;
00449     default:
00450         speedFactor = 25;
00451     }
00452 
00453     // Scale the mouse cursor speed with the display size so moving across
00454     // the screen takes a reasonable amount of time at higher resolutions.
00455     return speedFactor * 480 / _km.y_max;
00456 }
00457 
00458 #endif


Generated on Sat May 30 2020 05:00:30 for ResidualVM by doxygen 1.7.1
curved edge   curved edge