/*-- * Rubygame -- Ruby bindings to SDL to facilitate game creation * Copyright (C) 2004-2005 John 'jacius' Croisant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *++ */ #include "rubygame.h" #include "rubygame_event.h" void Rubygame_Init_Event(); VALUE cEvent; VALUE cQueue; VALUE cActiveEvent; VALUE cKeyDownEvent; VALUE cKeyUpEvent; VALUE cMouseMotionEvent; VALUE cMouseDownEvent; VALUE cMouseUpEvent; VALUE cJoyAxisEvent; VALUE cJoyBallEvent; VALUE cJoyHatEvent; VALUE cJoyDownEvent; VALUE cJoyUpEvent; VALUE cQuitEvent; VALUE cSysWMEvent; VALUE cResizeEvent; VALUE cExposeEvent; VALUE convert_active(Uint8); VALUE convert_keymod(SDLMod); VALUE convert_mousebuttons(Uint8); VALUE rbgm_convert_sdlevent(SDL_Event); VALUE rbgm_queue_getsdl(VALUE); /* *-- * * SDL Type Ruby type Ruby new() args * --------------------------------------------------------------------------- * SDL_ACTIVEEVENT ActiveEvent gain,state * SDL_KEYDOWN KeyDownEvent key,[mods,...] * SDL_KEYUP KeyUpEvent key,[mods,...] * SDL_MOUSEMOTION MouseMotionEvent [x,y],[xrel,yrel],[buttons,...] * SDL_MOUSEBUTTONDOWN MouseDownEvent [x,y],button * SDL_MOUSEBUTTONUP MouseUpEvent [x,y],button * SDL_JOYAXISMOTION JoyAxisEvent joy,axis,value * SDL_JOYBALLMOTION JoyBallEvent joy,ball,[xrel,yrel] * SDL_JOYHATMOTION JoyHatEvent joy,hat,value * SDL_JOYBUTTONDOWN JoyDownEvent joy,button * SDL_JOYBUTTONUP JoyUpEvent joy,button * SDL_VIDEORESIZE VideoResizeEvent [w,h] * SDL_QUIT QuitEvent (no args) * -------------------------------------------------------------------------- * *++ */ /*-- * * Queue-related functions. * *++ * */ /* Convert info about whether the window has mouse/keyboard focus */ VALUE convert_active( Uint8 state ) { VALUE array; array = rb_ary_new(); if(state != 0) { if(state & SDL_APPMOUSEFOCUS) rb_ary_push(array,rb_str_new2("mouse\0")); if(state & SDL_APPINPUTFOCUS) rb_ary_push(array,rb_str_new2("keyboard\0")); if(state & SDL_APPACTIVE) rb_ary_push(array,rb_str_new2("active\0")); } return array; } /* Convert an OR'd list of KMODs into a Ruby array of keysyms. */ VALUE convert_keymod( SDLMod mods ) { VALUE array; array = rb_ary_new(); if(mods != 0) { /* KEY MODIFIER KEY SYM */ if(mods & KMOD_LSHIFT) rb_ary_push(array,INT2NUM( SDLK_LSHIFT )); if(mods & KMOD_RSHIFT) rb_ary_push(array,INT2NUM( SDLK_RSHIFT )); if(mods & KMOD_LCTRL) rb_ary_push(array,INT2NUM( SDLK_LCTRL )); if(mods & KMOD_RCTRL) rb_ary_push(array,INT2NUM( SDLK_RCTRL )); if(mods & KMOD_LALT) rb_ary_push(array,INT2NUM( SDLK_LALT )); if(mods & KMOD_RALT) rb_ary_push(array,INT2NUM( SDLK_RALT )); if(mods & KMOD_LMETA) rb_ary_push(array,INT2NUM( SDLK_LMETA )); if(mods & KMOD_RMETA) rb_ary_push(array,INT2NUM( SDLK_RMETA )); if(mods & KMOD_NUM) rb_ary_push(array,INT2NUM( SDLK_NUMLOCK )); if(mods & KMOD_CAPS) rb_ary_push(array,INT2NUM( SDLK_CAPSLOCK )); if(mods & KMOD_MODE) rb_ary_push(array,INT2NUM( SDLK_MODE )); } return array; } /* convert a button state into a list of mouse button sym */ VALUE convert_mousebuttons( Uint8 state ) { VALUE buttons; buttons = rb_ary_new(); if(state & SDL_BUTTON(1)) rb_ary_push(buttons, INT2NUM(SDL_BUTTON_LEFT)); if(state & SDL_BUTTON(2)) rb_ary_push(buttons, INT2NUM(SDL_BUTTON_MIDDLE)); if(state & SDL_BUTTON(3)) rb_ary_push(buttons, INT2NUM(SDL_BUTTON_RIGHT)); return buttons; } #if 0 /* * (This method is no longer used, as it depends on unicode enabled in SDL, * and doesn't work for KeyUpEvents) */ /* Convert a unicode char into an ascii string or hex if it is not ascii */ VALUE convert_unicode( Uint16 unicode ) { char *str; if( unicode < 0x80 && unicode > 0 ) asprintf( &str,"%c\0",(char)unicode ); else asprintf( &str,"0x%04X\0",unicode ); return rb_str_new2(str); } #endif /*-- * * call-seq: * rbgm_convert_sdlevent( SDL_Event ) -> Rubygame_Event * * Converts an SDL_Event (C type) into a Rubygame Event of the corresponding * class. * *++ */ VALUE rbgm_convert_sdlevent( SDL_Event ev ) { VALUE new = rb_intern("new"); /* to call new() for any class */ /* switch for each particular type, call new() for the corresponding Rubygame class, with the proper arguments. */ switch(ev.type) { case SDL_ACTIVEEVENT: /* ActiveEvent.new(gain,state) */ return rb_funcall(cActiveEvent,new,2,\ ev.active.gain, convert_active(ev.active.state)); break; case SDL_KEYDOWN: /* KeyDownEvent.new(keysym,[mods,...]) */ return rb_funcall(cKeyDownEvent,new,2,\ /* keysym, string version is set in new()*/ INT2NUM(ev.key.keysym.sym),\ /* convert OR'd list of mods into Array of keysyms */ convert_keymod(ev.key.keysym.mod)\ ); break; case SDL_KEYUP: /* Same as SDL_KEYDOWN */ /* KeyUpEvent.new(keysym,[mods,...]) */ return rb_funcall(cKeyUpEvent,new,2,\ INT2NUM(ev.key.keysym.sym),\ convert_keymod(ev.key.keysym.mod)); break; case SDL_MOUSEMOTION:; /* MouseMotionEvent.new([x,y],[xrel,yrel],[buttons,...]) */ return rb_funcall(cMouseMotionEvent,new,3,\ rb_ary_new3(2,INT2NUM(ev.motion.x),INT2NUM(ev.motion.y)),\ rb_ary_new3(2,INT2NUM(ev.motion.xrel),\ INT2NUM(ev.motion.yrel)),\ /* Prepare list of buttons from OR'd list */ convert_mousebuttons(ev.motion.state)); break; case SDL_MOUSEBUTTONDOWN: /* MouseDownEvent.new([x,y],button) */ return rb_funcall(cMouseDownEvent,new,2,\ rb_ary_new3(2,INT2NUM(ev.button.x),INT2NUM(ev.button.y)),\ INT2NUM(ev.button.button)); break; case SDL_MOUSEBUTTONUP: /* MouseUpEvent.new([x,y],button) */ return rb_funcall(cMouseUpEvent,new,2,\ rb_ary_new3(2,INT2NUM(ev.button.x),INT2NUM(ev.button.y)),\ INT2NUM(ev.button.button)); break; case SDL_JOYAXISMOTION: /* JoyAxisEvent.new(joy,axis,value) */ /* Eventually, joy might be a reference to a Joystick instance? */ return rb_funcall(cJoyAxisEvent,new,3,\ INT2NUM(ev.jaxis.which),INT2NUM(ev.jaxis.axis),\ INT2NUM(ev.jaxis.value)); break; case SDL_JOYBALLMOTION: /* JoyBallEvent.new(joy,ball,) */ /* Eventually, joy might be a reference to a Joystick instance? */ return rb_funcall(cJoyBallEvent,new,3,\ INT2NUM(ev.jball.which),INT2NUM(ev.jball.ball), rb_ary_new3(2,INT2NUM(ev.jball.xrel),INT2NUM(ev.jball.yrel))); break; case SDL_JOYHATMOTION: /* JoyHatEvent.new(joy,hat,value) */ /* Eventually, joy might be a reference to a Joystick instance? */ return rb_funcall(cJoyHatEvent,new,3,\ INT2NUM(ev.jhat.which),INT2NUM(ev.jhat.hat),\ INT2NUM(ev.jhat.value)); break; case SDL_JOYBUTTONDOWN: /* JoyDownEvent.new(joy,button) */ /* Eventually, joy might be a reference to a Joystick instance? */ return rb_funcall(cJoyDownEvent,new,2,\ INT2NUM(ev.jbutton.which),INT2NUM(ev.jbutton.button)); break; case SDL_JOYBUTTONUP: /* JoyUp.new(joy,button) */ /* Eventually, joy might be a reference to a Joystick instance? */ return rb_funcall(cJoyUpEvent,new,2,\ INT2NUM(ev.jbutton.which),INT2NUM(ev.jbutton.button)); break; case SDL_VIDEORESIZE: /* ResizeEvent.new([w,h]) */ return rb_funcall(cResizeEvent,new,1,\ rb_ary_new3(2,INT2NUM(ev.resize.w),INT2NUM(ev.resize.h))); break; case SDL_VIDEOEXPOSE: /* ExposeEvent.new( ) */ return rb_funcall(cExposeEvent,new,0); break; case SDL_QUIT: /* QuitEvent.new( ) */ return rb_funcall(cQuitEvent,new,0); break; default: rb_warn("Cannot convert unknown event type (%d).", ev.type); return Qnil; break; } return Qnil; /* should never get here */ } /* * call-seq: * get_sdl -> [Event, ...] * * (This private method is intended for internal use, but you might need * to worry about it if you extend Queue.) * * Retrieves all pending events from SDL's event buffer and converts them * into Rubygame Event objects. Returns an Array of all the events, in * the order they were read. */ VALUE rbgm_queue_getsdl(VALUE self) { SDL_Event event; VALUE event_array; event_array = rb_ary_new(); /* put each in *event until no pending events are in SDL's queue */ /* for now, we don't care what type the event in. Filtering comes later */ while(SDL_PollEvent(&event)==1) { rb_ary_push(event_array, rbgm_convert_sdlevent(event) ); } return event_array; } /*-- * The event module documentation is in rubygame/lib/rubygame/event.rb *++ */ void Rubygame_Init_Event() { #if 0 /* Pretend to define Rubygame module, so RDoc knows about it: */ mRubygame = rb_define_module("Rubygame"); #endif /* Define the Queue class and the get_sdl method */ /* The rest of the methods are defined in event.rb */ cQueue = rb_define_class_under(mRubygame,"Queue",rb_cObject); rb_define_private_method(cQueue,"get_sdl",rbgm_queue_getsdl,0); /* Define a plethora of event types! */ cEvent = rb_define_class_under(mRubygame,"Event",rb_cObject); cActiveEvent = rb_define_class_under(mRubygame,"ActiveEvent",cEvent); cKeyDownEvent = rb_define_class_under(mRubygame,"KeyDownEvent",cEvent); cKeyUpEvent = rb_define_class_under(mRubygame,"KeyUpEvent",cEvent); cMouseMotionEvent = rb_define_class_under(mRubygame,"MouseMotionEvent",\ cEvent); cMouseDownEvent = rb_define_class_under(mRubygame,"MouseDownEvent",cEvent); cMouseUpEvent = rb_define_class_under(mRubygame,"MouseUpEvent",cEvent); cJoyAxisEvent = rb_define_class_under(mRubygame,"JoyAxisEvent",cEvent); cJoyBallEvent = rb_define_class_under(mRubygame,"JoyBallEvent",cEvent); cJoyHatEvent = rb_define_class_under(mRubygame,"JoyHatEvent",cEvent); cJoyDownEvent = rb_define_class_under(mRubygame,"JoyDownEvent",cEvent); cJoyUpEvent = rb_define_class_under(mRubygame,"JoyUpEvent",cEvent); cQuitEvent = rb_define_class_under(mRubygame,"QuitEvent",cEvent); cResizeEvent = rb_define_class_under(mRubygame,"ResizeEvent",cEvent); cExposeEvent = rb_define_class_under(mRubygame,"ExposeEvent",cEvent); }