mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-29 19:02:55 +02:00
FEATURE: Allows detecting simulated cursors in JS, this allows JS-developers to track all cursors separately. By using the deviceID. (deviceID 0 = default mouse-cursor , 1500 and 1501 hydra cursors)
This commit is contained in:
parent
7f9e39c7b2
commit
b6cb19c2f6
9 changed files with 118 additions and 32 deletions
79
examples/multipleCursorsExample.js
Normal file
79
examples/multipleCursorsExample.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
//
|
||||||
|
// multipleCursorsExample.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Thijs Wenker on 7/23/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This is an example script that demonstrates use of multiple cursors
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var wantDebugging = false;
|
||||||
|
|
||||||
|
var cursors = {};
|
||||||
|
|
||||||
|
function Cursor(event) {
|
||||||
|
this.deviceID = event.deviceID;
|
||||||
|
|
||||||
|
this.held_buttons = {
|
||||||
|
LEFT: false,
|
||||||
|
MIDDLE: false,
|
||||||
|
RIGHT: false
|
||||||
|
}
|
||||||
|
this.updatePosition = function(event) {
|
||||||
|
this.x = event.x;
|
||||||
|
this.y = event.y;
|
||||||
|
};
|
||||||
|
this.pressEvent = function(event) {
|
||||||
|
if (this.held_buttons[event.button] != undefined) {
|
||||||
|
this.held_buttons[event.button] = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.releaseEvent = function(event) {
|
||||||
|
if (this.held_buttons[event.button] != undefined) {
|
||||||
|
this.held_buttons[event.button] = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.updatePosition(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
if (cursors[event.deviceID] == undefined) {
|
||||||
|
cursors[event.deviceID] = new Cursor(event);
|
||||||
|
}
|
||||||
|
cursors[event.deviceID].pressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseReleaseEvent(event) {
|
||||||
|
if (cursors[event.deviceID] == undefined) {
|
||||||
|
cursors[event.deviceID] = new Cursor(event);
|
||||||
|
}
|
||||||
|
cursors[event.deviceID].releaseEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMoveEvent(event) {
|
||||||
|
if (cursors[event.deviceID] == undefined) {
|
||||||
|
cursors[event.deviceID] = new Cursor(event);
|
||||||
|
} else {
|
||||||
|
cursors[event.deviceID].updatePosition(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastOutputString = "";
|
||||||
|
function checkCursors() {
|
||||||
|
if(lastOutputString != JSON.stringify(cursors)) {
|
||||||
|
lastOutputString = JSON.stringify(cursors);
|
||||||
|
// outputs json string of all cursors only when a change occured
|
||||||
|
print(lastOutputString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.update.connect(checkCursors);
|
||||||
|
|
||||||
|
// Map the mouse events to our functions
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|
@ -155,7 +155,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_mouseX(0),
|
_mouseX(0),
|
||||||
_mouseY(0),
|
_mouseY(0),
|
||||||
_lastMouseMove(usecTimestampNow()),
|
_lastMouseMove(usecTimestampNow()),
|
||||||
_lastMouseMoveType(QEvent::MouseMove),
|
_lastMouseMoveWasSimulated(false),
|
||||||
_mouseHidden(false),
|
_mouseHidden(false),
|
||||||
_seenMouseMove(false),
|
_seenMouseMove(false),
|
||||||
_touchAvgX(0.0f),
|
_touchAvgX(0.0f),
|
||||||
|
@ -1141,18 +1141,19 @@ void Application::focusOutEvent(QFocusEvent* event) {
|
||||||
_keysPressed.clear();
|
_keysPressed.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mouseMoveEvent(QMouseEvent* event) {
|
void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||||
|
|
||||||
bool showMouse = true;
|
bool showMouse = true;
|
||||||
|
|
||||||
|
// Used by application overlay to determine how to draw cursor(s)
|
||||||
|
_lastMouseMoveWasSimulated = deviceID > 0;
|
||||||
|
|
||||||
// If this mouse move event is emitted by a controller, dont show the mouse cursor
|
// If this mouse move event is emitted by a controller, dont show the mouse cursor
|
||||||
if (event->type() == CONTROLLER_MOVE_EVENT) {
|
if (_lastMouseMoveWasSimulated) {
|
||||||
showMouse = false;
|
showMouse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by application overlay to determine how to draw cursor(s)
|
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
||||||
_lastMouseMoveType = event->type();
|
|
||||||
|
|
||||||
_controllerScriptingInterface.emitMouseMoveEvent(event); // send events to any registered scripts
|
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||||
|
@ -1171,7 +1172,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
_mouseY = event->y();
|
_mouseY = event->y();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mousePressEvent(QMouseEvent* event) {
|
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||||
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
|
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
|
@ -1204,7 +1205,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mouseReleaseEvent(QMouseEvent* event) {
|
void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||||
_controllerScriptingInterface.emitMouseReleaseEvent(event); // send events to any registered scripts
|
_controllerScriptingInterface.emitMouseReleaseEvent(event); // send events to any registered scripts
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
|
|
|
@ -159,9 +159,9 @@ public:
|
||||||
void focusOutEvent(QFocusEvent* event);
|
void focusOutEvent(QFocusEvent* event);
|
||||||
void focusInEvent(QFocusEvent* event);
|
void focusInEvent(QFocusEvent* event);
|
||||||
|
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0);
|
||||||
|
|
||||||
void touchBeginEvent(QTouchEvent* event);
|
void touchBeginEvent(QTouchEvent* event);
|
||||||
void touchEndEvent(QTouchEvent* event);
|
void touchEndEvent(QTouchEvent* event);
|
||||||
|
@ -207,7 +207,7 @@ public:
|
||||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||||
int getMouseX() const { return _mouseX; }
|
int getMouseX() const { return _mouseX; }
|
||||||
int getMouseY() const { return _mouseY; }
|
int getMouseY() const { return _mouseY; }
|
||||||
unsigned int getLastMouseMoveType() const { return _lastMouseMoveType; }
|
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated;; }
|
||||||
Faceplus* getFaceplus() { return &_faceplus; }
|
Faceplus* getFaceplus() { return &_faceplus; }
|
||||||
Faceshift* getFaceshift() { return &_faceshift; }
|
Faceshift* getFaceshift() { return &_faceshift; }
|
||||||
Visage* getVisage() { return &_visage; }
|
Visage* getVisage() { return &_visage; }
|
||||||
|
@ -507,7 +507,7 @@ private:
|
||||||
int _mouseDragStartedX;
|
int _mouseDragStartedX;
|
||||||
int _mouseDragStartedY;
|
int _mouseDragStartedY;
|
||||||
quint64 _lastMouseMove;
|
quint64 _lastMouseMove;
|
||||||
unsigned int _lastMouseMoveType;
|
bool _lastMouseMoveWasSimulated;
|
||||||
bool _mouseHidden;
|
bool _mouseHidden;
|
||||||
bool _seenMouseMove;
|
bool _seenMouseMove;
|
||||||
|
|
||||||
|
|
|
@ -373,6 +373,8 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
Qt::MouseButton bumperButton;
|
Qt::MouseButton bumperButton;
|
||||||
Qt::MouseButton triggerButton;
|
Qt::MouseButton triggerButton;
|
||||||
|
|
||||||
|
unsigned int deviceID = index == 0 ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
|
||||||
|
|
||||||
if (Menu::getInstance()->getInvertSixenseButtons()) {
|
if (Menu::getInstance()->getInvertSixenseButtons()) {
|
||||||
bumperButton = Qt::LeftButton;
|
bumperButton = Qt::LeftButton;
|
||||||
triggerButton = Qt::RightButton;
|
triggerButton = Qt::RightButton;
|
||||||
|
@ -405,14 +407,14 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
if (_bumperPressed[index]) {
|
if (_bumperPressed[index]) {
|
||||||
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, bumperButton, bumperButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, bumperButton, bumperButton, 0);
|
||||||
|
|
||||||
application->mouseReleaseEvent(&mouseEvent);
|
application->mouseReleaseEvent(&mouseEvent, deviceID);
|
||||||
|
|
||||||
_bumperPressed[index] = false;
|
_bumperPressed[index] = false;
|
||||||
}
|
}
|
||||||
if (_triggerPressed[index]) {
|
if (_triggerPressed[index]) {
|
||||||
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, triggerButton, triggerButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, triggerButton, triggerButton, 0);
|
||||||
|
|
||||||
application->mouseReleaseEvent(&mouseEvent);
|
application->mouseReleaseEvent(&mouseEvent, deviceID);
|
||||||
|
|
||||||
_triggerPressed[index] = false;
|
_triggerPressed[index] = false;
|
||||||
}
|
}
|
||||||
|
@ -421,17 +423,17 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
|
|
||||||
//If position has changed, emit a mouse move to the application
|
//If position has changed, emit a mouse move to the application
|
||||||
if (pos.x() != _oldX[index] || pos.y() != _oldY[index]) {
|
if (pos.x() != _oldX[index] || pos.y() != _oldY[index]) {
|
||||||
QMouseEvent mouseEvent(static_cast<QEvent::Type>(CONTROLLER_MOVE_EVENT), pos, Qt::NoButton, Qt::NoButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseMove, pos, Qt::NoButton, Qt::NoButton, 0);
|
||||||
|
|
||||||
//Only send the mouse event if the opposite left button isnt held down.
|
//Only send the mouse event if the opposite left button isnt held down.
|
||||||
//This is specifically for edit voxels
|
//This is specifically for edit voxels
|
||||||
if (triggerButton == Qt::LeftButton) {
|
if (triggerButton == Qt::LeftButton) {
|
||||||
if (!_triggerPressed[(int)(!index)]) {
|
if (!_triggerPressed[(int)(!index)]) {
|
||||||
application->mouseMoveEvent(&mouseEvent);
|
application->mouseMoveEvent(&mouseEvent, deviceID);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!_bumperPressed[(int)(!index)]) {
|
if (!_bumperPressed[(int)(!index)]) {
|
||||||
application->mouseMoveEvent(&mouseEvent);
|
application->mouseMoveEvent(&mouseEvent, deviceID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,12 +458,12 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
|
|
||||||
QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0);
|
||||||
|
|
||||||
application->mousePressEvent(&mouseEvent);
|
application->mousePressEvent(&mouseEvent, deviceID);
|
||||||
}
|
}
|
||||||
} else if (_bumperPressed[index]) {
|
} else if (_bumperPressed[index]) {
|
||||||
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, bumperButton, bumperButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, bumperButton, bumperButton, 0);
|
||||||
|
|
||||||
application->mouseReleaseEvent(&mouseEvent);
|
application->mouseReleaseEvent(&mouseEvent, deviceID);
|
||||||
|
|
||||||
_bumperPressed[index] = false;
|
_bumperPressed[index] = false;
|
||||||
}
|
}
|
||||||
|
@ -473,12 +475,12 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
||||||
|
|
||||||
QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, triggerButton, triggerButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, triggerButton, triggerButton, 0);
|
||||||
|
|
||||||
application->mousePressEvent(&mouseEvent);
|
application->mousePressEvent(&mouseEvent, deviceID);
|
||||||
}
|
}
|
||||||
} else if (_triggerPressed[index]) {
|
} else if (_triggerPressed[index]) {
|
||||||
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, triggerButton, triggerButton, 0);
|
QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, triggerButton, triggerButton, 0);
|
||||||
|
|
||||||
application->mouseReleaseEvent(&mouseEvent);
|
application->mouseReleaseEvent(&mouseEvent, deviceID);
|
||||||
|
|
||||||
_triggerPressed[index] = false;
|
_triggerPressed[index] = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,9 @@ const unsigned int BUTTON_3 = 1U << 3;
|
||||||
const unsigned int BUTTON_4 = 1U << 4;
|
const unsigned int BUTTON_4 = 1U << 4;
|
||||||
const unsigned int BUTTON_FWD = 1U << 7;
|
const unsigned int BUTTON_FWD = 1U << 7;
|
||||||
|
|
||||||
// Event type that represents moving the controller
|
// Event type that represents using the controller
|
||||||
const unsigned int CONTROLLER_MOVE_EVENT = 1500U;
|
const unsigned int CONTROLLER_0_EVENT = 1500U;
|
||||||
|
const unsigned int CONTROLLER_1_EVENT = 1501U;
|
||||||
|
|
||||||
const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 37.5f;
|
const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 37.5f;
|
||||||
const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
|
const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
|
||||||
|
|
|
@ -57,9 +57,9 @@ public:
|
||||||
void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
|
void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
|
||||||
void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
|
void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
|
||||||
|
|
||||||
void emitMouseMoveEvent(QMouseEvent* event) { emit mouseMoveEvent(MouseEvent(*event)); }
|
void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
|
||||||
void emitMousePressEvent(QMouseEvent* event) { emit mousePressEvent(MouseEvent(*event)); }
|
void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
|
||||||
void emitMouseReleaseEvent(QMouseEvent* event) { emit mouseReleaseEvent(MouseEvent(*event)); }
|
void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
|
||||||
|
|
||||||
void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
|
void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
|
||||||
void emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
|
void emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
|
||||||
|
|
|
@ -535,7 +535,7 @@ void ApplicationOverlay::renderPointers() {
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
||||||
|
|
||||||
if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) {
|
if (OculusManager::isConnected() && !application->getLastMouseMoveWasSimulated()) {
|
||||||
//If we are in oculus, render reticle later
|
//If we are in oculus, render reticle later
|
||||||
_reticleActive[MOUSE] = true;
|
_reticleActive[MOUSE] = true;
|
||||||
_magActive[MOUSE] = true;
|
_magActive[MOUSE] = true;
|
||||||
|
@ -546,7 +546,7 @@ void ApplicationOverlay::renderPointers() {
|
||||||
_reticleActive[LEFT_CONTROLLER] = false;
|
_reticleActive[LEFT_CONTROLLER] = false;
|
||||||
_reticleActive[RIGHT_CONTROLLER] = false;
|
_reticleActive[RIGHT_CONTROLLER] = false;
|
||||||
|
|
||||||
} else if (application->getLastMouseMoveType() == CONTROLLER_MOVE_EVENT && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
|
} else if (application->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
|
||||||
//only render controller pointer if we aren't already rendering a mouse pointer
|
//only render controller pointer if we aren't already rendering a mouse pointer
|
||||||
_reticleActive[MOUSE] = false;
|
_reticleActive[MOUSE] = false;
|
||||||
_magActive[MOUSE] = false;
|
_magActive[MOUSE] = false;
|
||||||
|
|
|
@ -298,9 +298,10 @@ MouseEvent::MouseEvent() :
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
MouseEvent::MouseEvent(const QMouseEvent& event) :
|
MouseEvent::MouseEvent(const QMouseEvent& event, const unsigned int deviceID) :
|
||||||
x(event.x()),
|
x(event.x()),
|
||||||
y(event.y()),
|
y(event.y()),
|
||||||
|
deviceID(deviceID),
|
||||||
isLeftButton(event.buttons().testFlag(Qt::LeftButton)),
|
isLeftButton(event.buttons().testFlag(Qt::LeftButton)),
|
||||||
isRightButton(event.buttons().testFlag(Qt::RightButton)),
|
isRightButton(event.buttons().testFlag(Qt::RightButton)),
|
||||||
isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)),
|
isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)),
|
||||||
|
@ -334,6 +335,7 @@ QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& ev
|
||||||
obj.setProperty("x", event.x);
|
obj.setProperty("x", event.x);
|
||||||
obj.setProperty("y", event.y);
|
obj.setProperty("y", event.y);
|
||||||
obj.setProperty("button", event.button);
|
obj.setProperty("button", event.button);
|
||||||
|
obj.setProperty("deviceID", event.deviceID);
|
||||||
obj.setProperty("isLeftButton", event.isLeftButton);
|
obj.setProperty("isLeftButton", event.isLeftButton);
|
||||||
obj.setProperty("isRightButton", event.isRightButton);
|
obj.setProperty("isRightButton", event.isRightButton);
|
||||||
obj.setProperty("isMiddleButton", event.isMiddleButton);
|
obj.setProperty("isMiddleButton", event.isMiddleButton);
|
||||||
|
|
|
@ -44,9 +44,10 @@ public:
|
||||||
class MouseEvent {
|
class MouseEvent {
|
||||||
public:
|
public:
|
||||||
MouseEvent();
|
MouseEvent();
|
||||||
MouseEvent(const QMouseEvent& event);
|
MouseEvent(const QMouseEvent& event, const unsigned int deviceID = 0);
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
unsigned int deviceID;
|
||||||
QString button;
|
QString button;
|
||||||
bool isLeftButton;
|
bool isLeftButton;
|
||||||
bool isRightButton;
|
bool isRightButton;
|
||||||
|
|
Loading…
Reference in a new issue