1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Multiple fixes for touch and pen input on Windows

This commit is contained in:
ed 2017-03-15 17:16:04 +00:00
parent 2e08db47ff
commit b7b8d5be57
21 changed files with 569 additions and 196 deletions

View file

@ -2402,6 +2402,8 @@ void Component::internalMouseEnter (MouseInputSource source, Point<float> relati
BailOutChecker checker (this);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
this, this, time, relativePos, time, 0, false);
mouseEnter (me);
@ -2428,6 +2430,8 @@ void Component::internalMouseExit (MouseInputSource source, Point<float> relativ
BailOutChecker checker (this);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
this, this, time, relativePos, time, 0, false);
mouseExit (me);
@ -2440,7 +2444,8 @@ 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, float pressure)
void Component::internalMouseDown (MouseInputSource source, Point<float> relativePos, Time time,
float pressure, float orientation, float rotation, float tiltX, float tiltY)
{
Desktop& desktop = Desktop::getInstance();
BailOutChecker checker (this);
@ -2458,9 +2463,9 @@ void Component::internalMouseDown (MouseInputSource source, Point<float> relativ
if (isCurrentlyBlockedByAnotherModalComponent())
{
// allow blocked mouse-events to go to global listeners..
const MouseEvent me (source, relativePos, source.getCurrentModifiers(),
pressure, this, this, time, relativePos, time,
source.getNumberOfMultipleClicks(), false);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), pressure,
orientation, rotation, tiltX, tiltY, this, this, time, relativePos,
time, source.getNumberOfMultipleClicks(), false);
desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseDown, me);
return;
@ -2491,9 +2496,9 @@ void Component::internalMouseDown (MouseInputSource source, Point<float> relativ
if (flags.repaintOnMouseActivityFlag)
repaint();
const MouseEvent me (source, relativePos, source.getCurrentModifiers(),
pressure, this, this, time, relativePos, time,
source.getNumberOfMultipleClicks(), false);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), pressure,
orientation, rotation, tiltX, tiltY, this, this, time, relativePos,
time, source.getNumberOfMultipleClicks(), false);
mouseDown (me);
if (checker.shouldBailOut())
@ -2504,8 +2509,8 @@ void Component::internalMouseDown (MouseInputSource source, Point<float> relativ
MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseDown, me);
}
void Component::internalMouseUp (MouseInputSource source, Point<float> relativePos,
Time time, const ModifierKeys oldModifiers, float pressure)
void Component::internalMouseUp (MouseInputSource source, Point<float> relativePos, Time time,
const ModifierKeys oldModifiers, float pressure, float orientation, float rotation, float tiltX, float tiltY)
{
if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent())
return;
@ -2515,8 +2520,8 @@ void Component::internalMouseUp (MouseInputSource source, Point<float> relativeP
if (flags.repaintOnMouseActivityFlag)
repaint();
const MouseEvent me (source, relativePos,
oldModifiers, pressure, this, this, time,
const MouseEvent me (source, relativePos, oldModifiers, pressure, orientation,
rotation, tiltX, tiltY, this, this, time,
getLocalPoint (nullptr, source.getLastMouseDownPosition()),
source.getLastMouseDownTime(),
source.getNumberOfMultipleClicks(),
@ -2547,14 +2552,15 @@ void Component::internalMouseUp (MouseInputSource source, Point<float> relativeP
}
}
void Component::internalMouseDrag (MouseInputSource source, Point<float> relativePos, Time time, float pressure)
void Component::internalMouseDrag (MouseInputSource source, Point<float> relativePos, Time time,
float pressure, float orientation, float rotation, float tiltX, float tiltY)
{
if (! isCurrentlyBlockedByAnotherModalComponent())
{
BailOutChecker checker (this);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(),
pressure, this, this, time,
pressure, orientation, rotation, tiltX, tiltY, this, this, time,
getLocalPoint (nullptr, source.getLastMouseDownPosition()),
source.getLastMouseDownTime(),
source.getNumberOfMultipleClicks(),
@ -2584,6 +2590,8 @@ void Component::internalMouseMove (MouseInputSource source, Point<float> relativ
BailOutChecker checker (this);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
this, this, time, relativePos, time, 0, false);
mouseMove (me);
@ -2603,6 +2611,8 @@ void Component::internalMouseWheel (MouseInputSource source, Point<float> relati
BailOutChecker checker (this);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
this, this, time, relativePos, time, 0, false);
if (isCurrentlyBlockedByAnotherModalComponent())
@ -2630,6 +2640,8 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point<float> re
if (! isCurrentlyBlockedByAnotherModalComponent())
{
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
this, this, time, relativePos, time, 0, false);
mouseMagnify (me, amount);
@ -2967,15 +2979,13 @@ void Component::sendEnablementChangeMessage()
//==============================================================================
bool Component::isMouseOver (const bool includeChildren) const
{
const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources();
for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi)
for (auto& ms : Desktop::getInstance().getMouseSources())
{
Component* const c = mi->getComponentUnderMouse();
auto* c = ms.getComponentUnderMouse();
if ((c == this || (includeChildren && isParentOf (c)))
&& c->reallyContains (c->getLocalPoint (nullptr, mi->getScreenPosition()).roundToInt(), false)
&& (mi->isMouse() || mi->isDragging()))
&& c->reallyContains (c->getLocalPoint (nullptr, ms.getScreenPosition()).roundToInt(), false)
&& ((! ms.isTouch()) || ms.isDragging()))
return true;
}
@ -2984,10 +2994,8 @@ bool Component::isMouseOver (const bool includeChildren) const
bool Component::isMouseButtonDown() const
{
const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources();
for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi)
if (mi->isDragging() && mi->getComponentUnderMouse() == this)
for (auto& ms : Desktop::getInstance().getMouseSources())
if (ms.isDragging() && ms.getComponentUnderMouse() == this)
return true;
return false;
@ -2995,14 +3003,12 @@ bool Component::isMouseButtonDown() const
bool Component::isMouseOverOrDragging (const bool includeChildren) const
{
const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources();
for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi)
for (auto& ms : Desktop::getInstance().getMouseSources())
{
Component* const c = mi->getComponentUnderMouse();
auto* c = ms.getComponentUnderMouse();
if ((c == this || (includeChildren && isParentOf (c)))
&& (mi->isMouse() || mi->isDragging()))
&& ((! ms.isTouch()) || ms.isDragging()))
return true;
}

View file

@ -2299,9 +2299,9 @@ private:
//==============================================================================
void internalMouseEnter (MouseInputSource, Point<float>, Time);
void internalMouseExit (MouseInputSource, Point<float>, Time);
void internalMouseDown (MouseInputSource, Point<float>, Time, float);
void internalMouseUp (MouseInputSource, Point<float>, Time, const ModifierKeys oldModifiers, float);
void internalMouseDrag (MouseInputSource, Point<float>, Time, float);
void internalMouseDown (MouseInputSource, Point<float>, Time, float, float, float, float, float);
void internalMouseUp (MouseInputSource, Point<float>, Time, const ModifierKeys oldModifiers, float, float, float, float, float);
void internalMouseDrag (MouseInputSource, Point<float>, Time, float, float, float, float, float);
void internalMouseMove (MouseInputSource, Point<float>, Time);
void internalMouseWheel (MouseInputSource, Point<float>, Time, const MouseWheelDetails&);
void internalMagnifyGesture (MouseInputSource, Point<float>, Time, float);

View file

@ -240,14 +240,16 @@ void Desktop::sendMouseMove()
lastFakeMouseMove = getMousePositionFloat();
if (Component* const target = findComponentAt (lastFakeMouseMove.roundToInt()))
if (auto* target = findComponentAt (lastFakeMouseMove.roundToInt()))
{
Component::BailOutChecker checker (target);
const Point<float> pos (target->getLocalPoint (nullptr, lastFakeMouseMove));
const Time now (Time::getCurrentTime());
const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::getCurrentModifiers(),
MouseInputSource::invalidPressure, target, target, now, pos, now, 0, false);
const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::getCurrentModifiers(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
target, target, now, pos, now, 0, false);
if (me.mods.isAnyMouseButtonDown())
mouseListeners.callChecked (checker, &MouseListener::mouseDrag, me);

View file

@ -120,6 +120,7 @@ class MarkerList;
class RelativeRectangle;
class MouseEvent;
struct MouseWheelDetails;
struct PenDetails;
class ToggleButton;
class TextButton;
class AlertWindow;

View file

@ -26,6 +26,8 @@ MouseEvent::MouseEvent (MouseInputSource inputSource,
Point<float> pos,
ModifierKeys modKeys,
float force,
float o, float r,
float tX, float tY,
Component* const eventComp,
Component* const originator,
Time time,
@ -38,6 +40,8 @@ MouseEvent::MouseEvent (MouseInputSource inputSource,
y (roundToInt (pos.y)),
mods (modKeys),
pressure (force),
orientation (o), rotation (r),
tiltX (tX), tiltY (tY),
eventComponent (eventComp),
originalComponent (originator),
eventTime (time),
@ -59,23 +63,24 @@ MouseEvent MouseEvent::getEventRelativeTo (Component* const otherComponent) cons
jassert (otherComponent != nullptr);
return MouseEvent (source, otherComponent->getLocalPoint (eventComponent, position),
mods, pressure, otherComponent, originalComponent, eventTime,
mods, pressure, orientation, rotation, tiltX, tiltY,
otherComponent, originalComponent, eventTime,
otherComponent->getLocalPoint (eventComponent, mouseDownPos),
mouseDownTime, numberOfClicks, wasMovedSinceMouseDown != 0);
}
MouseEvent MouseEvent::withNewPosition (Point<float> newPosition) const noexcept
{
return MouseEvent (source, newPosition, mods, pressure, eventComponent,
originalComponent, eventTime, mouseDownPos, mouseDownTime,
return MouseEvent (source, newPosition, mods, pressure, orientation, rotation, tiltX, tiltY,
eventComponent, originalComponent, eventTime, mouseDownPos, mouseDownTime,
numberOfClicks, wasMovedSinceMouseDown != 0);
}
MouseEvent MouseEvent::withNewPosition (Point<int> newPosition) const noexcept
{
return MouseEvent (source, newPosition.toFloat(), mods, pressure, eventComponent,
originalComponent, eventTime, mouseDownPos, mouseDownTime,
numberOfClicks, wasMovedSinceMouseDown != 0);
return MouseEvent (source, newPosition.toFloat(), mods, pressure, orientation, rotation,
tiltX, tiltY, eventComponent, originalComponent, eventTime, mouseDownPos,
mouseDownTime, numberOfClicks, wasMovedSinceMouseDown != 0);
}
//==============================================================================
@ -120,6 +125,9 @@ int MouseEvent::getMouseDownScreenX() const { return getMous
int MouseEvent::getMouseDownScreenY() const { return getMouseDownScreenPosition().y; }
bool MouseEvent::isPressureValid() const noexcept { return pressure > 0.0f && pressure < 1.0f; }
bool MouseEvent::isOrientationValid() const noexcept { return orientation >= 0.0f && orientation <= 2.0f * float_Pi; }
bool MouseEvent::isRotationValid() const noexcept { return rotation >= 0 && rotation <= 2.0f * float_Pi; }
bool MouseEvent::isTiltValid (bool isX) const noexcept { return isX ? (tiltX >= -1.0f && tiltX <= 1.0f) : (tiltY >= -1.0f && tiltY <= 1.0f); }
//==============================================================================
static int doubleClickTimeOutMs = 400;

View file

@ -24,7 +24,6 @@
#pragma once
//==============================================================================
/**
Contains position and status information about a mouse event.
@ -46,6 +45,10 @@ public:
@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 orientation the orientation of the touch input for this event in radians. The default is 0
@param rotation the rotation of the pen device for this event in radians. The default is 0
@param tiltX the tilt of the pen device along the x-axis between -1.0 and 1.0. The default is 0
@param tiltY the tilt of the pen device along the y-axis between -1.0 and 1.0. The default is 0
@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
@ -62,6 +65,8 @@ public:
Point<float> position,
ModifierKeys modifiers,
float pressure,
float orientation, float rotation,
float tiltX, float tiltY,
Component* eventComponent,
Component* originator,
Time eventTime,
@ -117,7 +122,27 @@ public:
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;
const float pressure;
/** The orientation of the touch input for this event in radians where 0 indicates a touch aligned with the x-axis
and pointing from left to right; increasing values indicate rotation in the clockwise direction. The default is 0.
*/
const float orientation;
/** The rotation of the pen device for this event in radians. Indicates the clockwise
rotation, or twist, of the pen. The default is 0.
*/
const float rotation;
/** The tilt of the pen device along the x-axis between -1.0 and 1.0. A positive value indicates
a tilt to the right. The default is 0.
*/
const float tiltX;
/** The tilt of the pen device along the y-axis between -1.0 and 1.0. A positive value indicates
a tilt toward the user. The default is 0.
*/
const float tiltY;
/** The component that this event applies to.
@ -239,6 +264,15 @@ public:
/** Returns true if the pressure value for this event is meaningful. */
bool isPressureValid() const noexcept;
/** Returns true if the orientation value for this event is meaningful. */
bool isOrientationValid() const noexcept;
/** Returns true if the rotation value for this event is meaningful. */
bool isRotationValid() const noexcept;
/** Returns true if the current tilt value (either x- or y-axis) is meaningful. */
bool isTiltValid (bool tiltX) const noexcept;
//==============================================================================
/** The position of the mouse when the event occurred.
@ -374,3 +408,30 @@ struct MouseWheelDetails
the wheel being released. */
bool isInertial;
};
//==============================================================================
/**
Contains status information about a pen event.
@see MouseListener, MouseEvent
*/
struct PenDetails
{
/**
The rotation of the pen device in radians. Indicates the clockwise rotation, or twist,
of the pen. The default is 0.
*/
float rotation;
/**
Indicates the angle of tilt of the pointer in a range of -1.0 to 1.0 along the x-axis where
a positive value indicates a tilt to the right. The default is 0.
*/
float tiltX;
/**
Indicates the angle of tilt of the pointer in a range of -1.0 to 1.0 along the y-axis where
a positive value indicates a tilt toward the user. The default is 0.
*/
float tiltY;
};

View file

@ -26,11 +26,10 @@ class MouseInputSourceInternal : private AsyncUpdater
{
public:
//==============================================================================
MouseInputSourceInternal (const int i, const bool isMouse)
: index (i), isMouseDevice (isMouse), pressure (0.0f),
isUnboundedMouseModeOn (false), isCursorVisibleUntilOffscreen (false),
lastPeer (nullptr), currentCursorHandle (nullptr),
mouseEventCounter (0), mouseMovedSignificantlySincePressed (false)
MouseInputSourceInternal (const int i, const MouseInputSource::InputSourceType type)
: index (i), inputType (type), pressure (0.0f), orientation (0.0f), rotation (0.0f), tiltX (0.0f), tiltY (0.0f),
isUnboundedMouseModeOn (false), isCursorVisibleUntilOffscreen (false), lastPeer (nullptr),
currentCursorHandle (nullptr), mouseEventCounter (0), mouseMovedSignificantlySincePressed (false)
{
}
@ -93,8 +92,8 @@ public:
// This needs to return the live position if possible, but it mustn't update the lastScreenPos
// value, because that can cause continuity problems.
return ScalingHelpers::unscaledScreenPosToScaled
(unboundedMouseOffset + (isMouseDevice ? MouseInputSource::getCurrentRawMousePosition()
: lastScreenPos));
(unboundedMouseOffset + (inputType != MouseInputSource::InputSourceType::touch ? MouseInputSource::getCurrentRawMousePosition()
: lastScreenPos));
}
void setScreenPosition (Point<float> p)
@ -102,11 +101,15 @@ public:
MouseInputSource::setRawMousePosition (ScalingHelpers::scaledScreenPosToUnscaled (p));
}
bool isPressureValid() const noexcept { return pressure > 0.0f && pressure < 1.0f; }
bool isPressureValid() const noexcept { return pressure >= 0.0f && pressure <= 1.0f; }
bool isOrientationValid() const noexcept { return orientation >= 0.0f && orientation <= 2.0f * float_Pi; }
bool isRotationValid() const noexcept { return rotation >= 0.0f && rotation <= 2.0f * float_Pi; }
bool isTiltValid (bool isX) const noexcept { return isX ? (tiltX >= -1.0f && tiltX <= 1.0f) : (tiltY >= -1.0f && tiltY <= 1.0f); }
//==============================================================================
#if JUCE_DUMP_MOUSE_EVENTS
#define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " << desc << " #" << index \
#define JUCE_MOUSE_EVENT_
(desc) DBG ("Mouse " << desc << " #" << index \
<< ": " << screenPosToLocalPos (comp, screenPos).toString() \
<< " - Comp: " << String::toHexString ((pointer_sized_int) &comp));
#else
@ -134,19 +137,19 @@ public:
void sendMouseDown (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("down")
comp.internalMouseDown (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure);
comp.internalMouseDown (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure, orientation, rotation, tiltX, tiltY);
}
void sendMouseDrag (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("drag")
comp.internalMouseDrag (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure);
comp.internalMouseDrag (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure, orientation, rotation, tiltX, tiltY);
}
void sendMouseUp (Component& comp, Point<float> screenPos, Time time, const ModifierKeys oldMods)
{
JUCE_MOUSE_EVENT_DBG ("up")
comp.internalMouseUp (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, oldMods, pressure);
comp.internalMouseUp (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, oldMods, pressure, orientation, rotation, tiltX, tiltY);
}
void sendMouseWheel (Component& comp, Point<float> screenPos, Time time, const MouseWheelDetails& wheel)
@ -290,17 +293,32 @@ public:
//==============================================================================
void handleEvent (ComponentPeer& newPeer, Point<float> positionWithinPeer, Time time,
const ModifierKeys newMods, float newPressure)
const ModifierKeys newMods, float newPressure, float newOrientation, PenDetails pen)
{
lastTime = time;
const bool pressureChanged = (pressure != newPressure);
pressure = newPressure;
const bool orientationChanged = (orientation != newOrientation);
orientation = newOrientation;
const bool rotationChanged = (rotation != pen.rotation);
rotation = pen.rotation;
const bool tiltChanged = (tiltX != pen.tiltX || tiltY != pen.tiltY);
tiltX = pen.tiltX;
tiltY = pen.tiltY;
const bool shouldUpdate = (pressureChanged || orientationChanged || rotationChanged || tiltChanged);
++mouseEventCounter;
const Point<float> screenPos (newPeer.localToGlobal (positionWithinPeer));
if (isDragging() && newMods.isAnyMouseButtonDown())
{
setScreenPos (screenPos, time, pressureChanged);
setScreenPos (screenPos, time, shouldUpdate);
}
else
{
@ -314,7 +332,7 @@ public:
peer = getPeer();
if (peer != nullptr)
setScreenPos (screenPos, time, pressureChanged);
setScreenPos (screenPos, time, shouldUpdate);
}
}
}
@ -475,10 +493,14 @@ public:
//==============================================================================
const int index;
const bool isMouseDevice;
const MouseInputSource::InputSourceType inputType;
Point<float> lastScreenPos, unboundedMouseOffset; // NB: these are unscaled coords
ModifierKeys buttonState;
float pressure;
float orientation;
float rotation;
float tiltX;
float tiltY;
bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen;
@ -551,36 +573,43 @@ MouseInputSource& MouseInputSource::operator= (const MouseInputSource& other) no
return *this;
}
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(); }
Time MouseInputSource::getLastMouseDownTime() const noexcept { return pimpl->getLastMouseDownTime(); }
Point<float> MouseInputSource::getLastMouseDownPosition() const noexcept { return pimpl->getLastMouseDownPosition(); }
MouseInputSource::InputSourceType MouseInputSource::getType() const noexcept { return pimpl->inputType; }
bool MouseInputSource::isTouch() const noexcept { return (getType() == MouseInputSource::InputSourceType::touch); }
bool MouseInputSource::canHover() const noexcept { return ! isTouch(); }
bool MouseInputSource::hasMouseWheel() const noexcept { return ! isTouch(); }
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(); }
float MouseInputSource::getCurrentOrientation() const noexcept { return pimpl->orientation; }
bool MouseInputSource::isOrientationValid() const noexcept { return pimpl->isOrientationValid(); }
float MouseInputSource::getCurrentRotation() const noexcept { return pimpl->rotation; }
bool MouseInputSource::isRotationValid() const noexcept { return pimpl->isRotationValid(); }
float MouseInputSource::getCurrentTilt (bool tiltX) const noexcept { return tiltX ? pimpl->tiltX : pimpl->tiltY; }
bool MouseInputSource::isTiltValid (bool isX) const noexcept { return pimpl->isTiltValid (isX); }
Component* MouseInputSource::getComponentUnderMouse() const { return pimpl->getComponentUnderMouse(); }
void MouseInputSource::triggerFakeMove() const { pimpl->triggerFakeMove(); }
int MouseInputSource::getNumberOfMultipleClicks() const noexcept { return pimpl->getNumberOfMultipleClicks(); }
Time MouseInputSource::getLastMouseDownTime() const noexcept { return pimpl->getLastMouseDownTime(); }
Point<float> MouseInputSource::getLastMouseDownPosition() const noexcept { return pimpl->getLastMouseDownPosition(); }
bool MouseInputSource::hasMouseMovedSignificantlySincePressed() const noexcept { return pimpl->hasMouseMovedSignificantlySincePressed(); }
bool MouseInputSource::canDoUnboundedMovement() const noexcept { return isMouse(); }
bool MouseInputSource::canDoUnboundedMovement() const noexcept { return ! isTouch(); }
void MouseInputSource::enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen) const
{ pimpl->enableUnboundedMouseMovement (isEnabled, keepCursorVisibleUntilOffscreen); }
bool MouseInputSource::isUnboundedMouseMovementEnabled() const { return pimpl->isUnboundedMouseModeOn; }
bool MouseInputSource::hasMouseCursor() const noexcept { return isMouse(); }
bool MouseInputSource::hasMouseCursor() const noexcept { return ! isTouch(); }
void MouseInputSource::showMouseCursor (const MouseCursor& cursor) { pimpl->showMouseCursor (cursor, false); }
void MouseInputSource::hideCursor() { pimpl->hideCursor(); }
void MouseInputSource::revealCursor() { pimpl->revealCursor (false); }
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, float pressure)
void MouseInputSource::handleEvent (ComponentPeer& peer, Point<float> pos, int64 time, ModifierKeys mods,
float pressure, float orientation, const PenDetails& pen)
{
pimpl->handleEvent (peer, pos, Time (time), mods.withOnlyMouseButtons(), pressure);
pimpl->handleEvent (peer, pos, Time (time), mods.withOnlyMouseButtons(), pressure, orientation, pen);
}
void MouseInputSource::handleWheel (ComponentPeer& peer, Point<float> pos, int64 time, const MouseWheelDetails& wheel)
@ -594,22 +623,30 @@ void MouseInputSource::handleMagnifyGesture (ComponentPeer& peer, Point<float> p
}
const float MouseInputSource::invalidPressure = 0.0f;
const float MouseInputSource::invalidOrientation = 0.0f;
const float MouseInputSource::invalidRotation = 0.0f;
const float MouseInputSource::invalidTiltX = 0.0f;
const float MouseInputSource::invalidTiltY = 0.0f;
//==============================================================================
struct MouseInputSource::SourceList : public Timer
{
SourceList()
{
addSource();
addSource (0, MouseInputSource::InputSourceType::mouse);
}
bool addSource();
bool canUseTouch();
void addSource (int index, bool isMouse)
MouseInputSource* addSource (int index, MouseInputSource::InputSourceType type)
{
MouseInputSourceInternal* s = new MouseInputSourceInternal (index, isMouse);
auto* s = new MouseInputSourceInternal (index, type);
sources.add (s);
sourceArray.add (MouseInputSource (s));
return &sourceArray.getReference (sourceArray.size() - 1);
}
MouseInputSource* getMouseSource (int index) const noexcept
@ -618,21 +655,29 @@ struct MouseInputSource::SourceList : public Timer
: nullptr;
}
MouseInputSource* getOrCreateMouseInputSource (int touchIndex)
MouseInputSource* getOrCreateMouseInputSource (MouseInputSource::InputSourceType type, int touchIndex = 0)
{
jassert (touchIndex >= 0 && touchIndex < 100); // sanity-check on number of fingers
for (;;)
if (type == MouseInputSource::InputSourceType::mouse || type == MouseInputSource::InputSourceType::pen)
{
if (MouseInputSource* mouse = getMouseSource (touchIndex))
return mouse;
for (auto& m : sourceArray)
if (type == m.getType())
return &m;
if (! addSource())
{
jassertfalse; // not enough mouse sources!
return nullptr;
}
addSource (0, type);
}
else if (type == MouseInputSource::InputSourceType::touch)
{
jassert (touchIndex >= 0 && touchIndex < 100); // sanity-check on number of fingers
for (auto& m : sourceArray)
if (type == m.getType() && touchIndex == m.getIndex())
return &m;
if (canUseTouch())
return addSource (touchIndex, type);
}
return nullptr;
}
int getNumDraggingMouseSources() const noexcept

