305 lines · 12.1 KB · C++
RawDownload
////  PointerEvent.cpp//  script-engine/src////  Created by Anthony Thibault on 2016-8-11.//  Copyright 2016 High Fidelity, Inc.//  Copyright 2023 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//  SPDX-License-Identifier: Apache-2.0// #include "PointerEvent.h" #include "RegisteredMetaTypes.h"#include "ScriptEngine.h"#include "ScriptValue.h"#include "ScriptValueUtils.h" static bool areFlagsSet(uint32_t flags, uint32_t mask) {    return (flags & mask) != 0;} PointerEvent::PointerEvent(EventType type, uint32_t id) :    _type(type),    _id(id){} PointerEvent::PointerEvent(EventType type, uint32_t id, const glm::vec2& pos2D, Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers) :    _type(type),    _id(id),    _pos2D(pos2D),    _button(button),    _buttons(buttons),    _keyboardModifiers(keyboardModifiers){} PointerEvent::PointerEvent(const glm::vec2& pos2D, const glm::vec3& pos3D, const glm::vec3& normal, const glm::vec3& direction) :    _pos2D(pos2D),    _pos3D(pos3D),    _normal(normal),    _direction(direction){} PointerEvent::PointerEvent(EventType type, uint32_t id,                           const glm::vec2& pos2D, const glm::vec3& pos3D,                           const glm::vec3& normal, const glm::vec3& direction,                           Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers) :    _type(type),    _id(id),    _pos2D(pos2D),    _pos3D(pos3D),    _normal(normal),    _direction(direction),    _button(button),    _buttons(buttons),    _keyboardModifiers(keyboardModifiers){} void PointerEvent::setButton(Button button) {    _button = button;    _buttons |= button;} /*@jsdoc * A 2D or 3D mouse or similar pointer event. * @typedef {object} PointerEvent * @property {string} type - The type of event: <code>"Press"</code>, <code>"DoublePress"</code>, <code>"Release"</code>, *     <code>"Move"</code>, or <code>"Scroll"</code>. * @property {number} id - Integer number used to identify the pointer: <code>0</code> = hardware mouse, <code>1</code> = left *     controller, <code>2</code> = right controller. * @property {Vec2} pos2D - The 2D position of the event on the intersected object XY plane, where applicable. * @property {Vec3} pos3D - The 3D position of the event on the intersected object, where applicable. * @property {Vec3} normal - The surface normal at the intersection point. * @property {Vec3} direction - The direction of the intersection ray. * @property {string} button - The name of the button pressed: <code>None</code>, <code>Primary</code>, <code>Secondary</code>, *    or <code>Tertiary</code>. * @property {boolean} isPrimaryButton - <code>true</code> if the button pressed was the primary button, otherwise  *     <code>undefined</code>; * @property {boolean} isLeftButton - <code>true</code> if the button pressed was the primary button, otherwise *     <code>undefined</code>; * @property {boolean} isSecondaryButton - <code>true</code> if the button pressed was the secondary button, otherwise *     <code>undefined</code>; * @property {boolean} isRightButton - <code>true</code> if the button pressed was the secondary button, otherwise *     <code>undefined</code>; * @property {boolean} isTertiaryButton - <code>true</code> if the button pressed was the tertiary button, otherwise *     <code>undefined</code>; * @property {boolean} isMiddleButton - <code>true</code> if the button pressed was the tertiary button, otherwise *     <code>undefined</code>; * @property {boolean} isPrimaryHeld - <code>true</code> if the primary button is currently being pressed, otherwise *     <code>false</code> * @property {boolean} isSecondaryHeld - <code>true</code> if the secondary button is currently being pressed, otherwise *     <code>false</code> * @property {boolean} isTertiaryHeld - <code>true</code> if the tertiary button is currently being pressed, otherwise *     <code>false</code> * @property {KeyboardModifiers} keyboardModifiers - Integer value with bits set according to which keyboard modifier keys were *     pressed when the event was generated. *//*@jsdoc * <p>A KeyboardModifiers value is used to specify which modifier keys on the keyboard are pressed. The value is the sum  * (bitwise OR) of the relevant combination of values from the following table:</p> * <table> *   <thead> *     <tr><th>Key</th><th>Hexadecimal value</th><th>Decimal value</th><th>Description</th></tr> *   </thead> *   <tbody> *     <tr><td>Shift</td><td><code>0x02000000</code></td><td><code>33554432</code></td> *         <td>A Shift key on the keyboard is pressed.</td></tr> *     <tr><td>Control</td><td><code>0x04000000</code></td><td><code>67108864</code></td> *         <td>A control key on the keyboard is pressed. On Windows the "control" key is the Ctrl key; on OSX it is the Command  *         key.</td></tr> *     <tr><td>Alt</td><td><code>0x08000000</code></td><td><code>134217728</code></td> *         <td>An Alt key on the keyboard is pressed.</td></tr> *     <tr><td>Meta</td><td><code>0x10000000</code></td><td><code>268435456</code></td> *         <td>A meta key on the keyboard is pressed. On Windows the "meta" key is the Windows key; on OSX it is the Control  *         (Splat) key.</td></tr> *     <tr><td>Keypad</td><td><code>0x20000000</code></td><td><code>536870912</code></td> *         <td>A keypad button is pressed.</td></tr> *     <tr><td>Group</td><td><code>0x40000000</code></td><td><code>1073741824</code></td> *         <td>X11 operating system only: An AltGr / Mode_switch key on the keyboard is pressed.</td></tr> *   </tbody> * </table> * @typedef {number} KeyboardModifiers */ScriptValue PointerEvent::toScriptValue(ScriptEngine* engine, const PointerEvent& event) {    ScriptValue obj = engine->newObject();     switch (event._type) {    case Press:        obj.setProperty("type", "Press");        break;    case DoublePress:        obj.setProperty("type", "DoublePress");        break;    case Release:        obj.setProperty("type", "Release");        break;    case Scroll: {        obj.setProperty("type", "Scroll");        ScriptValue scrollObj = engine->newObject();        scrollObj.setProperty("x", event._scroll.x);        scrollObj.setProperty("y", event._scroll.y);        obj.setProperty("scroll", scrollObj);        break;    }    default:    case Move:        obj.setProperty("type", "Move");        break;    };     obj.setProperty("id", event._id);     ScriptValue pos2D = engine->newObject();    pos2D.setProperty("x", event._pos2D.x);    pos2D.setProperty("y", event._pos2D.y);    obj.setProperty("pos2D", pos2D);     ScriptValue pos3D = engine->newObject();    pos3D.setProperty("x", event._pos3D.x);    pos3D.setProperty("y", event._pos3D.y);    pos3D.setProperty("z", event._pos3D.z);    obj.setProperty("pos3D", pos3D);     ScriptValue normal = engine->newObject();    normal.setProperty("x", event._normal.x);    normal.setProperty("y", event._normal.y);    normal.setProperty("z", event._normal.z);    obj.setProperty("normal", normal);     ScriptValue direction = engine->newObject();    direction.setProperty("x", event._direction.x);    direction.setProperty("y", event._direction.y);    direction.setProperty("z", event._direction.z);    obj.setProperty("direction", direction);     bool isPrimaryButton = false;    bool isSecondaryButton = false;    bool isTertiaryButton = false;    switch (event._button) {    case NoButtons:        obj.setProperty("button", "None");        break;    case PrimaryButton:        obj.setProperty("button", "Primary");        isPrimaryButton = true;        break;    case SecondaryButton:        obj.setProperty("button", "Secondary");        isSecondaryButton = true;        break;    case TertiaryButton:        obj.setProperty("button", "Tertiary");        isTertiaryButton = true;        break;    }     if (isPrimaryButton) {        obj.setProperty("isPrimaryButton", isPrimaryButton);        obj.setProperty("isLeftButton", isPrimaryButton);    }    if (isSecondaryButton) {        obj.setProperty("isSecondaryButton", isSecondaryButton);        obj.setProperty("isRightButton", isSecondaryButton);    }    if (isTertiaryButton) {        obj.setProperty("isTertiaryButton", isTertiaryButton);        obj.setProperty("isMiddleButton", isTertiaryButton);    }     obj.setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton));    obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton));    obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton));     obj.setProperty("keyboardModifiers", engine->newValue(event.getKeyboardModifiers()));     return obj;} bool PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& event) {    if (object.isObject()) {        ScriptValue type = object.property("type");        QString typeStr = type.isString() ? type.toString() : "Move";        if (typeStr == "Press") {            event._type = Press;        } else if (typeStr == "DoublePress") {            event._type = DoublePress;        } else if (typeStr == "Release") {            event._type = Release;        } else if (typeStr == "Scroll") {            event._type = Scroll;             ScriptValue scroll = object.property("scroll");            event._scroll = glm::vec2(scroll.property("x").toNumber(), scroll.property("y").toNumber());        } else {            event._type = Move;        }         ScriptValue id = object.property("id");        event._id = id.isNumber() ? (uint32_t)id.toNumber() : 0;         vec2FromScriptValue(object.property("pos2D"), event._pos2D);        vec3FromScriptValue(object.property("pos3D"), event._pos3D);        vec3FromScriptValue(object.property("normal"), event._normal);        vec3FromScriptValue(object.property("direction"), event._direction);         ScriptValue button = object.property("button");        QString buttonStr = type.isString() ? button.toString() : "NoButtons";         if (buttonStr == "Primary") {            event._button = PrimaryButton;        } else if (buttonStr == "Secondary") {            event._button = SecondaryButton;        } else if (buttonStr == "Tertiary") {            event._button = TertiaryButton;        } else {            event._button = NoButtons;        }         bool primary = object.property("isPrimaryHeld").toBool();        bool secondary = object.property("isSecondaryHeld").toBool();        bool tertiary = object.property("isTertiaryHeld").toBool();        event._buttons = 0;        if (primary) {            event._buttons |= PrimaryButton;        }        if (secondary) {            event._buttons |= SecondaryButton;        }        if (tertiary) {            event._buttons |= TertiaryButton;        }         event._keyboardModifiers = (Qt::KeyboardModifiers)(object.property("keyboardModifiers").toUInt32());    }    return true;} static const char* typeToStringMap[PointerEvent::NumEventTypes] = { "Press", "DoublePress", "Release", "Move", "Scroll" };static const char* buttonsToStringMap[8] = {    "NoButtons",    "PrimaryButton",    "SecondaryButton",    "PrimaryButton | SecondaryButton",    "TertiaryButton",    "PrimaryButton | TertiaryButton",    "SecondaryButton | TertiaryButton",    "PrimaryButton | SecondaryButton | TertiaryButton",}; QDebug& operator<<(QDebug& dbg, const PointerEvent& p) {    dbg.nospace() << "PointerEvent, type = " << typeToStringMap[p.getType()] << ", id = " << p.getID();    dbg.nospace() << ", pos2D = (" << p.getPos2D().x << ", " << p.getPos2D().y;    dbg.nospace() << "), pos3D = (" << p.getPos3D().x << ", " << p.getPos3D().y << ", " << p.getPos3D().z;    dbg.nospace() << "), normal = (" << p.getNormal().x << ", " << p.getNormal().y << ", " << p.getNormal().z;    dbg.nospace() << "), dir = (" << p.getDirection().x << ", " << p.getDirection().y << ", " << p.getDirection().z;    dbg.nospace() << "), button = " << buttonsToStringMap[p.getButton()] << " " << (int)p.getButton();    dbg.nospace() << ", buttons = " << buttonsToStringMap[p.getButtons()];    return dbg;}