bool EventDispatcher::DispatchSDLEvent(const SDL_Event &event) { switch (event.type) { case SDL_KEYDOWN: return Dispatch(KeyboardEvent(KeyboardEvent::KEY_DOWN, KeySym(event.key.keysym.sym, SDL_Keymod(event.key.keysym.mod)))); case SDL_KEYUP: return Dispatch(KeyboardEvent(KeyboardEvent::KEY_UP, KeySym(event.key.keysym.sym, SDL_Keymod(event.key.keysym.mod)))); case SDL_TEXTINPUT: Uint32 unicode; Text::utf8_decode_char(&unicode, event.text.text); return Dispatch(TextInputEvent(unicode)); case SDL_MOUSEWHEEL: return Dispatch(MouseWheelEvent(event.wheel.y > 0 ? MouseWheelEvent::WHEEL_UP : MouseWheelEvent::WHEEL_DOWN, m_lastMousePosition)); case SDL_MOUSEBUTTONDOWN: return Dispatch(MouseButtonEvent(MouseButtonEvent::BUTTON_DOWN, MouseButtonFromSDLButton(event.button.button), Point(event.button.x,event.button.y))); case SDL_MOUSEBUTTONUP: return Dispatch(MouseButtonEvent(MouseButtonEvent::BUTTON_UP, MouseButtonFromSDLButton(event.button.button), Point(event.button.x,event.button.y))); case SDL_MOUSEMOTION: return Dispatch(MouseMotionEvent(Point(event.motion.x,event.motion.y), Point(event.motion.xrel, event.motion.yrel))); } return false; }
bool EventDispatcher::DispatchSDLEvent(const SDL_Event &event) { switch (event.type) { case SDL_KEYDOWN: return Dispatch(KeyboardEvent(KeyboardEvent::KEY_DOWN, KeySym(event.key.keysym.sym, SDL_Keymod(event.key.keysym.mod)), event.key.repeat)); case SDL_KEYUP: return Dispatch(KeyboardEvent(KeyboardEvent::KEY_UP, KeySym(event.key.keysym.sym, SDL_Keymod(event.key.keysym.mod)), event.key.repeat)); case SDL_TEXTINPUT: Uint32 unicode; Text::utf8_decode_char(&unicode, event.text.text); return Dispatch(TextInputEvent(unicode)); case SDL_MOUSEWHEEL: return Dispatch(MouseWheelEvent(event.wheel.y > 0 ? MouseWheelEvent::WHEEL_UP : MouseWheelEvent::WHEEL_DOWN, m_lastMousePosition)); case SDL_MOUSEBUTTONDOWN: return Dispatch(MouseButtonEvent(MouseButtonEvent::BUTTON_DOWN, MouseButtonFromSDLButton(event.button.button), Point(event.button.x,event.button.y))); case SDL_MOUSEBUTTONUP: return Dispatch(MouseButtonEvent(MouseButtonEvent::BUTTON_UP, MouseButtonFromSDLButton(event.button.button), Point(event.button.x,event.button.y))); case SDL_MOUSEMOTION: return Dispatch(MouseMotionEvent(Point(event.motion.x,event.motion.y), Point(event.motion.xrel, event.motion.yrel))); case SDL_JOYAXISMOTION: // SDL joystick axis value is documented to have the range -32768 to 32767 // unfortunately this places the centre at -0.5, not at zero, which is clearly nuts... // so since that doesn't make any sense, we assume the range is *actually* -32767 to +32767, // and scale it accordingly, clamping the output so that if we *do* get -32768, it turns into -1 return Dispatch(JoystickAxisMotionEvent(event.jaxis.which, Clamp(event.jaxis.value * (1.0f / 32767.0f), -1.0f, 1.0f), event.jaxis.axis)); case SDL_JOYHATMOTION: return Dispatch(JoystickHatMotionEvent(event.jhat.which, JoystickHatMotionEvent::JoystickHatDirection(event.jhat.value), event.jhat.hat)); case SDL_JOYBUTTONDOWN: return Dispatch(JoystickButtonEvent(event.jbutton.which, JoystickButtonEvent::BUTTON_DOWN, event.jbutton.button)); case SDL_JOYBUTTONUP: return Dispatch(JoystickButtonEvent(event.jbutton.which, JoystickButtonEvent::BUTTON_UP, event.jbutton.button)); } return false; }
/** * Example strings: * Key55 * Joy{uuid}/Button2 * Joy{uuid}/Hat0Dir3 */ bool KeyBinding::FromString(const char *str, KeyBinding &kb) { const char *digits = "1234567890"; const char *p = str; if (strcmp(p, "disabled") == 0) { kb.Clear(); } else if (strncmp(p, "Key", 3) == 0) { kb.type = KEYBOARD_KEY; p += 3; kb.u.keyboard.key = SDL_Keycode(atoi(p)); p += strspn(p, digits); if (strncmp(p, "Mod", 3) == 0) { p += 3; kb.u.keyboard.mod = SDL_Keymod(atoi(p)); } else { kb.u.keyboard.mod = KMOD_NONE; } } else if (strncmp(p, "Joy", 3) == 0) { p += 3; const int JoyUUIDLength = 33; char joyUUIDBuf[JoyUUIDLength]; // read the UUID if (!ReadToTok('/', &p, joyUUIDBuf, JoyUUIDLength)) { return false; } // force terminate joyUUIDBuf[JoyUUIDLength-1] = '\0'; // now, locate the internal ID. int joy = Pi::JoystickFromGUIDString(joyUUIDBuf); if (joy == -1) { return false; } if (strncmp(p, "Button", 6) == 0) { p += 6; kb.type = JOYSTICK_BUTTON; kb.u.joystickButton.joystick = joy; kb.u.joystickButton.button = atoi(p); } else if (strncmp(p, "Hat", 3) == 0) { p += 3; kb.type = JOYSTICK_HAT; kb.u.joystickHat.joystick = joy; kb.u.joystickHat.hat = atoi(p); p += strspn(p, digits); if (strncmp(p, "Dir", 3) != 0) return false; p += 3; kb.u.joystickHat.direction = atoi(p); } else return false; } return true; }
/** * Exampe strings: * Key55 * Joy0Button2 * Joy0Hat0Dir3 */ bool KeyBindingFromString(const std::string &str, KeyBinding *kb) { const char *digits = "1234567890"; const char *p = str.c_str(); if (strncmp(p, "Key", 3) == 0) { kb->type = KEYBOARD_KEY; p += 3; kb->u.keyboard.key = SDL_Keycode(atoi(p)); p += strspn(p, digits); if (strncmp(p, "Mod", 3) == 0) { p += 3; kb->u.keyboard.mod = SDL_Keymod(atoi(p)); } else kb->u.keyboard.mod = KMOD_NONE; return true; } else if (strncmp(p, "Joy", 3) == 0) { p += 3; int joy = atoi(p); p += strspn(p, digits); if (strncmp(p, "Button", 6) == 0) { p += 6; kb->type = JOYSTICK_BUTTON; kb->u.joystickButton.joystick = joy; kb->u.joystickButton.button = atoi(p); return true; } else if (strncmp(p, "Hat", 3) == 0) { p += 3; kb->type = JOYSTICK_HAT; kb->u.joystickHat.joystick = joy; kb->u.joystickHat.hat = atoi(p); p += strspn(p, digits); if (strncmp(p, "Dir", 3) != 0) return false; p += 3; kb->u.joystickHat.direction = atoi(p); return true; } return false; } return false; }
KeySym KeySym::FromString(const std::string &spec) { static const std::string delim("+"); SDL_Keycode sym = SDLK_UNKNOWN; Uint32 mod = KMOD_NONE; size_t start = 0, end = 0; while (end != std::string::npos) { // get to the first non-delim char start = spec.find_first_not_of(delim, end); // read the end, no more to do if (start == std::string::npos) break; // find the end - next delim or end of string end = spec.find_first_of(delim, start); // extract the fragment const std::string token(spec.substr(start, (end == std::string::npos) ? std::string::npos : end - start)); if (token == "ctrl") mod |= KMOD_CTRL; else if (token == "shift") mod |= KMOD_SHIFT; else if (token == "alt") mod |= KMOD_ALT; else if (token == "meta") mod |= KMOD_GUI; else { if (sym != SDLK_UNKNOWN) Output("key spec '%s' has multiple keys, ignoring '%s'\n", spec.c_str(), token.c_str()); else { for (const KeyMap *map = keymap; map->name; map++) if (token == map->name) sym = map->sym; if (sym == SDLK_UNKNOWN) Output("key spec '%s' has unkown token '%s', ignoring it\n", spec.c_str(), token.c_str()); } } } return KeySym(sym, SDL_Keymod(mod)); }
bool EventDispatcher::Dispatch(const Event &event) { switch (event.type) { case Event::KEYBOARD: { const KeyboardEvent keyEvent = static_cast<const KeyboardEvent&>(event); switch (keyEvent.action) { case KeyboardEvent::KEY_DOWN: // all key events to the selected widget first if (m_selected && m_selected->IsOnTopLayer()) return m_selected->TriggerKeyDown(keyEvent); return m_baseContainer->TriggerKeyDown(keyEvent); case KeyboardEvent::KEY_UP: { // all key events to the selected widget first if (m_selected && m_selected->IsOnTopLayer()) return m_selected->TriggerKeyUp(keyEvent); // any modifier coming in will be a specific key, eg left // shift or right shift. shortcuts can't distinguish // betwen the two, and so have both set in m_shortcuts. we // can't just compare though, because the mods won't // match. so we make a new keysym with a new mod that // includes both of the type of key Uint32 mod = Uint32(keyEvent.keysym.mod); if (mod & KMOD_SHIFT) mod |= KMOD_SHIFT; if (mod & KMOD_CTRL) mod |= KMOD_CTRL; if (mod & KMOD_ALT) mod |= KMOD_ALT; if (mod & KMOD_GUI) mod |= KMOD_GUI; const KeySym shortcutSym(keyEvent.keysym.sym, SDL_Keymod(mod)); std::map<KeySym,Widget*>::iterator i = m_shortcuts.find(shortcutSym); if (i != m_shortcuts.end()) { // DispatchSelect must happen before TriggerClick, so // that Click handlers can override the selection DispatchSelect((*i).second); (*i).second->TriggerClick(); return true; } return m_baseContainer->TriggerKeyUp(keyEvent); } } return false; } case Event::TEXT_INPUT: { const TextInputEvent textInputEvent = static_cast<const TextInputEvent&>(event); // selected widgets get all the text input events if (m_selected && m_selected->IsOnTopLayer()) return m_selected->TriggerTextInput(textInputEvent); return m_baseContainer->TriggerTextInput(textInputEvent); } case Event::MOUSE_BUTTON: { const MouseButtonEvent mouseButtonEvent = static_cast<const MouseButtonEvent&>(event); m_lastMousePosition = mouseButtonEvent.pos; RefCountedPtr<Widget> target(m_baseContainer->GetWidgetAt(m_lastMousePosition)); switch (mouseButtonEvent.action) { case MouseButtonEvent::BUTTON_DOWN: { if (!target->IsOnTopLayer()) return false; if (target->IsDisabled()) return false; // activate widget and remember it if (!m_mouseActiveReceiver) { m_mouseActiveReceiver = target; m_mouseActiveTrigger = mouseButtonEvent.button; target->TriggerMouseActivate(); } MouseButtonEvent translatedEvent = MouseButtonEvent(mouseButtonEvent.action, mouseButtonEvent.button, m_lastMousePosition-target->GetAbsolutePosition()); return target->TriggerMouseDown(translatedEvent); } case MouseButtonEvent::BUTTON_UP: { // if there's an active widget, deactivate it if (m_mouseActiveReceiver && m_mouseActiveTrigger == mouseButtonEvent.button) { m_mouseActiveReceiver->TriggerMouseDeactivate(); // if we released over the active widget, then we clicked it if (m_mouseActiveReceiver.Get() == target) { // DispatchSelect must happen before TriggerClick, so // that Click handlers can override the selection DispatchSelect(m_mouseActiveReceiver.Get()); m_mouseActiveReceiver->TriggerClick(); } m_mouseActiveReceiver.Reset(); // send the straight up event too bool ret = false; if (!target->IsDisabled()) { MouseButtonEvent translatedEvent = MouseButtonEvent(mouseButtonEvent.action, mouseButtonEvent.button, m_lastMousePosition-target->GetAbsolutePosition()); ret = target->TriggerMouseUp(translatedEvent); } DispatchMouseOverOut(target.Get(), m_lastMousePosition); return ret; } if (!target->IsOnTopLayer()) return false; MouseButtonEvent translatedEvent = MouseButtonEvent(mouseButtonEvent.action, mouseButtonEvent.button, m_lastMousePosition-target->GetAbsolutePosition()); return target->TriggerMouseUp(translatedEvent); } default: return false; } } case Event::MOUSE_MOTION: { const MouseMotionEvent mouseMotionEvent = static_cast<const MouseMotionEvent&>(event); m_lastMousePosition = mouseMotionEvent.pos; // if there's a mouse-active widget, just send motion events directly into it if (m_mouseActiveReceiver) { if (!m_mouseActiveReceiver->IsOnTopLayer()) return false; MouseMotionEvent translatedEvent = MouseMotionEvent(m_lastMousePosition-m_mouseActiveReceiver->GetAbsolutePosition(), mouseMotionEvent.rel); return m_mouseActiveReceiver->TriggerMouseMove(translatedEvent); } // widget directly under the mouse RefCountedPtr<Widget> target(m_baseContainer->GetWidgetAt(m_lastMousePosition)); bool ret = false; if (!target->IsDisabled() && target->IsOnTopLayer()) { MouseMotionEvent translatedEvent = MouseMotionEvent(m_lastMousePosition-target->GetAbsolutePosition(), mouseMotionEvent.rel); ret = target->TriggerMouseMove(translatedEvent); } DispatchMouseOverOut(target.Get(), m_lastMousePosition); return ret; } case Event::MOUSE_WHEEL: { const MouseWheelEvent mouseWheelEvent = static_cast<const MouseWheelEvent&>(event); m_lastMousePosition = mouseWheelEvent.pos; RefCountedPtr<Widget> target(m_baseContainer->GetWidgetAt(m_lastMousePosition)); if (!target->IsOnTopLayer()) return false; return target->TriggerMouseWheel(mouseWheelEvent); } case Event::JOYSTICK_AXIS_MOTION: return m_baseContainer->TriggerJoystickAxisMove(static_cast<const JoystickAxisMotionEvent&>(event)); case Event::JOYSTICK_HAT_MOTION: return m_baseContainer->TriggerJoystickHatMove(static_cast<const JoystickHatMotionEvent&>(event)); case Event::JOYSTICK_BUTTON: { const JoystickButtonEvent &joyButtonEvent = static_cast<const JoystickButtonEvent&>(event); switch (joyButtonEvent.action) { case JoystickButtonEvent::BUTTON_DOWN: return m_baseContainer->TriggerJoystickButtonDown(joyButtonEvent); case JoystickButtonEvent::BUTTON_UP: return m_baseContainer->TriggerJoystickButtonUp(joyButtonEvent); default: assert(0); return false; } } default: return false; } return false; }