| @@ -58,7 +58,7 @@ public: | |||
| trails.add (t); | |||
| } | |||
| t->pushPoint (e.position, e.mods); | |||
| t->pushPoint (e.position, e.mods, e.pressure); | |||
| repaint(); | |||
| } | |||
| @@ -74,22 +74,26 @@ public: | |||
| : source (ms), colour (getRandomBrightColour().withAlpha (0.6f)) | |||
| {} | |||
| void pushPoint (Point<float> p, ModifierKeys newMods) | |||
| void pushPoint (Point<float> newPoint, ModifierKeys newMods, float pressure) | |||
| { | |||
| currentPosition = p; | |||
| currentPosition = newPoint; | |||
| modifierKeys = newMods; | |||
| if (lastPoint.getDistanceFrom(p) > 5.0f) | |||
| if (lastPoint.getDistanceFrom (newPoint) > 5.0f) | |||
| { | |||
| if (lastPoint != Point<float>()) | |||
| { | |||
| path.quadraticTo (lastPoint, p); | |||
| lastPoint = Point<float>(); | |||
| } | |||
| else | |||
| { | |||
| lastPoint = p; | |||
| Path newSegment; | |||
| newSegment.startNewSubPath (lastPoint); | |||
| newSegment.lineTo (newPoint); | |||
| float diameter = 20.0f * (pressure > 0 && pressure < 1.0f ? pressure : 1.0f); | |||
| PathStrokeType (diameter, PathStrokeType::curved, PathStrokeType::rounded).createStrokedPath (newSegment, newSegment); | |||
| path.addPath (newSegment); | |||
| } | |||
| lastPoint = newPoint; | |||
| } | |||
| } | |||
| @@ -107,7 +111,7 @@ public: | |||
| void drawTrail (Trail& trail, Graphics& g) | |||
| { | |||
| g.setColour (trail.colour); | |||
| g.strokePath (trail.path, PathStrokeType (20.0f, PathStrokeType::curved, PathStrokeType::rounded)); | |||
| g.fillPath (trail.path); | |||
| const float radius = 40.0f; | |||
| @@ -121,6 +125,11 @@ public: | |||
| String desc ("Mouse #"); | |||
| desc << trail.source.getIndex(); | |||
| float pressure = trail.source.getCurrentPressure(); | |||
| if (pressure > 0.0f && pressure < 1.0f) | |||
| desc << " (pressure: " << (int) (pressure * 100.0f) << "%)"; | |||
| if (trail.modifierKeys.isCommandDown()) desc << " (CMD)"; | |||
| if (trail.modifierKeys.isShiftDown()) desc << " (SHIFT)"; | |||
| if (trail.modifierKeys.isCtrlDown()) desc << " (CTRL)"; | |||
| @@ -51,7 +51,8 @@ public: | |||
| if (Component* const comp = Desktop::getInstance().findComponentAt (screenPos.roundToInt())) | |||
| if (ComponentPeer* const peer = comp->getPeer()) | |||
| if (! peer->isFocused()) | |||
| peer->handleMouseEvent (0, peer->globalToLocal (screenPos), mods, Time::currentTimeMillis()); | |||
| peer->handleMouseEvent (0, peer->globalToLocal (screenPos), mods, | |||
| MouseInputSource::invalidPressure, Time::currentTimeMillis()); | |||
| } | |||
| } | |||
| @@ -2384,7 +2384,7 @@ void Component::internalMouseEnter (MouseInputSource source, Point<float> relati | |||
| BailOutChecker checker (this); | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, | |||
| this, this, time, relativePos, time, 0, false); | |||
| mouseEnter (me); | |||
| @@ -2403,7 +2403,7 @@ void Component::internalMouseExit (MouseInputSource source, Point<float> relativ | |||
| BailOutChecker checker (this); | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, | |||
| this, this, time, relativePos, time, 0, false); | |||
| mouseExit (me); | |||
| @@ -2416,7 +2416,7 @@ void Component::internalMouseExit (MouseInputSource source, Point<float> relativ | |||
| MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseExit, me); | |||
| } | |||
| void Component::internalMouseDown (MouseInputSource source, Point<float> relativePos, Time time) | |||
| void Component::internalMouseDown (MouseInputSource source, Point<float> relativePos, Time time, float pressure) | |||
| { | |||
| Desktop& desktop = Desktop::getInstance(); | |||
| BailOutChecker checker (this); | |||
| @@ -2435,7 +2435,7 @@ void Component::internalMouseDown (MouseInputSource source, Point<float> relativ | |||
| { | |||
| // allow blocked mouse-events to go to global listeners.. | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| this, this, time, relativePos, time, | |||
| pressure, this, this, time, relativePos, time, | |||
| source.getNumberOfMultipleClicks(), false); | |||
| desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseDown, me); | |||
| @@ -2468,7 +2468,7 @@ void Component::internalMouseDown (MouseInputSource source, Point<float> relativ | |||
| repaint(); | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| this, this, time, relativePos, time, | |||
| pressure, this, this, time, relativePos, time, | |||
| source.getNumberOfMultipleClicks(), false); | |||
| mouseDown (me); | |||
| @@ -2492,7 +2492,7 @@ void Component::internalMouseUp (MouseInputSource source, Point<float> relativeP | |||
| repaint(); | |||
| const MouseEvent me (source, relativePos, | |||
| oldModifiers, this, this, time, | |||
| oldModifiers, MouseInputSource::invalidPressure, this, this, time, | |||
| getLocalPoint (nullptr, source.getLastMouseDownPosition()), | |||
| source.getLastMouseDownTime(), | |||
| source.getNumberOfMultipleClicks(), | |||
| @@ -2523,14 +2523,14 @@ void Component::internalMouseUp (MouseInputSource source, Point<float> relativeP | |||
| } | |||
| } | |||
| void Component::internalMouseDrag (MouseInputSource source, Point<float> relativePos, Time time) | |||
| void Component::internalMouseDrag (MouseInputSource source, Point<float> relativePos, Time time, float pressure) | |||
| { | |||
| if (! isCurrentlyBlockedByAnotherModalComponent()) | |||
| { | |||
| BailOutChecker checker (this); | |||
| const MouseEvent me (source, relativePos, | |||
| source.getCurrentModifiers(), this, this, time, | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| pressure, this, this, time, | |||
| getLocalPoint (nullptr, source.getLastMouseDownPosition()), | |||
| source.getLastMouseDownTime(), | |||
| source.getNumberOfMultipleClicks(), | |||
| @@ -2559,7 +2559,7 @@ void Component::internalMouseMove (MouseInputSource source, Point<float> relativ | |||
| { | |||
| BailOutChecker checker (this); | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, | |||
| this, this, time, relativePos, time, 0, false); | |||
| mouseMove (me); | |||
| @@ -2578,7 +2578,7 @@ void Component::internalMouseWheel (MouseInputSource source, Point<float> relati | |||
| Desktop& desktop = Desktop::getInstance(); | |||
| BailOutChecker checker (this); | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, | |||
| this, this, time, relativePos, time, 0, false); | |||
| if (isCurrentlyBlockedByAnotherModalComponent()) | |||
| @@ -2605,7 +2605,7 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point<float> re | |||
| { | |||
| if (! isCurrentlyBlockedByAnotherModalComponent()) | |||
| { | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, | |||
| this, this, time, relativePos, time, 0, false); | |||
| mouseMagnify (me, amount); | |||
| @@ -2300,9 +2300,9 @@ private: | |||
| //============================================================================== | |||
| void internalMouseEnter (MouseInputSource, Point<float>, Time); | |||
| void internalMouseExit (MouseInputSource, Point<float>, Time); | |||
| void internalMouseDown (MouseInputSource, Point<float>, Time); | |||
| void internalMouseDown (MouseInputSource, Point<float>, Time, float); | |||
| void internalMouseUp (MouseInputSource, Point<float>, Time, const ModifierKeys oldModifiers); | |||
| void internalMouseDrag (MouseInputSource, Point<float>, Time); | |||
| void internalMouseDrag (MouseInputSource, Point<float>, Time, float); | |||
| void internalMouseMove (MouseInputSource, Point<float>, Time); | |||
| void internalMouseWheel (MouseInputSource, Point<float>, Time, const MouseWheelDetails&); | |||
| void internalMagnifyGesture (MouseInputSource, Point<float>, Time, float); | |||
| @@ -246,7 +246,7 @@ void Desktop::sendMouseMove() | |||
| const Time now (Time::getCurrentTime()); | |||
| const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::getCurrentModifiers(), | |||
| target, target, now, pos, now, 0, false); | |||
| MouseInputSource::invalidPressure, target, target, now, pos, now, 0, false); | |||
| if (me.mods.isAnyMouseButtonDown()) | |||
| mouseListeners.callChecked (checker, &MouseListener::mouseDrag, me); | |||
| @@ -25,6 +25,7 @@ | |||
| MouseEvent::MouseEvent (MouseInputSource inputSource, | |||
| Point<float> pos, | |||
| ModifierKeys modKeys, | |||
| float force, | |||
| Component* const eventComp, | |||
| Component* const originator, | |||
| Time time, | |||
| @@ -36,6 +37,7 @@ MouseEvent::MouseEvent (MouseInputSource inputSource, | |||
| x (roundToInt (pos.x)), | |||
| y (roundToInt (pos.y)), | |||
| mods (modKeys), | |||
| pressure (force), | |||
| eventComponent (eventComp), | |||
| originalComponent (originator), | |||
| eventTime (time), | |||
| @@ -57,22 +59,22 @@ MouseEvent MouseEvent::getEventRelativeTo (Component* const otherComponent) cons | |||
| jassert (otherComponent != nullptr); | |||
| return MouseEvent (source, otherComponent->getLocalPoint (eventComponent, position), | |||
| mods, otherComponent, originalComponent, eventTime, | |||
| mods, pressure, otherComponent, originalComponent, eventTime, | |||
| otherComponent->getLocalPoint (eventComponent, mouseDownPos), | |||
| mouseDownTime, numberOfClicks, wasMovedSinceMouseDown != 0); | |||
| } | |||
| MouseEvent MouseEvent::withNewPosition (Point<float> newPosition) const noexcept | |||
| { | |||
| return MouseEvent (source, newPosition, mods, eventComponent, originalComponent, | |||
| eventTime, mouseDownPos, mouseDownTime, | |||
| return MouseEvent (source, newPosition, mods, pressure, eventComponent, | |||
| originalComponent, eventTime, mouseDownPos, mouseDownTime, | |||
| numberOfClicks, wasMovedSinceMouseDown != 0); | |||
| } | |||
| MouseEvent MouseEvent::withNewPosition (Point<int> newPosition) const noexcept | |||
| { | |||
| return MouseEvent (source, newPosition.toFloat(), mods, eventComponent, originalComponent, | |||
| eventTime, mouseDownPos, mouseDownTime, | |||
| return MouseEvent (source, newPosition.toFloat(), mods, pressure, eventComponent, | |||
| originalComponent, eventTime, mouseDownPos, mouseDownTime, | |||
| numberOfClicks, wasMovedSinceMouseDown != 0); | |||
| } | |||
| @@ -112,6 +114,8 @@ int MouseEvent::getScreenY() const { return getScre | |||
| int MouseEvent::getMouseDownScreenX() const { return getMouseDownScreenPosition().x; } | |||
| int MouseEvent::getMouseDownScreenY() const { return getMouseDownScreenPosition().y; } | |||
| bool MouseEvent::isPressureValid() const noexcept { return pressure > 0.0f && pressure < 1.0f; } | |||
| //============================================================================== | |||
| static int doubleClickTimeOutMs = 400; | |||
| @@ -44,6 +44,9 @@ public: | |||
| @param source the source that's invoking the event | |||
| @param position the position of the mouse, relative to the component that is passed-in | |||
| @param modifiers the key modifiers at the time of the event | |||
| @param pressure the pressure of the touch or stylus, in the range 0 to 1. Devices that | |||
| do not support force information may return 0.0, 1.0, or a negative value, | |||
| depending on the platform | |||
| @param eventComponent the component that the mouse event applies to | |||
| @param originator the component that originally received the event | |||
| @param eventTime the time the event happened | |||
| @@ -59,6 +62,7 @@ public: | |||
| MouseEvent (MouseInputSource source, | |||
| Point<float> position, | |||
| ModifierKeys modifiers, | |||
| float pressure, | |||
| Component* eventComponent, | |||
| Component* originator, | |||
| Time eventTime, | |||
| @@ -109,6 +113,13 @@ public: | |||
| */ | |||
| const ModifierKeys mods; | |||
| /** The pressure of the touch or stylus for this event. | |||
| The range is 0 (soft) to 1 (hard). | |||
| If the input device doesn't provide any pressure data, it may return a negative | |||
| value here, or 0.0 or 1.0, depending on the platform. | |||
| */ | |||
| float pressure; | |||
| /** The component that this event applies to. | |||
| This is usually the component that the mouse was over at the time, but for mouse-drag | |||
| @@ -224,6 +235,9 @@ public: | |||
| */ | |||
| int getLengthOfMousePress() const noexcept; | |||
| /** Returns true if the pressure value for this event is meaningful. */ | |||
| bool isPressureValid() const noexcept; | |||
| //============================================================================== | |||
| /** The position of the mouse when the event occurred. | |||
| @@ -27,7 +27,7 @@ class MouseInputSourceInternal : private AsyncUpdater | |||
| public: | |||
| //============================================================================== | |||
| MouseInputSourceInternal (const int i, const bool isMouse) | |||
| : index (i), isMouseDevice (isMouse), | |||
| : index (i), isMouseDevice (isMouse), pressure (0.0f), | |||
| isUnboundedMouseModeOn (false), isCursorVisibleUntilOffscreen (false), | |||
| lastPeer (nullptr), currentCursorHandle (nullptr), | |||
| mouseEventCounter (0), mouseMovedSignificantlySincePressed (false) | |||
| @@ -40,17 +40,17 @@ public: | |||
| return buttonState.isAnyMouseButtonDown(); | |||
| } | |||
| Component* getComponentUnderMouse() const | |||
| Component* getComponentUnderMouse() const noexcept | |||
| { | |||
| return componentUnderMouse.get(); | |||
| } | |||
| ModifierKeys getCurrentModifiers() const | |||
| ModifierKeys getCurrentModifiers() const noexcept | |||
| { | |||
| return ModifierKeys::getCurrentModifiers().withoutMouseButtons().withFlags (buttonState.getRawFlags()); | |||
| } | |||
| ComponentPeer* getPeer() | |||
| ComponentPeer* getPeer() noexcept | |||
| { | |||
| if (! ComponentPeer::isValidPeer (lastPeer)) | |||
| lastPeer = nullptr; | |||
| @@ -102,6 +102,8 @@ public: | |||
| MouseInputSource::setRawMousePosition (ScalingHelpers::scaledScreenPosToUnscaled (p)); | |||
| } | |||
| bool isPressureValid() const noexcept { return pressure > 0.0f && pressure < 1.0f; } | |||
| //============================================================================== | |||
| #if JUCE_DUMP_MOUSE_EVENTS | |||
| #define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " << desc << " #" << index \ | |||
| @@ -132,13 +134,13 @@ public: | |||
| void sendMouseDown (Component& comp, Point<float> screenPos, Time time) | |||
| { | |||
| JUCE_MOUSE_EVENT_DBG ("down") | |||
| comp.internalMouseDown (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time); | |||
| comp.internalMouseDown (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure); | |||
| } | |||
| void sendMouseDrag (Component& comp, Point<float> screenPos, Time time) | |||
| { | |||
| JUCE_MOUSE_EVENT_DBG ("drag") | |||
| comp.internalMouseDrag (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time); | |||
| comp.internalMouseDrag (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure); | |||
| } | |||
| void sendMouseUp (Component& comp, Point<float> screenPos, Time time, const ModifierKeys oldMods) | |||
| @@ -287,15 +289,18 @@ public: | |||
| } | |||
| //============================================================================== | |||
| void handleEvent (ComponentPeer& newPeer, Point<float> positionWithinPeer, Time time, const ModifierKeys newMods) | |||
| void handleEvent (ComponentPeer& newPeer, Point<float> positionWithinPeer, Time time, | |||
| const ModifierKeys newMods, float newPressure) | |||
| { | |||
| lastTime = time; | |||
| const bool pressureChanged = (pressure != newPressure); | |||
| pressure = newPressure; | |||
| ++mouseEventCounter; | |||
| const Point<float> screenPos (newPeer.localToGlobal (positionWithinPeer)); | |||
| if (isDragging() && newMods.isAnyMouseButtonDown()) | |||
| { | |||
| setScreenPos (screenPos, time, false); | |||
| setScreenPos (screenPos, time, pressureChanged); | |||
| } | |||
| else | |||
| { | |||
| @@ -307,8 +312,9 @@ public: | |||
| return; // some modal events have been dispatched, so the current event is now out-of-date | |||
| peer = getPeer(); | |||
| if (peer != nullptr) | |||
| setScreenPos (screenPos, time, false); | |||
| setScreenPos (screenPos, time, pressureChanged); | |||
| } | |||
| } | |||
| } | |||
| @@ -470,6 +476,7 @@ public: | |||
| const bool isMouseDevice; | |||
| Point<float> lastScreenPos, unboundedMouseOffset; // NB: these are unscaled coords | |||
| ModifierKeys buttonState; | |||
| float pressure; | |||
| bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; | |||
| @@ -542,14 +549,16 @@ MouseInputSource& MouseInputSource::operator= (const MouseInputSource& other) no | |||
| return *this; | |||
| } | |||
| bool MouseInputSource::isMouse() const { return pimpl->isMouseDevice; } | |||
| bool MouseInputSource::isTouch() const { return ! isMouse(); } | |||
| bool MouseInputSource::canHover() const { return isMouse(); } | |||
| bool MouseInputSource::hasMouseWheel() const { return isMouse(); } | |||
| int MouseInputSource::getIndex() const { return pimpl->index; } | |||
| bool MouseInputSource::isDragging() const { return pimpl->isDragging(); } | |||
| Point<float> MouseInputSource::getScreenPosition() const { return pimpl->getScreenPosition(); } | |||
| ModifierKeys MouseInputSource::getCurrentModifiers() const { return pimpl->getCurrentModifiers(); } | |||
| bool MouseInputSource::isMouse() const noexcept { return pimpl->isMouseDevice; } | |||
| bool MouseInputSource::isTouch() const noexcept { return ! isMouse(); } | |||
| bool MouseInputSource::canHover() const noexcept { return isMouse(); } | |||
| bool MouseInputSource::hasMouseWheel() const noexcept { return isMouse(); } | |||
| int MouseInputSource::getIndex() const noexcept { return pimpl->index; } | |||
| bool MouseInputSource::isDragging() const noexcept { return pimpl->isDragging(); } | |||
| Point<float> MouseInputSource::getScreenPosition() const noexcept { return pimpl->getScreenPosition(); } | |||
| ModifierKeys MouseInputSource::getCurrentModifiers() const noexcept { return pimpl->getCurrentModifiers(); } | |||
| float MouseInputSource::getCurrentPressure() const noexcept { return pimpl->pressure; } | |||
| bool MouseInputSource::isPressureValid() const noexcept { return pimpl->isPressureValid(); } | |||
| Component* MouseInputSource::getComponentUnderMouse() const { return pimpl->getComponentUnderMouse(); } | |||
| void MouseInputSource::triggerFakeMove() const { pimpl->triggerFakeMove(); } | |||
| int MouseInputSource::getNumberOfMultipleClicks() const noexcept { return pimpl->getNumberOfMultipleClicks(); } | |||
| @@ -567,9 +576,9 @@ void MouseInputSource::revealCursor() { pimpl | |||
| void MouseInputSource::forceMouseCursorUpdate() { pimpl->revealCursor (true); } | |||
| void MouseInputSource::setScreenPosition (Point<float> p) { pimpl->setScreenPosition (p); } | |||
| void MouseInputSource::handleEvent (ComponentPeer& peer, Point<float> pos, int64 time, ModifierKeys mods) | |||
| void MouseInputSource::handleEvent (ComponentPeer& peer, Point<float> pos, int64 time, ModifierKeys mods, float pressure) | |||
| { | |||
| pimpl->handleEvent (peer, pos, Time (time), mods.withOnlyMouseButtons()); | |||
| pimpl->handleEvent (peer, pos, Time (time), mods.withOnlyMouseButtons(), pressure); | |||
| } | |||
| void MouseInputSource::handleWheel (ComponentPeer& peer, Point<float> pos, int64 time, const MouseWheelDetails& wheel) | |||
| @@ -582,6 +591,8 @@ void MouseInputSource::handleMagnifyGesture (ComponentPeer& peer, Point<float> p | |||
| pimpl->handleMagnifyGesture (peer, pos, Time (time), scaleFactor); | |||
| } | |||
| const float MouseInputSource::invalidPressure = 0.0f; | |||
| //============================================================================== | |||
| struct MouseInputSource::SourceList : public Timer | |||
| { | |||
| @@ -60,18 +60,18 @@ public: | |||
| //============================================================================== | |||
| /** Returns true if this object represents a normal desk-based mouse device. */ | |||
| bool isMouse() const; | |||
| bool isMouse() const noexcept; | |||
| /** Returns true if this object represents a source of touch events - i.e. a finger or stylus. */ | |||
| bool isTouch() const; | |||
| bool isTouch() const noexcept; | |||
| /** Returns true if this source has an on-screen pointer that can hover over | |||
| items without clicking them. | |||
| */ | |||
| bool canHover() const; | |||
| bool canHover() const noexcept; | |||
| /** Returns true if this source may have a scroll wheel. */ | |||
| bool hasMouseWheel() const; | |||
| bool hasMouseWheel() const noexcept; | |||
| /** Returns this source's index in the global list of possible sources. | |||
| If the system only has a single mouse, there will only be a single MouseInputSource | |||
| @@ -82,18 +82,28 @@ public: | |||
| number 0, and then if a second touch happens while the first is still down, it | |||
| will have index 1, etc. | |||
| */ | |||
| int getIndex() const; | |||
| int getIndex() const noexcept; | |||
| /** Returns true if this device is currently being pressed. */ | |||
| bool isDragging() const; | |||
| bool isDragging() const noexcept; | |||
| /** Returns the last-known screen position of this source. */ | |||
| Point<float> getScreenPosition() const; | |||
| Point<float> getScreenPosition() const noexcept; | |||
| /** Returns a set of modifiers that indicate which buttons are currently | |||
| held down on this device. | |||
| */ | |||
| ModifierKeys getCurrentModifiers() const; | |||
| ModifierKeys getCurrentModifiers() const noexcept; | |||
| /** Returns the device's current touch or pen pressure. | |||
| The range is 0 (soft) to 1 (hard). | |||
| If the input device doesn't provide any pressure data, it may return a negative | |||
| value here, or 0.0 or 1.0, depending on the platform. | |||
| */ | |||
| float getCurrentPressure() const noexcept; | |||
| /** Returns true if the current pressure value is meaningful. */ | |||
| bool isPressureValid() const noexcept; | |||
| /** Returns the component that was last known to be under this pointer. */ | |||
| Component* getComponentUnderMouse() const; | |||
| @@ -164,6 +174,11 @@ public: | |||
| /** Attempts to set this mouse pointer's screen position. */ | |||
| void setScreenPosition (Point<float> newPosition); | |||
| /** A default value for pressure, which is used when a device doesn't support it, or for | |||
| mouse-moves, mouse-ups, etc. | |||
| */ | |||
| static const float invalidPressure; | |||
| private: | |||
| //============================================================================== | |||
| friend class ComponentPeer; | |||
| @@ -174,7 +189,7 @@ private: | |||
| struct SourceList; | |||
| explicit MouseInputSource (MouseInputSourceInternal*) noexcept; | |||
| void handleEvent (ComponentPeer&, Point<float>, int64 time, ModifierKeys); | |||
| void handleEvent (ComponentPeer&, Point<float>, int64 time, ModifierKeys, float); | |||
| void handleWheel (ComponentPeer&, Point<float>, int64 time, const MouseWheelDetails&); | |||
| void handleMagnifyGesture (ComponentPeer&, Point<float>, int64 time, float scaleFactor); | |||
| @@ -332,7 +332,7 @@ public: | |||
| lastMousePos = pos; | |||
| // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), time); | |||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure, time); | |||
| if (isValidPeer (this)) | |||
| handleMouseDragCallback (index, sysPos, time); | |||
| @@ -346,8 +346,8 @@ public: | |||
| jassert (index < 64); | |||
| touchesDown = (touchesDown | (1 << (index & 63))); | |||
| currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons() | |||
| .withFlags (ModifierKeys::leftButtonModifier), time); | |||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier), | |||
| MouseInputSource::invalidPressure, time); | |||
| } | |||
| void handleMouseUpCallback (int index, Point<float> pos, int64 time) | |||
| @@ -361,7 +361,7 @@ public: | |||
| if (touchesDown == 0) | |||
| currentModifiers = currentModifiers.withoutMouseButtons(); | |||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), time); | |||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure, time); | |||
| } | |||
| void handleKeyDownCallback (int k, int kc) | |||
| @@ -767,7 +767,11 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons | |||
| { | |||
| UITouch* touch = [touches objectAtIndex: i]; | |||
| #if defined (__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0 | |||
| if ([touch phase] == UITouchPhaseStationary && touch.maximumPossibleForce <= 0) | |||
| #else | |||
| if ([touch phase] == UITouchPhaseStationary) | |||
| #endif | |||
| continue; | |||
| CGPoint p = [touch locationInView: view]; | |||
| @@ -788,7 +792,9 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons | |||
| modsToSend = currentModifiers; | |||
| // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
| handleMouseEvent (touchIndex, pos, modsToSend.withoutMouseButtons(), time); | |||
| handleMouseEvent (touchIndex, pos, modsToSend.withoutMouseButtons(), | |||
| MouseInputSource::invalidPressure, time); | |||
| if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
| return; | |||
| } | |||
| @@ -810,13 +816,24 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons | |||
| modsToSend = currentModifiers = currentModifiers.withoutMouseButtons(); | |||
| } | |||
| handleMouseEvent (touchIndex, pos, modsToSend, time); | |||
| float pressure = MouseInputSource::invalidPressure; | |||
| #if defined (__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0 | |||
| if (touch.maximumPossibleForce > 0) | |||
| // NB: other devices return 0 or 1.0 if pressure is unknown, so we'll clip our value to a believable range: | |||
| pressure = jlimit (0.0001f, 0.9999f, (float) (touch.force / touch.maximumPossibleForce)); | |||
| #endif | |||
| handleMouseEvent (touchIndex, pos, modsToSend, pressure, time); | |||
| if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
| return; | |||
| if (isUp || isCancel) | |||
| { | |||
| handleMouseEvent (touchIndex, Point<float> (-1.0f, -1.0f), modsToSend, time); | |||
| handleMouseEvent (touchIndex, Point<float> (-1.0f, -1.0f), | |||
| modsToSend, MouseInputSource::invalidPressure, time); | |||
| if (! isValidPeer (this)) | |||
| return; | |||
| } | |||
| @@ -2215,7 +2215,8 @@ public: | |||
| { | |||
| currentModifiers = currentModifiers.withFlags (buttonModifierFlag); | |||
| toFront (true); | |||
| handleMouseEvent (0, getMousePos (buttonPressEvent), currentModifiers, getEventTime (buttonPressEvent)); | |||
| handleMouseEvent (0, getMousePos (buttonPressEvent), currentModifiers, | |||
| MouseInputSource::invalidPressure, getEventTime (buttonPressEvent)); | |||
| } | |||
| void handleButtonPressEvent (const XButtonPressedEvent& buttonPressEvent) | |||
| @@ -2253,7 +2254,8 @@ public: | |||
| if (dragState.dragging) | |||
| handleExternalDragButtonReleaseEvent(); | |||
| handleMouseEvent (0, getMousePos (buttonRelEvent), currentModifiers, getEventTime (buttonRelEvent)); | |||
| handleMouseEvent (0, getMousePos (buttonRelEvent), currentModifiers, | |||
| MouseInputSource::invalidPressure, getEventTime (buttonRelEvent)); | |||
| clearLastMousePos(); | |||
| } | |||
| @@ -2267,7 +2269,8 @@ public: | |||
| if (dragState.dragging) | |||
| handleExternalDragMotionNotify(); | |||
| handleMouseEvent (0, getMousePos (movedEvent), currentModifiers, getEventTime (movedEvent)); | |||
| handleMouseEvent (0, getMousePos (movedEvent), currentModifiers, | |||
| MouseInputSource::invalidPressure, getEventTime (movedEvent)); | |||
| } | |||
| void handleEnterNotifyEvent (const XEnterWindowEvent& enterEvent) | |||
| @@ -2280,7 +2283,8 @@ public: | |||
| if (! currentModifiers.isAnyMouseButtonDown()) | |||
| { | |||
| updateKeyModifiers ((int) enterEvent.state); | |||
| handleMouseEvent (0, getMousePos (enterEvent), currentModifiers, getEventTime (enterEvent)); | |||
| handleMouseEvent (0, getMousePos (enterEvent), currentModifiers, | |||
| MouseInputSource::invalidPressure, getEventTime (enterEvent)); | |||
| } | |||
| } | |||
| @@ -2293,7 +2297,8 @@ public: | |||
| || leaveEvent.mode == NotifyUngrab) | |||
| { | |||
| updateKeyModifiers ((int) leaveEvent.state); | |||
| handleMouseEvent (0, getMousePos (leaveEvent), currentModifiers, getEventTime (leaveEvent)); | |||
| handleMouseEvent (0, getMousePos (leaveEvent), currentModifiers, | |||
| MouseInputSource::invalidPressure, getEventTime (leaveEvent)); | |||
| } | |||
| } | |||
| @@ -587,7 +587,8 @@ public: | |||
| sendMouseEvent (ev); | |||
| else | |||
| // moved into another window which overlaps this one, so trigger an exit | |||
| handleMouseEvent (0, Point<float> (-1.0f, -1.0f), currentModifiers, getMouseTime (ev)); | |||
| handleMouseEvent (0, Point<float> (-1.0f, -1.0f), currentModifiers, | |||
| getMousePressure (ev), getMouseTime (ev)); | |||
| showArrowCursorIfNeeded(); | |||
| } | |||
| @@ -678,7 +679,8 @@ public: | |||
| void sendMouseEvent (NSEvent* ev) | |||
| { | |||
| updateModifiers (ev); | |||
| handleMouseEvent (0, getMousePos (ev, view), currentModifiers, getMouseTime (ev)); | |||
| handleMouseEvent (0, getMousePos (ev, view), currentModifiers, | |||
| getMousePressure (ev), getMouseTime (ev)); | |||
| } | |||
| bool handleKeyEvent (NSEvent* ev, bool isKeyDown) | |||
| @@ -1080,10 +1082,15 @@ public: | |||
| return keyCode; | |||
| } | |||
| static int64 getMouseTime (NSEvent* e) | |||
| static int64 getMouseTime (NSEvent* e) noexcept | |||
| { | |||
| return (Time::currentTimeMillis() - Time::getMillisecondCounter()) | |||
| + (int64) ([e timestamp] * 1000.0); | |||
| + (int64) ([e timestamp] * 1000.0); | |||
| } | |||
| static float getMousePressure (NSEvent* e) noexcept | |||
| { | |||
| return (float) e.pressure; | |||
| } | |||
| static Point<float> getMousePos (NSEvent* e, NSView* view) | |||
| @@ -1663,9 +1663,9 @@ private: | |||
| } | |||
| //============================================================================== | |||
| void doMouseEvent (Point<float> position) | |||
| void doMouseEvent (Point<float> position, float pressure) | |||
| { | |||
| handleMouseEvent (0, position, currentModifiers, getMouseEventTime()); | |||
| handleMouseEvent (0, position, currentModifiers, pressure, getMouseEventTime()); | |||
| } | |||
| StringArray getAvailableRenderingEngines() override | |||
| @@ -1760,7 +1760,7 @@ private: | |||
| if (now >= lastMouseTime + minTimeBetweenMouses) | |||
| { | |||
| lastMouseTime = now; | |||
| doMouseEvent (position); | |||
| doMouseEvent (position, MouseInputSource::invalidPressure); | |||
| } | |||
| } | |||
| @@ -1780,7 +1780,7 @@ private: | |||
| updateModifiersFromWParam (wParam); | |||
| isDragging = true; | |||
| doMouseEvent (position); | |||
| doMouseEvent (position, MouseInputSource::invalidPressure); | |||
| } | |||
| } | |||
| @@ -1801,7 +1801,7 @@ private: | |||
| // NB: under some circumstances (e.g. double-clicking a native title bar), a mouse-up can | |||
| // arrive without a mouse-down, so in that case we need to avoid sending a message. | |||
| if (wasDragging) | |||
| doMouseEvent (position); | |||
| doMouseEvent (position, MouseInputSource::invalidPressure); | |||
| } | |||
| void doCaptureChanged() | |||
| @@ -1821,7 +1821,7 @@ private: | |||
| void doMouseExit() | |||
| { | |||
| isMouseOver = false; | |||
| doMouseEvent (getCurrentMousePos()); | |||
| doMouseEvent (getCurrentMousePos(), MouseInputSource::invalidPressure); | |||
| } | |||
| ComponentPeer* findPeerUnderMouse (Point<float>& localPos) | |||
| @@ -1925,6 +1925,7 @@ private: | |||
| const int64 time = getMouseEventTime(); | |||
| const Point<float> pos (globalToLocal (Point<float> (static_cast<float> (TOUCH_COORD_TO_PIXEL (touch.x)), | |||
| static_cast<float> (TOUCH_COORD_TO_PIXEL (touch.y))))); | |||
| const float pressure = MouseInputSource::invalidPressure; | |||
| ModifierKeys modsToSend (currentModifiers); | |||
| if (isDown) | |||
| @@ -1932,9 +1933,10 @@ private: | |||
| currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
| modsToSend = currentModifiers; | |||
| // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
| handleMouseEvent (touchIndex, pos.toFloat(), modsToSend.withoutMouseButtons(), time); | |||
| if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
| // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
| handleMouseEvent (touchIndex, pos.toFloat(), modsToSend.withoutMouseButtons(), pressure, time); | |||
| if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
| return false; | |||
| } | |||
| else if (isUp) | |||
| @@ -1956,13 +1958,15 @@ private: | |||
| currentModifiers = currentModifiers.withoutMouseButtons(); | |||
| } | |||
| handleMouseEvent (touchIndex, pos.toFloat(), modsToSend, time); | |||
| handleMouseEvent (touchIndex, pos.toFloat(), modsToSend, pressure, time); | |||
| if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
| return false; | |||
| if (isUp || isCancel) | |||
| { | |||
| handleMouseEvent (touchIndex, Point<float> (-10.0f, -10.0f), currentModifiers, time); | |||
| handleMouseEvent (touchIndex, Point<float> (-10.0f, -10.0f), currentModifiers, pressure, time); | |||
| if (! isValidPeer (this)) | |||
| return false; | |||
| } | |||
| @@ -2248,7 +2252,7 @@ private: | |||
| if (contains (pos.roundToInt(), false)) | |||
| { | |||
| doMouseEvent (pos); | |||
| doMouseEvent (pos, MouseInputSource::invalidPressure); | |||
| if (! isValidPeer (this)) | |||
| return true; | |||
| @@ -85,10 +85,10 @@ bool ComponentPeer::isKioskMode() const | |||
| } | |||
| //============================================================================== | |||
| void ComponentPeer::handleMouseEvent (int touchIndex, Point<float> pos, ModifierKeys newMods, int64 time) | |||
| void ComponentPeer::handleMouseEvent (int touchIndex, Point<float> pos, ModifierKeys newMods, float newPressure, int64 time) | |||
| { | |||
| if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex)) | |||
| MouseInputSource (*mouse).handleEvent (*this, pos, time, newMods); | |||
| MouseInputSource (*mouse).handleEvent (*this, pos, time, newMods, newPressure); | |||
| } | |||
| void ComponentPeer::handleMouseWheel (int touchIndex, Point<float> pos, int64 time, const MouseWheelDetails& wheel) | |||
| @@ -306,7 +306,7 @@ public: | |||
| virtual void setAlpha (float newAlpha) = 0; | |||
| //============================================================================== | |||
| void handleMouseEvent (int touchIndex, Point<float> positionWithinPeer, ModifierKeys newMods, int64 time); | |||
| void handleMouseEvent (int touchIndex, Point<float> positionWithinPeer, ModifierKeys newMods, float pressure, int64 time); | |||
| void handleMouseWheel (int touchIndex, Point<float> positionWithinPeer, int64 time, const MouseWheelDetails&); | |||
| void handleMagnifyGesture (int touchIndex, Point<float> positionWithinPeer, int64 time, float scaleFactor); | |||
| @@ -104,6 +104,7 @@ public: | |||
| const Time now (Time::getCurrentTime()); | |||
| MouseInputSource mouseSource = Desktop::getInstance().getMainMouseSource(); | |||
| const float pressure = (float) e.pressure; | |||
| if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up | |||
| { | |||
| @@ -113,17 +114,17 @@ public: | |||
| owner.mouseDown (MouseEvent (mouseSource, Point<float>(), | |||
| eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier | |||
| : ModifierKeys::rightButtonModifier), | |||
| &owner, &owner, now, | |||
| pressure, &owner, &owner, now, | |||
| Point<float>(), now, 1, false)); | |||
| owner.mouseUp (MouseEvent (mouseSource, Point<float>(), eventMods.withoutMouseButtons(), | |||
| &owner, &owner, now, | |||
| pressure, &owner, &owner, now, | |||
| Point<float>(), now, 1, false)); | |||
| } | |||
| else if (type == NSMouseMoved) | |||
| { | |||
| owner.mouseMove (MouseEvent (mouseSource, Point<float>(), eventMods, | |||
| &owner, &owner, now, | |||
| pressure, &owner, &owner, now, | |||
| Point<float>(), now, 1, false)); | |||
| } | |||
| } | |||
| @@ -189,6 +189,7 @@ namespace ActiveXHelpers | |||
| peer->handleMouseEvent (0, Point<int> (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left, | |||
| GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top).toFloat(), | |||
| ModifierKeys::getCurrentModifiersRealtime(), | |||
| MouseInputSource::invalidPressure, | |||
| getMouseEventTime()); | |||
| break; | |||
| @@ -111,8 +111,8 @@ public: | |||
| const Time eventTime (getMouseEventTime()); | |||
| const MouseEvent e (Desktop::getInstance().getMainMouseSource(), | |||
| Point<float>(), eventMods, &owner, &owner, eventTime, | |||
| Point<float>(), eventTime, 1, false); | |||
| Point<float>(), eventMods, MouseInputSource::invalidPressure, | |||
| &owner, &owner, eventTime, Point<float>(), eventTime, 1, false); | |||
| if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) | |||
| { | |||