From a3426aae10f632152612fc3f1255e88d6fb1f17d Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 2 Nov 2015 11:51:16 +0000 Subject: [PATCH] Added support for iOS force-touch --- examples/Demo/Source/Demos/MultiTouch.cpp | 31 +++++++----- .../utility/juce_FakeMouseMoveGenerator.h | 3 +- .../components/juce_Component.cpp | 24 ++++----- .../components/juce_Component.h | 4 +- .../components/juce_Desktop.cpp | 2 +- .../juce_gui_basics/mouse/juce_MouseEvent.cpp | 14 ++++-- .../juce_gui_basics/mouse/juce_MouseEvent.h | 14 ++++++ .../mouse/juce_MouseInputSource.cpp | 49 ++++++++++++------- .../mouse/juce_MouseInputSource.h | 33 +++++++++---- .../native/juce_android_Windowing.cpp | 8 +-- .../native/juce_ios_UIViewComponentPeer.mm | 23 +++++++-- .../native/juce_linux_Windowing.cpp | 15 ++++-- .../native/juce_mac_NSViewComponentPeer.mm | 15 ++++-- .../native/juce_win32_Windowing.cpp | 28 ++++++----- .../windows/juce_ComponentPeer.cpp | 4 +- .../windows/juce_ComponentPeer.h | 2 +- .../native/juce_mac_SystemTrayIcon.cpp | 7 +-- .../native/juce_win32_ActiveXComponent.cpp | 1 + .../native/juce_win32_SystemTrayIcon.cpp | 4 +- 19 files changed, 185 insertions(+), 96 deletions(-) diff --git a/examples/Demo/Source/Demos/MultiTouch.cpp b/examples/Demo/Source/Demos/MultiTouch.cpp index 7f1c38dc3d..cb58d2a41d 100644 --- a/examples/Demo/Source/Demos/MultiTouch.cpp +++ b/examples/Demo/Source/Demos/MultiTouch.cpp @@ -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 p, ModifierKeys newMods) + void pushPoint (Point 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()) { - path.quadraticTo (lastPoint, p); - lastPoint = Point(); - } - 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)"; diff --git a/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h b/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h index a7336dd6ea..d239cc1eca 100644 --- a/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h +++ b/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h @@ -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()); } } diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index a02f6a56e1..925da676fe 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -2384,7 +2384,7 @@ void Component::internalMouseEnter (MouseInputSource source, Point 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 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 relativ MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseExit, me); } -void Component::internalMouseDown (MouseInputSource source, Point relativePos, Time time) +void Component::internalMouseDown (MouseInputSource source, Point relativePos, Time time, float pressure) { Desktop& desktop = Desktop::getInstance(); BailOutChecker checker (this); @@ -2435,7 +2435,7 @@ void Component::internalMouseDown (MouseInputSource source, Point 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 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 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 relativeP } } -void Component::internalMouseDrag (MouseInputSource source, Point relativePos, Time time) +void Component::internalMouseDrag (MouseInputSource source, Point 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 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 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 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); diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 9b93c4ef08..d4bbd58f58 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -2300,9 +2300,9 @@ private: //============================================================================== void internalMouseEnter (MouseInputSource, Point, Time); void internalMouseExit (MouseInputSource, Point, Time); - void internalMouseDown (MouseInputSource, Point, Time); + void internalMouseDown (MouseInputSource, Point, Time, float); void internalMouseUp (MouseInputSource, Point, Time, const ModifierKeys oldModifiers); - void internalMouseDrag (MouseInputSource, Point, Time); + void internalMouseDrag (MouseInputSource, Point, Time, float); void internalMouseMove (MouseInputSource, Point, Time); void internalMouseWheel (MouseInputSource, Point, Time, const MouseWheelDetails&); void internalMagnifyGesture (MouseInputSource, Point, Time, float); diff --git a/modules/juce_gui_basics/components/juce_Desktop.cpp b/modules/juce_gui_basics/components/juce_Desktop.cpp index 66d7c4bc3e..56f818b60f 100644 --- a/modules/juce_gui_basics/components/juce_Desktop.cpp +++ b/modules/juce_gui_basics/components/juce_Desktop.cpp @@ -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); diff --git a/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp b/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp index 517b1982a7..bf5cb87a75 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp +++ b/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp @@ -25,6 +25,7 @@ MouseEvent::MouseEvent (MouseInputSource inputSource, Point 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 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 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; diff --git a/modules/juce_gui_basics/mouse/juce_MouseEvent.h b/modules/juce_gui_basics/mouse/juce_MouseEvent.h index 5cc6c789da..9d993e31da 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseEvent.h +++ b/modules/juce_gui_basics/mouse/juce_MouseEvent.h @@ -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 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. diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp index 77be371368..2302105cd4 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp +++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp @@ -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 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 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 screenPos, Time time, const ModifierKeys oldMods) @@ -287,15 +289,18 @@ public: } //============================================================================== - void handleEvent (ComponentPeer& newPeer, Point positionWithinPeer, Time time, const ModifierKeys newMods) + void handleEvent (ComponentPeer& newPeer, Point positionWithinPeer, Time time, + const ModifierKeys newMods, float newPressure) { lastTime = time; + const bool pressureChanged = (pressure != newPressure); + pressure = newPressure; ++mouseEventCounter; const Point 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 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 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 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 p) { pimpl->setScreenPosition (p); } -void MouseInputSource::handleEvent (ComponentPeer& peer, Point pos, int64 time, ModifierKeys mods) +void MouseInputSource::handleEvent (ComponentPeer& peer, Point 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 pos, int64 time, const MouseWheelDetails& wheel) @@ -582,6 +591,8 @@ void MouseInputSource::handleMagnifyGesture (ComponentPeer& peer, Point p pimpl->handleMagnifyGesture (peer, pos, Time (time), scaleFactor); } +const float MouseInputSource::invalidPressure = 0.0f; + //============================================================================== struct MouseInputSource::SourceList : public Timer { diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.h b/modules/juce_gui_basics/mouse/juce_MouseInputSource.h index 7bf19c5cfa..bbceb508d6 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.h +++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.h @@ -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 getScreenPosition() const; + Point 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 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, int64 time, ModifierKeys); + void handleEvent (ComponentPeer&, Point, int64 time, ModifierKeys, float); void handleWheel (ComponentPeer&, Point, int64 time, const MouseWheelDetails&); void handleMagnifyGesture (ComponentPeer&, Point, int64 time, float scaleFactor); diff --git a/modules/juce_gui_basics/native/juce_android_Windowing.cpp b/modules/juce_gui_basics/native/juce_android_Windowing.cpp index c1627ec3db..e212d5c84c 100644 --- a/modules/juce_gui_basics/native/juce_android_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_android_Windowing.cpp @@ -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 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) diff --git a/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm index 32f8c2487e..f6de8d650e 100644 --- a/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm @@ -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 (-1.0f, -1.0f), modsToSend, time); + handleMouseEvent (touchIndex, Point (-1.0f, -1.0f), + modsToSend, MouseInputSource::invalidPressure, time); + if (! isValidPeer (this)) return; } diff --git a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index 4002f4cd66..2de412a7d0 100644 --- a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -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)); } } diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 0f1bf2e250..d59f039241 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -587,7 +587,8 @@ public: sendMouseEvent (ev); else // moved into another window which overlaps this one, so trigger an exit - handleMouseEvent (0, Point (-1.0f, -1.0f), currentModifiers, getMouseTime (ev)); + handleMouseEvent (0, Point (-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 getMousePos (NSEvent* e, NSView* view) diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index 0dcf00b8f6..df708e312a 100644 --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -1663,9 +1663,9 @@ private: } //============================================================================== - void doMouseEvent (Point position) + void doMouseEvent (Point 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& localPos) @@ -1925,6 +1925,7 @@ private: const int64 time = getMouseEventTime(); const Point pos (globalToLocal (Point (static_cast (TOUCH_COORD_TO_PIXEL (touch.x)), static_cast (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 (-10.0f, -10.0f), currentModifiers, time); + handleMouseEvent (touchIndex, Point (-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; diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp index 370983813a..cb71b21985 100644 --- a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp +++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp @@ -85,10 +85,10 @@ bool ComponentPeer::isKioskMode() const } //============================================================================== -void ComponentPeer::handleMouseEvent (int touchIndex, Point pos, ModifierKeys newMods, int64 time) +void ComponentPeer::handleMouseEvent (int touchIndex, Point 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 pos, int64 time, const MouseWheelDetails& wheel) diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.h b/modules/juce_gui_basics/windows/juce_ComponentPeer.h index c2a609d6b1..a79a1fbd06 100644 --- a/modules/juce_gui_basics/windows/juce_ComponentPeer.h +++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.h @@ -306,7 +306,7 @@ public: virtual void setAlpha (float newAlpha) = 0; //============================================================================== - void handleMouseEvent (int touchIndex, Point positionWithinPeer, ModifierKeys newMods, int64 time); + void handleMouseEvent (int touchIndex, Point positionWithinPeer, ModifierKeys newMods, float pressure, int64 time); void handleMouseWheel (int touchIndex, Point positionWithinPeer, int64 time, const MouseWheelDetails&); void handleMagnifyGesture (int touchIndex, Point positionWithinPeer, int64 time, float scaleFactor); diff --git a/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp b/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp index c1d66ff247..c04e109041 100644 --- a/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp +++ b/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp @@ -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(), eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier : ModifierKeys::rightButtonModifier), - &owner, &owner, now, + pressure, &owner, &owner, now, Point(), now, 1, false)); owner.mouseUp (MouseEvent (mouseSource, Point(), eventMods.withoutMouseButtons(), - &owner, &owner, now, + pressure, &owner, &owner, now, Point(), now, 1, false)); } else if (type == NSMouseMoved) { owner.mouseMove (MouseEvent (mouseSource, Point(), eventMods, - &owner, &owner, now, + pressure, &owner, &owner, now, Point(), now, 1, false)); } } diff --git a/modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp b/modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp index 2d2555707c..b35b6fcb5b 100644 --- a/modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp +++ b/modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp @@ -189,6 +189,7 @@ namespace ActiveXHelpers peer->handleMouseEvent (0, Point (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left, GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top).toFloat(), ModifierKeys::getCurrentModifiersRealtime(), + MouseInputSource::invalidPressure, getMouseEventTime()); break; diff --git a/modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp b/modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp index 4b4007a1d2..8737955c74 100644 --- a/modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp +++ b/modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp @@ -111,8 +111,8 @@ public: const Time eventTime (getMouseEventTime()); const MouseEvent e (Desktop::getInstance().getMainMouseSource(), - Point(), eventMods, &owner, &owner, eventTime, - Point(), eventTime, 1, false); + Point(), eventMods, MouseInputSource::invalidPressure, + &owner, &owner, eventTime, Point(), eventTime, 1, false); if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) {