00001 /* 00002 libwt - Vassilis Virvilis Toolkit - a widget library 00003 Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the 00017 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, SA. 00019 */ 00020 00021 #include <SDL/SDL_events.h> 00022 00023 #include <boost/assign/list_of.hpp> // for 'map_list_of()' 00024 00025 #include "sdlinput.h" 00026 #include "sdlevent.h" 00027 #include <wt/event.h> 00028 #include <wt/rootwindow.h> 00029 #include <wt/application.h> 00030 00031 namespace Wt { 00032 00033 ///static members 00034 const FlagMap SDLInput::buttonMap = boost::assign::map_list_of 00035 (SDL_BUTTON_LEFT, LeftButton) 00036 (SDL_BUTTON_MIDDLE, MidButton) 00037 (SDL_BUTTON_RIGHT, RightButton); 00038 00039 const FlagMap SDLInput::wheelMap = boost::assign::map_list_of 00040 (SDL_BUTTON_WHEELUP, 120) 00041 (SDL_BUTTON_WHEELDOWN, -120); 00042 00043 const FlagMap SDLInput::keyMap = boost::assign::map_list_of 00044 (KMOD_LSHIFT, ShiftButton) 00045 (KMOD_RSHIFT, ShiftButton) 00046 (KMOD_LCTRL, ControlButton) 00047 (KMOD_RCTRL, ControlButton) 00048 (KMOD_LALT, AltButton) 00049 (KMOD_RALT, AltButton) 00050 (KMOD_LMETA, MetaButton) 00051 (KMOD_RMETA, MetaButton) 00052 (KMOD_NUM, Keypad) 00053 (KMOD_CAPS, Keypad) 00054 (KMOD_MODE, Keypad); 00055 00056 SDLInput::EventInfo SDLInput::previous_position_; 00057 SDLInput::EventInfo SDLInput::previous_button_; 00058 00059 // ******** EventInfo ******* 00060 00061 SDLInput::EventInfo::EventInfo() : 00062 button(NoButton), 00063 state(0), 00064 wheel_delta(0), 00065 button_event_type(0), 00066 point(-1, -1), 00067 widget(0) {} 00068 00069 SDLInput::EventInfo::EventInfo(const SDL_Event *event) { 00070 00071 int modifiers_state = SDL_GetModState(); 00072 00073 switch(event->type) { 00074 case SDL_MOUSEMOTION: { 00075 const SDL_MouseMotionEvent *mme = reinterpret_cast< 00076 const SDL_MouseMotionEvent *>(event); 00077 button = NoButton; 00078 state = keyMap.state(modifiers_state) | buttonMap.state(mme->state); 00079 wheel_delta = 0; 00080 button_event_type = Event::Nope; 00081 point = Point(mme->x, mme->y); 00082 } 00083 break; 00084 case SDL_MOUSEBUTTONDOWN: 00085 case SDL_MOUSEBUTTONUP: { 00086 const SDL_MouseButtonEvent *mbe = reinterpret_cast< 00087 const SDL_MouseButtonEvent *>(event); 00088 button = buttonMap[mbe->button]; 00089 state = keyMap.state(modifiers_state); 00090 wheel_delta = wheelMap[mbe->button]; 00091 button_event_type = (event->type == SDL_MOUSEBUTTONDOWN) ? 00092 Event::MouseButtonPress : Event::MouseButtonRelease; 00093 point = Point(mbe->x, mbe->y); 00094 if (button_event_type == Event::MouseButtonPress) { 00095 time.start(); 00096 } 00097 } 00098 break; 00099 default: 00100 assert(0); 00101 break; 00102 } 00103 00104 Widget *w = RootWindow::instance()->childAt(point, true); 00105 Widget *mg = SDLInput::instance()->mouseGrabber(); 00106 widget = (!mg || w->isDescendant(mg)) ? w : mg; 00107 } 00108 00109 bool SDLInput::EventInfo::operator==(const EventInfo& other) const { 00110 if (button != other.button) 00111 return false; 00112 if (state != other.state) 00113 return false; 00114 if (wheel_delta != other.wheel_delta) 00115 return false; 00116 if (button_event_type != other.button_event_type) 00117 return false; 00118 if (std::max(abs(point.x() - other.point.x()), 00119 abs(point.y() - other.point.y())) > delta_proximity) 00120 return false; 00121 if (widget != other.widget) 00122 return false; 00123 if (abs(time.msecsTo(other.time)) > delta_delay) { 00124 return false; 00125 } 00126 return true; 00127 } 00128 00129 // ******** SDLInput ******* 00130 00131 SDLInput::SDLInput() 00132 : Singleton<SDLInput>(this), 00133 keyboard_grabber(0), 00134 mouse_grabber(0) { 00135 SDLEvent& sdlevent = *SDLEvent::instance(); 00136 sdlevent[SDLEvent::Active] = &handleActiveEvent; 00137 sdlevent[SDLEvent::KeyDown] = &handleKeyEvent; 00138 sdlevent[SDLEvent::KeyUp] = &handleKeyEvent; 00139 sdlevent[SDLEvent::MouseMotion] = &handleMouseEvent; 00140 sdlevent[SDLEvent::MouseButtonDown] = &handleMouseEvent; 00141 sdlevent[SDLEvent::MouseButtonUp] = &handleMouseEvent; 00142 sdlevent[SDLEvent::Quit] = &handleQuitEvent; 00143 sdlevent[SDLEvent::VideoResize] = &handleVideoResizeEvent; 00144 sdlevent[SDLEvent::SysWM] = &handleUnusualEvent; 00145 sdlevent[SDLEvent::VideoExpose] = &handleUnusualEvent; 00146 } 00147 00148 Widget *SDLInput::keyboardGrabber() const { 00149 return keyboard_grabber; 00150 } 00151 00152 void SDLInput::setKeyboardGrabber(Widget *w) { 00153 keyboard_grabber = w; 00154 } 00155 00156 void SDLInput::releaseKeyboardGrab() { 00157 setKeyboardGrabber(0); 00158 } 00159 00160 Widget *SDLInput::mouseGrabber() const { 00161 return mouse_grabber; 00162 } 00163 00164 void SDLInput::setMouseGrabber(Widget *w) { 00165 mouse_grabber = w; 00166 } 00167 00168 void SDLInput::releaseMouseGrab() { 00169 setMouseGrabber(0); 00170 } 00171 00172 void SDLInput::handleKeyEvent(const SDL_Event *event) { 00173 switch(event->type) { 00174 case SDL_KEYDOWN: 00175 case SDL_KEYUP: { 00176 const SDL_KeyboardEvent *ke = reinterpret_cast< 00177 const SDL_KeyboardEvent *>(event); 00178 int keymap_state = keyMap.state(ke->keysym.mod); 00179 int sym = ke->keysym.sym; 00180 if (ke->keysym.sym == SDLK_TAB) { 00181 sym = (keymap_state & ShiftButton) ? Key_Backtab : Key_Tab; 00182 } 00183 Widget *w = RootWindow::instance()->focusWidget(); 00184 Widget *kg = SDLInput::instance()->keyboardGrabber(); 00185 w = (!kg || w->isDescendant(kg)) ? w : kg; 00186 Application::postEvent(w, new KeyEvent((ke->type == SDL_KEYDOWN) ? 00187 Event::KeyPress : 00188 Event::KeyRelease, 00189 sym, keymap_state)); 00190 } 00191 break; 00192 default: 00193 assert(0); 00194 break; 00195 } 00196 return; 00197 } 00198 00199 /// \todo drag n' drop 00200 void SDLInput::handleMouseEvent(const SDL_Event *event) { 00201 const EventInfo ei(event); 00202 00203 // let's skip this event if we can't find the originating 00204 // widget i.e. window resize 00205 if (!ei.widget) 00206 return; 00207 00208 // position in widget coordinates 00209 const Point& wp = ei.widget->mapFromGlobal(ei.point); 00210 00211 trace("sdlinput", "Position [%d, %d] button %d (%d) state %d wheel %d\n", 00212 ei.point.x(), ei.point.y(), ei.button, 00213 ei.button_event_type, ei.state, ei.wheel_delta); 00214 trace("sdlinput") << "Inside " << ei.widget << std::endl; 00215 trace("sdlinput", "Widget's corrds [%d, %d]\n", wp.x(), wp.y()); 00216 00217 switch(event->type) { 00218 case SDL_MOUSEMOTION: 00219 if ((ei.state & MouseButtonMask) || ei.widget->mouseTracking) { 00220 Application::postEvent(ei.widget, new MouseEvent(Event::MouseMove, 00221 wp, ei.point, ei.button, ei.state)); 00222 } 00223 00224 if (ei.widget != previous_position_.widget) { 00225 if (previous_position_.widget) { 00226 Application::postEvent(previous_position_.widget, 00227 new Event(Event::Leave)); 00228 } 00229 Application::postEvent(ei.widget, 00230 new Event(Event::Enter)); 00231 } 00232 previous_position_ = ei; 00233 break; 00234 case SDL_MOUSEBUTTONDOWN: 00235 if (ei.wheel_delta) { 00236 Application::postEvent(ei.widget, new WheelEvent(wp, 00237 ei.point, ei.wheel_delta, ei.button)); 00238 break; 00239 } 00240 // check for double click 00241 if (ei == previous_button_) { 00242 Application::postEvent(ei.widget, new MouseEvent( 00243 Event::MouseButtonDblClick, wp, 00244 ei.point, ei.button, ei.state)); 00245 break; 00246 } 00247 previous_button_ = ei; 00248 case SDL_MOUSEBUTTONUP: 00249 if (!ei.wheel_delta) { 00250 Application::postEvent(ei.widget, new MouseEvent( 00251 ei.button_event_type, wp, 00252 ei.point, ei.button, ei.state)); 00253 } 00254 break; 00255 default: 00256 assert(0); 00257 break; 00258 } 00259 return; 00260 } 00261 00262 void SDLInput::handleActiveEvent(const SDL_Event *event) { 00263 if (event->active.state & SDL_APPMOUSEFOCUS && 00264 !event->active.gain) { 00265 trace("sdlactive", "Application mouse lost...\n"); 00266 // we are out of SDL window. We have to send Leave event 00267 if (previous_position_.widget) { 00268 Application::postEvent(previous_position_.widget, 00269 new Event(Event::Leave)); 00270 } 00271 previous_position_.widget = 0; 00272 } 00273 if (event->active.state & SDL_APPINPUTFOCUS) { 00274 trace("sdlactive", "Application Focus...\n"); 00275 Application::postEvent(RootWindow::instance()->focusWidget(), 00276 new FocusEvent((event->active.gain) ? 00277 Event::FocusIn : 00278 Event::FocusOut, 00279 FocusEvent::ActiveWindow)); 00280 } 00281 // if deiconify 00282 /// this doesn't look usefull 00283 if (event->active.state & SDL_APPACTIVE && event->active.gain) { 00284 trace("sdlactive", "Deiconify...\n"); 00285 //RootWindow::rootWindow()->update(); 00286 } 00287 } 00288 00289 void SDLInput::handleQuitEvent(const SDL_Event *) { 00290 Application::exit(); 00291 } 00292 00293 void SDLInput::handleVideoResizeEvent(const SDL_Event *event) { 00294 RootWindow::instance()->resize(event->resize.w, event->resize.h); 00295 } 00296 00297 void SDLInput::handleUnusualEvent(const SDL_Event *event) { 00298 Warn("Unusual SDL_Event type: %d\n", event->type); 00299 } 00300 00301 } // namespace
This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.