View file

@ -48,6 +48,14 @@
class JUCE_API MouseInputSource
{
public:
/** Possible mouse input sources */
enum InputSourceType
{
mouse,
touch,
pen
};
//==============================================================================
MouseInputSource (const MouseInputSource&) noexcept;
MouseInputSource& operator= (const MouseInputSource&) noexcept;
@ -58,10 +66,9 @@ public:
bool operator!= (const MouseInputSource& other) const noexcept { return pimpl != other.pimpl; }
//==============================================================================
/** Returns true if this object represents a normal desk-based mouse device. */
bool isMouse() const noexcept;
/** Returns the type of input source that this object represents */
MouseInputSource::InputSourceType getType() const noexcept;
/** Returns true if this object represents a source of touch events - i.e. a finger or stylus. */
bool isTouch() const noexcept;
/** Returns true if this source has an on-screen pointer that can hover over
@ -101,9 +108,35 @@ public:
*/
float getCurrentPressure() const noexcept;
/** Returns the device's current orientation in radians. 0 indicates a touch pointer
aligned with the x-axis and pointing from left to right; increasing values indicate
rotation in the clockwise direction. Only reported by a touch pointer.
*/
float getCurrentOrientation() const noexcept;
/** Returns the device's current rotation. Indicates the clockwise rotation, or twist, of the pointer
in radians. The default is 0. Only reported by a pen pointer.
*/
float getCurrentRotation() const noexcept;
/** Returns the angle of tilt of the pointer in a range of -1.0 to 1.0 either in the x- or y-axis. The default is 0.
If x-axis, a positive value indicates a tilt to the right and if y-axis, a positive value indicates a tilt toward the user.
Only reported by a pen pointer.
*/
float getCurrentTilt (bool tiltX) const noexcept;
/** Returns true if the current pressure value is meaningful. */
bool isPressureValid() const noexcept;
/** Returns true if the current orientation value is meaningful. */
bool isOrientationValid() const noexcept;
/** Returns true if the current rotation value is meaningful. */
bool isRotationValid() const noexcept;
/** Returns true if the current tilt value (either x- or y-axis) is meaningful. */
bool isTiltValid (bool tiltX) const noexcept;
/** Returns the component that was last known to be under this pointer. */
Component* getComponentUnderMouse() const;
@ -178,6 +211,16 @@ public:
*/
static const float invalidPressure;
/** A default value for orientation, which is used when a device doesn't support it */
static const float invalidOrientation;
/** A default value for rotation, which is used when a device doesn't support it */
static const float invalidRotation;
/** Default values for tilt, which are used when a device doesn't support it */
static const float invalidTiltX;
static const float invalidTiltY;
private:
//==============================================================================
friend class ComponentPeer;
@ -188,7 +231,7 @@ private:
struct SourceList;
explicit MouseInputSource (MouseInputSourceInternal*) noexcept;
void handleEvent (ComponentPeer&, Point<float>, int64 time, ModifierKeys, float);
void handleEvent (ComponentPeer&, Point<float>, int64 time, ModifierKeys, float, float, const PenDetails&);
void handleWheel (ComponentPeer&, Point<float>, int64 time, const MouseWheelDetails&);
void handleMagnifyGesture (ComponentPeer&, Point<float>, int64 time, float scaleFactor);

View file

@ -392,7 +392,8 @@ 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(), MouseInputSource::invalidPressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons(),
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index);
if (isValidPeer (this))
handleMouseDragCallback (index, sysPos, time);
@ -406,8 +407,8 @@ public:
jassert (index < 64);
touchesDown = (touchesDown | (1 << (index & 63)));
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier),
MouseInputSource::invalidPressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier),
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index);
}
void handleMouseUpCallback (int index, Point<float> pos, int64 time)
@ -421,7 +422,8 @@ public:
if (touchesDown == 0)
currentModifiers = currentModifiers.withoutMouseButtons();
handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, time, {}, index);
}
void handleKeyDownCallback (int k, int kc)
@ -682,7 +684,12 @@ Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
bool MouseInputSource::SourceList::addSource()
{
addSource (sources.size(), false);
addSource (sources.size(), MouseInputSource::InputSourceType::touch);
return true;
}
bool MouseInputSource::SourceList::canUseTouch()
{
return true;
}

