sdlinput.cpp

Go to the documentation of this file.
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

Generated Fri Jul 28 19:23:00 2006.
Copyright © 1998-2003 by the respective authors.

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.