// Copyright (C) 2014-2015 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. #include "nv/sdl/sdl_input.hh" #include "nv/lib/sdl.hh" #include "nv/core/logging.hh" using namespace nv; nv::sdl::input::input() { if ( ! SDL_WasInit( SDL_INIT_JOYSTICK ) ) SDL_InitSubSystem( SDL_INIT_JOYSTICK ); if ( ! SDL_WasInit( SDL_INIT_GAMECONTROLLER ) ) SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER ); } static bool sdl_key_event_to_io_event( const SDL_KeyboardEvent& ke, io_event& kevent ) { kevent.type = EV_KEY; kevent.key.pressed = ( ke.state != SDL_RELEASED ); kevent.key.ascii = 0; kevent.key.code = KEY_NONE; uint32 ucode = (uint32)ke.keysym.sym; // if result is a typable char place it into the structure if (ucode >= 32 && ucode < 128 ) { kevent.key.ascii = static_cast( ucode ); if (ucode >= 'a' && ucode <= 'z') { int shifted = !!(ke.keysym.mod & KMOD_SHIFT); int capslock = !!(ke.keysym.mod & KMOD_CAPS); if ((shifted ^ capslock) != 0) { kevent.key.ascii = (uchar8)SDL_toupper((int)ucode); } } } // Get the Key value from the SDL Keyboard event int result = ke.keysym.sym; // Check the control and shift states kevent.key.alt = (ke.keysym.mod & KMOD_ALT ) != 0; kevent.key.control = (ke.keysym.mod & KMOD_CTRL ) != 0; kevent.key.shift = (ke.keysym.mod & KMOD_SHIFT ) != 0; // if result is a typable char from the directly transformable ranges if ( ( result >= KEY_A && result <= KEY_Z ) || ( result >= KEY_0 && result <= KEY_9 ) || result == ' ' ) { kevent.key.code = static_cast(result); } // if result is a typable char from the a..z range if ( result >= KEY_A + 32 && result <= KEY_Z + 32 ) { kevent.key.code = static_cast(result - 32); } if ( result >= SDLK_F1 && result <= SDLK_F12 ) { kevent.key.code = static_cast(result - SDLK_F1 + KEY_F1 ); } // other recognized codes switch ( result ) { case SDLK_BACKSPACE : kevent.key.code = KEY_BACK; break; case SDLK_TAB : kevent.key.code = KEY_TAB; break; case SDLK_RETURN : kevent.key.code = KEY_ENTER; break; case SDLK_PAGEUP : kevent.key.code = KEY_PGUP; break; case SDLK_PAGEDOWN : kevent.key.code = KEY_PGDOWN; break; case SDLK_END : kevent.key.code = KEY_END; break; case SDLK_HOME : kevent.key.code = KEY_HOME; break; case SDLK_LEFT : kevent.key.code = KEY_LEFT; break; case SDLK_UP : kevent.key.code = KEY_UP; break; case SDLK_RIGHT : kevent.key.code = KEY_RIGHT; break; case SDLK_DOWN : kevent.key.code = KEY_DOWN; break; case SDLK_DELETE : kevent.key.code = KEY_DELETE; break; case SDLK_INSERT : kevent.key.code = KEY_INSERT; break; //case SDLK_KP5 : kevent.key.code = KEY_CENTER; break; case SDLK_ESCAPE : kevent.key.code = KEY_ESCAPE; break; case SDLK_QUOTE : kevent.key.code = KEY_QUOTE; break; case SDLK_COMMA : kevent.key.code = KEY_COMMA; break; case SDLK_MINUS : kevent.key.code = KEY_MINUS; break; case SDLK_PERIOD : kevent.key.code = KEY_PERIOD; break; case SDLK_SLASH : kevent.key.code = KEY_SLASH; break; case SDLK_SEMICOLON : kevent.key.code = KEY_SCOLON; break; case SDLK_LEFTBRACKET : kevent.key.code = KEY_LBRACKET; break; case SDLK_BACKSLASH : kevent.key.code = KEY_BSLASH; break; case SDLK_RIGHTBRACKET : kevent.key.code = KEY_RBRACKET; break; case SDLK_BACKQUOTE : kevent.key.code = KEY_BQUOTE; break; default : break; } kevent.key.native = ke.keysym.scancode; // If key was understood by nv, then it's valid, otherwise ignored return kevent.key.ascii != 0 || kevent.key.code != 0; } static bool sdl_mouse_button_to_io_event( const SDL_MouseButtonEvent& mb, io_event& mevent ) { mevent.type = EV_MOUSE_BUTTON; mevent.mbutton.button = MOUSE_NONE; mevent.mbutton.pressed = (mb.state != SDL_RELEASED); mevent.mbutton.x = static_cast< uint16 >( mb.x ); mevent.mbutton.y = static_cast< uint16 >( mb.y ); switch ( mb.button ) { case SDL_BUTTON_LEFT : mevent.mbutton.button = MOUSE_LEFT; break; case SDL_BUTTON_MIDDLE : mevent.mbutton.button = MOUSE_MIDDLE; break; case SDL_BUTTON_RIGHT : mevent.mbutton.button = MOUSE_RIGHT; break; default : break; } return mevent.mbutton.button != MOUSE_NONE; } static bool sdl_mouse_wheel_to_io_event( const SDL_MouseWheelEvent& mm, io_event& mevent ) { mevent.type = EV_MOUSE_WHEEL; mevent.mwheel.x = static_cast< sint32 >( mm.x ); mevent.mwheel.y = static_cast< sint32 >( mm.y ); return true; } static bool sdl_mouse_motion_to_io_event( const SDL_MouseMotionEvent& mm, io_event& mevent ) { mevent.type = EV_MOUSE_MOVE; mevent.mmove.pressed = (mm.state != SDL_RELEASED); mevent.mmove.x = static_cast< uint16 >( mm.x ); mevent.mmove.y = static_cast< uint16 >( mm.y ); mevent.mmove.rx = static_cast< sint16 >( mm.xrel ); mevent.mmove.ry = static_cast< sint16 >( mm.yrel ); return true; } static bool sdl_pad_button_event_to_io_event( const SDL_ControllerButtonEvent& cb, io_event& cevent ) { cevent.type = EV_PAD_BUTTON; cevent.pbutton.id = cb.which; cevent.pbutton.button = cb.button; cevent.pbutton.pressed = (cb.type == SDL_PRESSED); return true; } static bool sdl_pad_axis_event_to_io_event( const SDL_ControllerAxisEvent& ca, io_event& cevent ) { cevent.type = EV_PAD_AXIS; cevent.paxis.id = ca.which; cevent.paxis.axis = ca.axis; cevent.paxis.value = ca.value; return true; } static bool sdl_joy_button_event_to_io_event( const SDL_JoyButtonEvent& jb, io_event& jevent ) { jevent.type = EV_JOY_BUTTON; jevent.jbutton.id = jb.which; jevent.jbutton.button = jb.button; jevent.jbutton.pressed = (jb.type == SDL_PRESSED); return true; } static bool sdl_joy_axis_event_to_io_event( const SDL_JoyAxisEvent& ja, io_event& jevent ) { jevent.type = EV_JOY_AXIS; jevent.jaxis.id = ja.which; jevent.jaxis.axis = ja.axis; jevent.jaxis.value = ja.value; return true; } static bool sdl_joy_hat_event_to_io_event( const SDL_JoyHatEvent& jh, io_event& jevent ) { jevent.type = EV_JOY_HAT; jevent.jhat.id = jh.which; jevent.jhat.hat = jh.hat; jevent.jhat.value = jh.value; return true; } static bool sdl_joy_ball_event_to_io_event( const SDL_JoyBallEvent& jb, io_event& jevent ) { jevent.type = EV_JOY_HAT; jevent.jball.id = jb.which; jevent.jball.ball = jb.ball; jevent.jball.rx = jb.xrel; jevent.jball.ry = jb.yrel; return true; } static bool sdl_event_to_io_event( const SDL_Event& e, io_event& ioevent ) { switch ( e.type ) { case SDL_KEYDOWN : return sdl_key_event_to_io_event( e.key, ioevent ); case SDL_KEYUP : return sdl_key_event_to_io_event( e.key, ioevent ); case SDL_MOUSEMOTION : return sdl_mouse_motion_to_io_event( e.motion, ioevent ); case SDL_MOUSEBUTTONDOWN : return sdl_mouse_button_to_io_event( e.button, ioevent ); case SDL_MOUSEBUTTONUP : return sdl_mouse_button_to_io_event( e.button, ioevent ); case SDL_MOUSEWHEEL : return sdl_mouse_wheel_to_io_event( e.wheel, ioevent ); /* // SDL 2.0 incompatible case SDL_ACTIVEEVENT : ioevent.type = EV_ACTIVE; ioevent.active.gain = (e.active.gain != 0); return e.active.state == SDL_APPINPUTFOCUS; case SDL_VIDEORESIZE : ioevent.type = EV_RESIZE; ioevent.resize.x = e.resize.w; ioevent.resize.y = e.resize.h; return true; case SDL_NOEVENT : return false; case SDL_VIDEOEXPOSE : return false; */ case SDL_SYSWMEVENT : ioevent.type = EV_SYSTEM; return true; case SDL_QUIT : ioevent.type = EV_QUIT; return true; case SDL_CONTROLLERAXISMOTION : return sdl_pad_axis_event_to_io_event( e.caxis, ioevent ); case SDL_CONTROLLERBUTTONDOWN : return sdl_pad_button_event_to_io_event( e.cbutton, ioevent ); case SDL_CONTROLLERBUTTONUP : case SDL_JOYAXISMOTION : return sdl_joy_axis_event_to_io_event( e.jaxis, ioevent ); case SDL_JOYBALLMOTION : return sdl_joy_ball_event_to_io_event( e.jball, ioevent ); case SDL_JOYHATMOTION : return sdl_joy_hat_event_to_io_event( e.jhat, ioevent ); case SDL_JOYBUTTONDOWN : return sdl_joy_button_event_to_io_event( e.jbutton, ioevent ); case SDL_JOYBUTTONUP : return sdl_joy_button_event_to_io_event( e.jbutton, ioevent ); default : return false; } } bool sdl::input::is_event_pending() { return SDL_PollEvent( nullptr ) != 0; } bool sdl::input::poll_event( io_event& event ) { SDL_Event sdl_event; if ( SDL_PollEvent( &sdl_event ) == 0 ) return false; return sdl_event_to_io_event( sdl_event, event ); }