View file

@ -846,8 +846,8 @@ 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(),
MouseInputSource::invalidPressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, modsToSend.withoutMouseButtons(),
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, touchIndex);
if (! isValidPeer (this)) // (in case this component was deleted by the event)
return;
@ -874,15 +874,16 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons
float pressure = maximumForce > 0 ? jlimit (0.0001f, 0.9999f, getTouchForce (touch) / maximumForce)
: MouseInputSource::invalidPressure;
handleMouseEvent (touchIndex, pos, modsToSend, pressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, modsToSend, pressure,
MouseInputSource::invalidOrientation, time, { }, touchIndex);
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, MouseInputSource::invalidPressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, Point<float> (-1.0f, -1.0f), modsToSend,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, touchIndex);
if (! isValidPeer (this))
return;

View file

@ -429,7 +429,12 @@ String SystemClipboard::getTextFromClipboard()
//==============================================================================
bool MouseInputSource::SourceList::addSource()
{
addSource (sources.size(), false);
addSource (sources.size(), MouseInputSource::InputSourceType::touch);
return true;
}
bool MouseInputSource::SourceList::canUseTouch()
{
return true;
}

View file

@ -2157,15 +2157,16 @@ public:
wheel.isSmooth = false;
wheel.isInertial = false;
handleMouseWheel (0, getMousePos (buttonPressEvent), getEventTime (buttonPressEvent), wheel);
handleMouseWheel (MouseInputSource::InputSourceType::mouse, getMousePos (buttonPressEvent),
getEventTime (buttonPressEvent), wheel);
}
void handleButtonPressEvent (const XButtonPressedEvent& buttonPressEvent, int buttonModifierFlag)
{
currentModifiers = currentModifiers.withFlags (buttonModifierFlag);
toFront (true);
handleMouseEvent (0, getMousePos (buttonPressEvent), currentModifiers,
MouseInputSource::invalidPressure, getEventTime (buttonPressEvent));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, getMousePos (buttonPressEvent), currentModifiers,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, getEventTime (buttonPressEvent), {});
}
void handleButtonPressEvent (const XButtonPressedEvent& buttonPressEvent)
@ -2203,8 +2204,8 @@ public:
if (dragState->dragging)
handleExternalDragButtonReleaseEvent();
handleMouseEvent (0, getMousePos (buttonRelEvent), currentModifiers,
MouseInputSource::invalidPressure, getEventTime (buttonRelEvent));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, getMousePos (buttonRelEvent), currentModifiers,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, getEventTime (buttonRelEvent));
clearLastMousePos();
}
@ -2218,8 +2219,8 @@ public:
if (dragState->dragging)
handleExternalDragMotionNotify();
handleMouseEvent (0, getMousePos (movedEvent), currentModifiers,
MouseInputSource::invalidPressure, getEventTime (movedEvent));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, getMousePos (movedEvent), currentModifiers,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, getEventTime (movedEvent));
}
void handleEnterNotifyEvent (const XEnterWindowEvent& enterEvent)
@ -2232,8 +2233,8 @@ public:
if (! currentModifiers.isAnyMouseButtonDown())
{
updateKeyModifiers ((int) enterEvent.state);
handleMouseEvent (0, getMousePos (enterEvent), currentModifiers,
MouseInputSource::invalidPressure, getEventTime (enterEvent));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, getMousePos (enterEvent), currentModifiers,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, getEventTime (enterEvent));
}
}
@ -2246,8 +2247,8 @@ public:
|| leaveEvent.mode == NotifyUngrab)
{
updateKeyModifiers ((int) leaveEvent.state);
handleMouseEvent (0, getMousePos (leaveEvent), currentModifiers,
MouseInputSource::invalidPressure, getEventTime (leaveEvent));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, getMousePos (leaveEvent), currentModifiers,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, getEventTime (leaveEvent));
}
}
@ -3782,13 +3783,18 @@ bool MouseInputSource::SourceList::addSource()
{
if (sources.size() == 0)
{
addSource (0, true);
addSource (0, MouseInputSource::InputSourceType::mouse);
return true;
}
return false;
}
bool MouseInputSource::SourceList::canUseTouch()
{
return false;
}
bool Desktop::canUseSemiTransparentWindows() noexcept
{
#if JUCE_USE_XRENDER

View file

@ -585,8 +585,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,
getMousePressure (ev), getMouseTime (ev));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, { -1.0f, -1.0f }, currentModifiers,
getMousePressure (ev), MouseInputSource::invalidOrientation, getMouseTime (ev));
showArrowCursorIfNeeded();
}
@ -658,7 +658,7 @@ public:
wheel.deltaY = scale * (float) [ev deltaY];
}
handleMouseWheel (0, getMousePos (ev, view), getMouseTime (ev), wheel);
handleMouseWheel (MouseInputSource::InputSourceType::mouse, getMousePos (ev, view), getMouseTime (ev), wheel);
}
void redirectMagnify (NSEvent* ev)
@ -667,7 +667,7 @@ public:
const float invScale = 1.0f - (float) [ev magnification];
if (invScale > 0.0f)
handleMagnifyGesture (0, getMousePos (ev, view), getMouseTime (ev), 1.0f / invScale);
handleMagnifyGesture (MouseInputSource::InputSourceType::mouse, getMousePos (ev, view), getMouseTime (ev), 1.0f / invScale);
#endif
ignoreUnused (ev);
}
@ -689,8 +689,8 @@ public:
void sendMouseEvent (NSEvent* ev)
{
updateModifiers (ev);
handleMouseEvent (0, getMousePos (ev, view), currentModifiers,
getMousePressure (ev), getMouseTime (ev));
handleMouseEvent (MouseInputSource::InputSourceType::mouse, getMousePos (ev, view), currentModifiers,
getMousePressure (ev), MouseInputSource::invalidOrientation, getMouseTime (ev));
}
bool handleKeyEvent (NSEvent* ev, bool isKeyDown)
@ -2046,13 +2046,18 @@ bool MouseInputSource::SourceList::addSource()
{
if (sources.size() == 0)
{
addSource (0, true);
addSource (0, MouseInputSource::InputSourceType::mouse);
return true;
}
return false;
}
bool MouseInputSource::SourceList::canUseTouch()
{
return false;
}
//==============================================================================
void Desktop::setKioskComponent (Component* kioskComp, bool shouldBeEnabled, bool allowMenusAndBars)
{

View file

@ -105,6 +105,26 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
#endif
#ifndef WM_NCPOINTERUPDATE
enum
{
WM_NCPOINTERUPDATE = 0x241,
WM_NCPOINTERDOWN = 0x242,
WM_NCPOINTERUP = 0x243,
WM_POINTERUPDATE = 0x245,
WM_POINTERDOWN = 0x246,
WM_POINTERUP = 0x247,
WM_POINTERENTER = 0x249,
WM_POINTERLEAVE = 0x24A,
WM_POINTERACTIVATE = 0x24B,
WM_POINTERCAPTURECHANGED = 0x24C,
WM_TOUCHHITTESTING = 0x24D,
WM_POINTERWHEEL = 0x24E,
WM_POINTERHWHEEL = 0x24F,
WM_POINTERHITTEST = 0x250
};
#endif
#ifndef MONITOR_DPI_TYPE
enum Monitor_DPI_Type
{
@ -1530,7 +1550,7 @@ private:
static bool isHWNDBlockedByModalComponents (HWND h)
{
for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
if (Component* const c = Desktop::getInstance().getComponent (i))
if (auto* c = Desktop::getInstance().getComponent (i))
if ((! c->isCurrentlyBlockedByAnotherModalComponent())
&& IsChild ((HWND) c->getWindowHandle(), h))
return false;
@ -1560,12 +1580,13 @@ private:
case WM_NCMOUSEHOVER:
case WM_MOUSEHOVER:
case WM_TOUCH:
#ifdef WM_POINTERUPDATE
case WM_POINTERUPDATE:
case WM_POINTERDOWN:
case WM_NCPOINTERUPDATE:
case WM_POINTERWHEEL:
case WM_POINTERHWHEEL:
case WM_POINTERUP:
#endif
return isHWNDBlockedByModalComponents (m.hwnd);
case WM_POINTERACTIVATE:
return isHWNDBlockedByModalComponents(m.hwnd);
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONDBLCLK:
case WM_NCRBUTTONDOWN:
@ -1580,9 +1601,11 @@ private:
case WM_RBUTTONDBLCLK:
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_NCPOINTERDOWN:
case WM_POINTERDOWN:
if (isHWNDBlockedByModalComponents (m.hwnd))
{
if (Component* const modal = Component::getCurrentlyModalComponent (0))
if (auto* modal = Component::getCurrentlyModalComponent (0))
modal->inputAttemptWhenModal();
return true;
@ -1955,9 +1978,9 @@ private:
}
//==============================================================================
void doMouseEvent (Point<float> position, float pressure)
void doMouseEvent (Point<float> position, float pressure, float orientation = 0.0f, ModifierKeys mods = currentModifiers)
{
handleMouseEvent (0, position, currentModifiers, pressure, getMouseEventTime());
handleMouseEvent (MouseInputSource::InputSourceType::mouse, position, mods, pressure, orientation, getMouseEventTime());
}
StringArray getAvailableRenderingEngines() override
@ -2018,10 +2041,22 @@ private:
return (GetMessageExtraInfo() & 0xFFFFFF80 /*SIGNATURE_MASK*/) == 0xFF515780 /*MI_WP_SIGNATURE*/;
}
static bool areOtherTouchSourcesActive()
{
for (auto& ms : Desktop::getInstance().getMouseSources())
if (ms.isDragging() && (ms.getType() == MouseInputSource::InputSourceType::touch
|| ms.getType() == MouseInputSource::InputSourceType::pen))
return true;
return false;
}
void doMouseMove (Point<float> position, bool isMouseDownEvent)
{
ModifierKeys modsToSend (currentModifiers);
// this will be handled by WM_TOUCH
if (isTouchEvent())
if (isTouchEvent() || areOtherTouchSourcesActive())
return;
if (! isMouseOver)
@ -2062,17 +2097,21 @@ private:
static int minTimeBetweenMouses = getMinTimeBetweenMouseMoves();
const uint32 now = Time::getMillisecondCounter();
if (! Desktop::getInstance().getMainMouseSource().isDragging())
modsToSend = modsToSend.withoutMouseButtons();
if (now >= lastMouseTime + minTimeBetweenMouses)
{
lastMouseTime = now;
doMouseEvent (position, MouseInputSource::invalidPressure);
doMouseEvent (position, MouseInputSource::invalidPressure,
MouseInputSource::invalidOrientation, modsToSend);
}
}
void doMouseDown (Point<float> position, const WPARAM wParam)
{
// this will be handled by WM_TOUCH
if (isTouchEvent())
if (isTouchEvent() || areOtherTouchSourcesActive())
return;
if (GetCapture() != hwnd)
@ -2098,7 +2137,7 @@ private:
void doMouseUp (Point<float> position, const WPARAM wParam)
{
// this will be handled by WM_TOUCH
if (isTouchEvent())
if (isTouchEvent() || areOtherTouchSourcesActive())
return;
updateModifiersFromWParam (wParam);
@ -2138,7 +2177,9 @@ private:
void doMouseExit()
{
isMouseOver = false;
doMouseEvent (getCurrentMousePos(), MouseInputSource::invalidPressure);
if (! areOtherTouchSourcesActive())
doMouseEvent (getCurrentMousePos(), MouseInputSource::invalidPressure);
}
ComponentPeer* findPeerUnderMouse (Point<float>& localPos)
@ -2157,6 +2198,19 @@ private:
return peer;
}
static MouseInputSource::InputSourceType getPointerType (WPARAM wParam)
{
#ifdef WM_POINTERWHEEL
POINTER_INPUT_TYPE pointerType;
if (GetPointerType (GET_POINTERID_WPARAM (wParam), &pointerType))
if (pointerType == 3)
return MouseInputSource::InputSourceType::pen;
#endif
return MouseInputSource::InputSourceType::mouse;
}
void doMouseWheel (const WPARAM wParam, const bool isVertical)
{
updateKeyModifiers();
@ -2170,8 +2224,8 @@ private:
wheel.isInertial = false;
Point<float> localPos;
if (ComponentPeer* const peer = findPeerUnderMouse (localPos))
peer->handleMouseWheel (0, localPos, getMouseEventTime(), wheel);
if (auto* peer = findPeerUnderMouse (localPos))
peer->handleMouseWheel (getPointerType (wParam), localPos, getMouseEventTime(), wheel);
}
bool doGestureEvent (LPARAM lParam)
@ -2191,7 +2245,7 @@ private:
{
case 3: /*GID_ZOOM*/
if (gi.dwFlags != 1 /*GF_BEGIN*/ && lastMagnifySize > 0)
peer->handleMagnifyGesture (0, localPos, getMouseEventTime(),
peer->handleMagnifyGesture (MouseInputSource::InputSourceType::touch, localPos, getMouseEventTime(),
(float) (gi.ullArguments / (double) lastMagnifySize));
lastMagnifySize = gi.ullArguments;
@ -2213,7 +2267,7 @@ private:
LRESULT doTouchEvent (const int numInputs, HTOUCHINPUT eventHandle)
{
if ((styleFlags & windowIgnoresMouseClicks) != 0)
if (HWNDComponentPeer* const parent = getOwnerOfWindow (GetParent (hwnd)))
if (auto* parent = getOwnerOfWindow (GetParent (hwnd)))
if (parent != this)
return parent->doTouchEvent (numInputs, eventHandle);
@ -2235,7 +2289,9 @@ private:
return 0;
}
bool handleTouchInput (const TOUCHINPUT& touch, const bool isDown, const bool isUp)
bool handleTouchInput (const TOUCHINPUT& touch, const bool isDown, const bool isUp,
const float touchPressure = MouseInputSource::invalidPressure,
const float orientation = 0.0f)
{
bool isCancel = false;
@ -2243,7 +2299,7 @@ private:
const int64 time = getMouseEventTime();
const Point<float> pos (globalToLocal (Point<float> (touch.x / 100.0f,
touch.y / 100.0f)));
const float pressure = MouseInputSource::invalidPressure;
const float pressure = touchPressure;
ModifierKeys modsToSend (currentModifiers);
if (isDown)
@ -2252,7 +2308,7 @@ private:
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(), pressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, modsToSend.withoutMouseButtons(), pressure, orientation, time, PenDetails(), touchIndex);
if (! isValidPeer (this)) // (in case this component was deleted by the event)
return false;
@ -2276,14 +2332,14 @@ private:
currentModifiers = currentModifiers.withoutMouseButtons();
}
handleMouseEvent (touchIndex, pos, modsToSend, pressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, modsToSend, pressure, orientation, time, PenDetails(), touchIndex);
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, pressure, time);
handleMouseEvent (MouseInputSource::InputSourceType::touch, Point<float> (-10.0f, -10.0f), currentModifiers, pressure, orientation, time, PenDetails(), touchIndex);
if (! isValidPeer (this))
return false;
@ -2293,6 +2349,47 @@ private:
}
#ifdef WM_POINTERUPDATE
bool handlePointerInput (WPARAM wParam, LPARAM lParam, const bool isDown, const bool isUp)
{
POINTER_INPUT_TYPE pointerType;
if (! GetPointerType (GET_POINTERID_WPARAM (wParam), &pointerType))
return false;
if (pointerType == 0x00000002) // PT_TOUCH
{
POINTER_TOUCH_INFO touchInfo;
if (! GetPointerTouchInfo (GET_POINTERID_WPARAM (wParam), &touchInfo))
return false;
const float pressure = touchInfo.touchMask & TOUCH_MASK_PRESSURE ? touchInfo.pressure : MouseInputSource::invalidPressure;
const float orientation = touchInfo.touchMask & TOUCH_MASK_ORIENTATION ? degreesToRadians (static_cast<float> (touchInfo.orientation))
: MouseInputSource::invalidOrientation;
if (! handleTouchInput (emulateTouchEventFromPointer (lParam, wParam),
isDown, isUp, pressure, orientation))
return false;
}
else if (pointerType == 0x00000003) // PT_PEN
{
POINTER_PEN_INFO penInfo;
if (! GetPointerPenInfo (GET_POINTERID_WPARAM (wParam), &penInfo))
return false;
const float pressure = (penInfo.penMask & PEN_MASK_PRESSURE) ? penInfo.pressure / 1024.0f : MouseInputSource::invalidPressure;
if (! handlePenInput (penInfo, globalToLocal (Point<float> (static_cast<float> (GET_X_LPARAM(lParam)),
static_cast<float> (GET_Y_LPARAM(lParam)))),
pressure, isDown, isUp))
return false;
}
else
{
return false;
}
return true;
}
TOUCHINPUT emulateTouchEventFromPointer (LPARAM lParam, WPARAM wParam)
{
TOUCHINPUT touchInput;
@ -2303,6 +2400,58 @@ private:
return touchInput;
}
bool handlePenInput (POINTER_PEN_INFO penInfo, Point<float> pos, const float pressure, bool isDown, bool isUp)
{
const int64 time = getMouseEventTime();
ModifierKeys modsToSend (currentModifiers);
PenDetails penDetails;
penDetails.rotation = (penInfo.penMask & PEN_MASK_ROTATION) ? degreesToRadians (static_cast<float> (penInfo.rotation)) : MouseInputSource::invalidRotation;
penDetails.tiltX = (penInfo.penMask & PEN_MASK_TILT_X) ? penInfo.tiltX / 90.0f : MouseInputSource::invalidTiltX;
penDetails.tiltY = (penInfo.penMask & PEN_MASK_TILT_Y) ? penInfo.tiltY / 90.0f : MouseInputSource::invalidTiltY;
auto pInfoFlags = penInfo.pointerInfo.pointerFlags;
if ((pInfoFlags & POINTER_FLAG_FIRSTBUTTON) != 0)
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
else if ((pInfoFlags & POINTER_FLAG_SECONDBUTTON) != 0)
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::rightButtonModifier);
if (isDown)
{
modsToSend = currentModifiers;
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
handleMouseEvent (MouseInputSource::InputSourceType::pen, pos, modsToSend.withoutMouseButtons(),
pressure, MouseInputSource::invalidOrientation, time, penDetails);
if (! isValidPeer (this)) // (in case this component was deleted by the event)
return false;
}
else if (isUp || ! (pInfoFlags & POINTER_FLAG_INCONTACT))
{
modsToSend = modsToSend.withoutMouseButtons();
}
handleMouseEvent (MouseInputSource::InputSourceType::pen, pos, modsToSend, pressure,
MouseInputSource::invalidOrientation, time, penDetails);
if (! isValidPeer (this)) // (in case this component was deleted by the event)
return false;
if (isUp)
{
handleMouseEvent (MouseInputSource::InputSourceType::pen, { -10.0f, -10.0f }, currentModifiers,
pressure, MouseInputSource::invalidOrientation, time, penDetails);
if (! isValidPeer (this))
return false;
}
return true;
}
#endif
//==============================================================================
@ -2583,7 +2732,8 @@ private:
if (contains (pos.roundToInt(), false))
{
doMouseEvent (pos, MouseInputSource::invalidPressure);
if (! areOtherTouchSourcesActive())
doMouseEvent (pos, MouseInputSource::invalidPressure);
if (! isValidPeer (this))
return true;
@ -2724,7 +2874,7 @@ private:
public:
static LRESULT CALLBACK windowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
{
if (HWNDComponentPeer* const peer = getOwnerOfWindow (h))
if (auto* peer = getOwnerOfWindow (h))
{
jassert (isValidPeer (peer));
return peer->peerWindowProc (h, message, wParam, lParam);
@ -2794,13 +2944,25 @@ private:
return 1;
//==============================================================================
#ifdef WM_POINTERUPDATE
case WM_POINTERUPDATE: handleTouchInput (emulateTouchEventFromPointer (lParam, wParam), false, false); return 0;
case WM_POINTERDOWN: handleTouchInput (emulateTouchEventFromPointer (lParam, wParam), true, false); return 0;
case WM_POINTERUP: handleTouchInput (emulateTouchEventFromPointer (lParam, wParam), false, true); return 0;
#endif
case WM_POINTERUPDATE:
if (handlePointerInput (wParam, lParam, false, false))
return 0;
break;
case WM_POINTERDOWN:
if (handlePointerInput (wParam, lParam, true, false))
return 0;
break;
case WM_POINTERUP:
if (handlePointerInput (wParam, lParam, false, true))
return 0;
break;
//==============================================================================
case WM_MOUSEMOVE: doMouseMove (getPointFromLParam (lParam), false); return 0;
case WM_POINTERLEAVE:
case WM_MOUSELEAVE: doMouseExit(); return 0;
case WM_LBUTTONDOWN:
@ -2811,11 +2973,15 @@ private:
case WM_MBUTTONUP:
case WM_RBUTTONUP: doMouseUp (getPointFromLParam (lParam), wParam); return 0;
case WM_POINTERWHEEL:
case 0x020A: /* WM_MOUSEWHEEL */ doMouseWheel (wParam, true); return 0;
case WM_POINTERHWHEEL:
case 0x020E: /* WM_MOUSEHWHEEL */ doMouseWheel (wParam, false); return 0;
case WM_CAPTURECHANGED: doCaptureChanged(); return 0;
case WM_NCPOINTERUPDATE:
case WM_NCMOUSEMOVE:
if (hasTitleBar())
break;
@ -2928,6 +3094,7 @@ private:
break;
case WM_POINTERACTIVATE:
case WM_MOUSEACTIVATE:
if (! component.getMouseClickGrabsKeyboardFocus())
return MA_NOACTIVATE;
@ -3054,6 +3221,7 @@ private:
break;
case WM_NCPOINTERDOWN:
case WM_NCLBUTTONDOWN:
handleLeftClickInNCArea (wParam);
break;
@ -3571,13 +3739,19 @@ bool MouseInputSource::SourceList::addSource()
if (numSources == 0 || canUseMultiTouch())
{
addSource (numSources, numSources == 0);
addSource (numSources, numSources == 0 ? MouseInputSource::InputSourceType::mouse
: MouseInputSource::InputSourceType::touch);
return true;
}
return false;
}
bool MouseInputSource::SourceList::canUseTouch()
{
return canUseMultiTouch();
}
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
POINT mousePos;

View file

@ -1044,13 +1044,11 @@ public:
void restoreMouseIfHidden()
{
const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources();
for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi)
for (auto& ms : Desktop::getInstance().getMouseSources())
{
if (mi->isUnboundedMouseMovementEnabled())
if (ms.isUnboundedMouseMovementEnabled())
{
mi->enableUnboundedMouseMovement (false);
ms.enableUnboundedMouseMovement (false);
const double pos = sliderBeingDragged == 2 ? getMaxValue()
: (sliderBeingDragged == 1 ? getMinValue()
@ -1059,7 +1057,7 @@ public:
if (isRotary())
{
mousePos = mi->getLastMouseDownPosition();
mousePos = ms.getLastMouseDownPosition();
const float delta = (float) (pixelsForFullDragExtent * (owner.valueToProportionOfLength (valueOnMouseDown)
- owner.valueToProportionOfLength (pos)));
@ -1080,7 +1078,7 @@ public:
isVertical() ? pixelPos : (owner.getHeight() / 2.0f)));
}
mi->setScreenPosition (mousePos);
ms.setScreenPosition (mousePos);
}
}
}

View file

@ -85,21 +85,22 @@ bool ComponentPeer::isKioskMode() const
}
//==============================================================================
void ComponentPeer::handleMouseEvent (int touchIndex, Point<float> pos, ModifierKeys newMods, float newPressure, int64 time)
void ComponentPeer::handleMouseEvent (MouseInputSource::InputSourceType type, Point<float> pos, ModifierKeys newMods,
float newPressure, float newOrientation, int64 time, PenDetails pen, int touchIndex)
{
if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex))
MouseInputSource (*mouse).handleEvent (*this, pos, time, newMods, newPressure);
if (auto* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (type, touchIndex))
MouseInputSource (*mouse).handleEvent (*this, pos, time, newMods, newPressure, newOrientation, pen);
}
void ComponentPeer::handleMouseWheel (int touchIndex, Point<float> pos, int64 time, const MouseWheelDetails& wheel)
void ComponentPeer::handleMouseWheel (MouseInputSource::InputSourceType type, Point<float> pos, int64 time, const MouseWheelDetails& wheel, int touchIndex)
{
if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex))
if (auto* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (type, touchIndex))
MouseInputSource (*mouse).handleWheel (*this, pos, time, wheel);
}
void ComponentPeer::handleMagnifyGesture (int touchIndex, Point<float> pos, int64 time, float scaleFactor)
void ComponentPeer::handleMagnifyGesture (MouseInputSource::InputSourceType type, Point<float> pos, int64 time, float scaleFactor, int touchIndex)
{
if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex))
if (auto* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (type, touchIndex))
MouseInputSource (*mouse).handleMagnifyGesture (*this, pos, time, scaleFactor);
}
@ -113,7 +114,7 @@ void ComponentPeer::handlePaint (LowLevelGraphicsContext& contextToPaintTo)
if (component.isTransformed())
g.addTransform (component.getTransform());
const Rectangle<int> peerBounds (getBounds());
auto peerBounds = getBounds();
if (peerBounds.getWidth() != component.getWidth() || peerBounds.getHeight() != component.getHeight())
// Tweak the scaling so that the component's integer size exactly aligns with the peer's scaled size

