/* * Copyright 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // This file contains the declaration of Event. #ifndef O3D_CORE_CROSS_EVENT_H_ #define O3D_CORE_CROSS_EVENT_H_ #include #include "core/cross/types.h" namespace o3d { // This Event class is used to pass information to JavaScript event handlers. // It's the single argument passed to JavaScript for any event that we catch // and forward through. // See http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html // for what we're trying to emulate. However, some of the fields are hard to // produce, so we skip them for now or make up the different in JavaScript. class Event { public: // TODO: Figure out what events to add here; stuff like onmouseout is // probably handled by the browser. For a decent list of HTML5 events, see: // http://www.w3schools.com/tags/html5_ref_eventattributes.asp enum Type { // When you add to this, don't forget to add to StringFromType! TYPE_INVALID, TYPE_CLICK, TYPE_DBLCLICK, TYPE_MOUSEDOWN, TYPE_MOUSEMOVE, TYPE_MOUSEUP, TYPE_WHEEL, TYPE_KEYDOWN, TYPE_KEYPRESS, TYPE_KEYUP, TYPE_RESIZE, // This we also trigger on the fullscreen transition. TYPE_CONTEXTMENU, NUM_TYPES }; enum Button { BUTTON_LEFT = 0, BUTTON_MIDDLE = 1, BUTTON_RIGHT = 2, BUTTON_4 = 3, BUTTON_5 = 4, NUM_BUTTONS, }; enum Modifier { MODIFIER_ALT = 1, MODIFIER_CTRL = 2, MODIFIER_SHIFT = 4, MODIFIER_META = 8, // Command on OSX MODIFIER_MAX = MODIFIER_META, // Must update this if you add a modifier. MODIFIER_MASK = (MODIFIER_MAX << 1) - 1 }; static const char *StringFromType(Type type) { switch (type) { case TYPE_CLICK: return "click"; case TYPE_DBLCLICK: return "dblclick"; case TYPE_KEYDOWN: return "keydown"; case TYPE_KEYPRESS: return "keypress"; case TYPE_KEYUP: return "keyup"; case TYPE_MOUSEDOWN: return "mousedown"; case TYPE_MOUSEMOVE: return "mousemove"; case TYPE_MOUSEUP: return "mouseup"; case TYPE_WHEEL: return "wheel"; case TYPE_RESIZE: return "resize"; case TYPE_CONTEXTMENU: return "contextmenu"; case TYPE_INVALID: default: DCHECK(false); return "invalid"; } } static Type TypeFromString(const char *type_string) { for (int i = TYPE_INVALID + 1; i < NUM_TYPES; ++i) { if (!strcmp(type_string, StringFromType(static_cast(i)))) { return static_cast(i); } } return TYPE_INVALID; } static bool ValidType(Type type) { return TYPE_INVALID < type && type < NUM_TYPES; } Event() : type_(TYPE_INVALID), button_valid_(false), modifier_state_valid_(false), key_code_valid_(false), char_code_valid_(false), position_valid_(false), delta_valid_(false), size_valid_(false), valid_(false) { } explicit Event(Type type) : type_(type), button_valid_(false), modifier_state_valid_(false), key_code_valid_(false), char_code_valid_(false), position_valid_(false), delta_valid_(false), size_valid_(false), valid_(true) { } Event(const Event& event) { if (event.valid()) { Copy(event); } else { valid_ = false; } } Event& operator=(const Event& event) { if (event.valid()) { Copy(event); } else { valid_ = false; } return *this; } bool operator==(const Event& e) const; bool operator!=(const Event& e) const { return !(*this == e); } Type type() const { DCHECK(valid_); return type_; } // This is generally used only for overriding a type on a copied event [to // create a click from a mouseup, for example]. void set_type(Type type) { DCHECK(valid_); type_ = type; } const char *type_string() const { return StringFromType(type()); } // Button is valid on mousedown, mouseup, click, and dblclick. // It indicates which button actually caused the event. int button() const { DCHECK(valid_); return button_valid_ ? button_ : 0; } void set_button(int button) { DCHECK(valid_); DCHECK(button >= 0 && button < NUM_BUTTONS); button_valid_ = true; button_ = button; } bool button_valid() const { return button_valid_; } void clear_button() { button_valid_ = false; } int modifier_state() const { DCHECK(valid_); return modifier_state_valid_ ? modifier_state_ : 0; } void set_modifier_state(int state) { DCHECK(valid_); DCHECK(!(state & ~MODIFIER_MASK)); modifier_state_valid_ = true; modifier_state_ = state; } bool modifier_state_valid() const { return modifier_state_valid_; } void clear_modifier_state() { modifier_state_valid_ = false; } bool ctrl_key() const { DCHECK(valid_); return modifier_state_valid_ ? (modifier_state_ & MODIFIER_CTRL) != 0 : false; } bool alt_key() const { DCHECK(valid_); return modifier_state_valid_ ? (modifier_state_ & MODIFIER_ALT) != 0 : false; } bool shift_key() const { DCHECK(valid_); return modifier_state_valid_ ? (modifier_state_ & MODIFIER_SHIFT) != 0 : false; } bool meta_key() const { DCHECK(valid_); return modifier_state_valid_ ? (modifier_state_ & MODIFIER_META) != 0 : false; } // Key code is valid on keydown and keyup events only. int key_code() const { DCHECK(valid_); return key_code_valid_ ? key_code_ : 0; } void set_key_code(int key_code) { DCHECK(valid_); key_code_valid_ = true; key_code_ = key_code; } bool key_code_valid() const { return key_code_valid_; } void clear_key_code() { key_code_valid_ = false; } // Key char is valid on keypress events only. void set_char_code(int char_code) { DCHECK(valid_); char_code_valid_ = true; char_code_ = char_code; } int char_code() const { DCHECK(valid_); return char_code_valid_ ? char_code_ : 0; } bool char_code_valid() const { return char_code_valid_; } void clear_char_code() { char_code_valid_ = false; } // Position is valid on mouse events only. int x() const { DCHECK(valid_); return position_valid_ ? x_ : 0; } int y() const { DCHECK(valid_); return position_valid_ ? y_ : 0; } int screen_x() const { DCHECK(valid_); return position_valid_ ? screen_x_ : 0; } int screen_y() const { DCHECK(valid_); return position_valid_ ? screen_y_ : 0; } // This tells whether or not the position was within the plugin region at the // time of the event. This is used to determine when to synthesize a click // event, which only happens when both a mousedown and its corresponding // mouseup both occur within the plugin region [regardless of the location // intervening mousemove events]. Technically we only absolutely need this // for mousedown and mouseup, but the interface is simpler to require it on // all positioned events, and it might be useful. bool in_plugin() const { DCHECK(valid_); return position_valid_ ? in_plugin_ : false; } void set_position(int x, int y, int screen_x, int screen_y, bool inPlugin) { DCHECK(valid_); position_valid_ = true; x_ = x; y_ = y; screen_x_ = screen_x; screen_y_ = screen_y; in_plugin_ = inPlugin; } bool position_valid() const { return position_valid_; } void clear_position() { position_valid_ = false; } // These are used for mouse scroll events only. Currently one of the two will // always be zero, as some platforms can only detect one axis at a time. // We'll want to add a z axis at some point. int delta_x() const { DCHECK(valid_); return delta_valid_ ? delta_x_ : 0; } int delta_y() const { DCHECK(valid_); return delta_valid_ ? delta_y_ : 0; } void set_delta(int delta_x, int delta_y) { DCHECK(valid_); DCHECK(!delta_x || !delta_y); delta_valid_ = true; delta_x_ = delta_x; delta_y_ = delta_y; } bool delta_valid() const { return delta_valid_; } void clear_delta() { delta_valid_ = false; } // Width, height, and fullscreen are valid on resize events only. int width() const { DCHECK(valid_); return size_valid_ ? width_ : 0; } int height() const { DCHECK(valid_); return size_valid_ ? height_ : 0; } bool fullscreen() const { DCHECK(valid_); return size_valid_ ? fullscreen_ : false; } void set_size(int width, int height, bool fullscreen) { DCHECK(valid_); size_valid_ = true; width_ = width; height_ = height; fullscreen_ = fullscreen; } bool size_valid() const { return size_valid_; } void clear_size() { size_valid_ = false; } bool valid() const { return valid_; } protected: void Copy(const Event& event) { valid_ = true; type_ = event.type(); if (event.button_valid()) { set_button(event.button()); } else { button_valid_ = false; } if (event.modifier_state_valid()) { set_modifier_state(event.modifier_state()); } else { modifier_state_valid_ = false; } if (event.key_code_valid()) { set_key_code(event.key_code()); } else { key_code_valid_ = false; } if (event.char_code_valid()) { set_char_code(event.char_code()); } else { char_code_valid_ = false; } if (event.position_valid()) { set_position(event.x(), event.y(), event.screen_x(), event.screen_y(), event.in_plugin()); } else { position_valid_ = false; } if (event.delta_valid()) { set_delta(event.delta_x(), event.delta_y()); } else { delta_valid_ = false; } if (event.size_valid()) { set_size(event.width(), event.height(), event.fullscreen()); } else { size_valid_ = false; } } private: Type type_; int button_; bool button_valid_; int modifier_state_; bool modifier_state_valid_; int key_code_; bool key_code_valid_; int char_code_; bool char_code_valid_; int x_, y_; int screen_x_, screen_y_; bool in_plugin_; bool position_valid_; int delta_x_, delta_y_; bool delta_valid_; int width_, height_; bool fullscreen_; bool size_valid_; bool valid_; }; typedef std::deque EventQueue; } // namespace o3d #endif // O3D_CORE_CROSS_EVENT_H_