View file

@ -310,9 +310,14 @@ public:
virtual void setAlpha (float newAlpha) = 0;
//==============================================================================
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);
void handleMouseEvent (MouseInputSource::InputSourceType type, Point<float> positionWithinPeer, ModifierKeys newMods, float pressure,
float orientation, int64 time, PenDetails pen = {}, int touchIndex = 0);
void handleMouseWheel (MouseInputSource::InputSourceType type, Point<float> positionWithinPeer,
int64 time, const MouseWheelDetails&, int touchIndex = 0);
void handleMagnifyGesture (MouseInputSource::InputSourceType type, Point<float> positionWithinPeer,
int64 time, float scaleFactor, int touchIndex = 0);
void handleUserClosingWindow();

View file

@ -130,7 +130,7 @@ void TooltipWindow::timerCallback()
const MouseInputSource mouseSource (desktop.getMainMouseSource());
const unsigned int now = Time::getApproximateMillisecondCounter();
Component* const newComp = mouseSource.isMouse() ? mouseSource.getComponentUnderMouse() : nullptr;
Component* const newComp = ! mouseSource.isTouch() ? mouseSource.getComponentUnderMouse() : nullptr;
const String newTip (getTipFor (newComp));
const bool tipChanged = (newTip != lastTipUnderMouse || newComp != lastComponentUnderMouse);
lastComponentUnderMouse = newComp;

View file

@ -92,41 +92,44 @@ public:
if (owner.isCurrentlyBlockedByAnotherModalComponent())
{
if (isLeft || isRight)
if (Component* const current = Component::getCurrentlyModalComponent())
if (auto* current = Component::getCurrentlyModalComponent())
current->inputAttemptWhenModal();
}
else
{
ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
auto eventMods = ModifierKeys::getCurrentModifiersRealtime();
if (([e modifierFlags] & NSEventModifierFlagCommand) != 0)
eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
const Time now (Time::getCurrentTime());
auto now = Time::getCurrentTime();
MouseInputSource mouseSource = Desktop::getInstance().getMainMouseSource();
const float pressure = (float) e.pressure;
auto pressure = (float) e.pressure;
if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up
{
setHighlighted (true);
startTimer (150);
owner.mouseDown (MouseEvent (mouseSource, Point<float>(),
owner.mouseDown (MouseEvent (mouseSource, {},
eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
: ModifierKeys::rightButtonModifier),
pressure, &owner, &owner, now,
Point<float>(), now, 1, false));
pressure, MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
&owner, &owner, now, {}, now, 1, false));
owner.mouseUp (MouseEvent (mouseSource, Point<float>(), eventMods.withoutMouseButtons(),
pressure, &owner, &owner, now,
Point<float>(), now, 1, false));
owner.mouseUp (MouseEvent (mouseSource, {}, eventMods.withoutMouseButtons(), pressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
&owner, &owner, now, {}, now, 1, false));
}
else if (type == NSEventTypeMouseMoved)
{
owner.mouseMove (MouseEvent (mouseSource, Point<float>(), eventMods,
pressure, &owner, &owner, now,
Point<float>(), now, 1, false));
owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure,
MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
&owner, &owner, now, {}, now, 1, false));
}
}
}
@ -195,7 +198,7 @@ private:
private:
static void handleEventDown (id self, SEL, NSEvent* e)
{
if (Pimpl* const owner = getOwner (self))
if (auto* owner = getOwner (self))
owner->handleStatusItemAction (e);
}
@ -203,7 +206,7 @@ private:
{
NSRect bounds = [self bounds];
if (Pimpl* const owner = getOwner (self))
if (auto* owner = getOwner (self))
[owner->statusItem drawStatusBarBackgroundInRect: bounds
withHighlight: owner->isHighlighted];

View file

@ -204,10 +204,11 @@ namespace ActiveXHelpers
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
peer->handleMouseEvent (0, Point<int> (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left,
GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top).toFloat(),
peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse,
{ (float) (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left),
(float) (GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top) },
ModifierKeys::getCurrentModifiersRealtime(),
MouseInputSource::invalidPressure,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation,
getMouseEventTime());
break;

View file

@ -93,7 +93,7 @@ public:
if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
|| lParam == WM_LBUTTONDBLCLK || lParam == WM_RBUTTONDBLCLK)
{
if (Component* const current = Component::getCurrentlyModalComponent())
if (auto* current = Component::getCurrentlyModalComponent())
current->inputAttemptWhenModal();
}
}
@ -110,9 +110,10 @@ public:
const Time eventTime (getMouseEventTime());
const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
Point<float>(), eventMods, MouseInputSource::invalidPressure,
&owner, &owner, eventTime, Point<float>(), eventTime, 1, false);
const MouseEvent e (Desktop::getInstance().getMainMouseSource(), {}, eventMods,
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation,
MouseInputSource::invalidRotation, MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
&owner, &owner, eventTime, {}, eventTime, 1, false);
if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
{