40 bool isDragging()
const noexcept
45 Component* getComponentUnderMouse()
const noexcept
47 return componentUnderMouse.get();
70 auto relativePos = SH::unscaledScreenPosToScaled (peer->
getComponent(),
75 if (comp.contains (relativePos))
85 return SH::unscaledScreenPosToScaled (getRawScreenPosition());
90 return unboundedMouseOffset + (inputType != MouseInputSource::InputSourceType::touch ? MouseInputSource::getCurrentRawMousePosition()
91 : lastPointerState.position);
96 MouseInputSource::setRawMousePosition (SH::scaledScreenPosToUnscaled (p));
100 #if JUCE_DUMP_MOUSE_EVENTS
101 #define JUCE_MOUSE_EVENT_DBG(desc, screenPos) DBG ("Mouse " << desc << " #" << index \
102 << ": " << SH::screenPosToLocalPos (comp, screenPos).toString() \
103 << " - Comp: " << String::toHexString ((pointer_sized_int) &comp));
105 #define JUCE_MOUSE_EVENT_DBG(desc, screenPos)
110 JUCE_MOUSE_EVENT_DBG (
"enter", pointerState.position)
112 SH::screenPosToLocalPos (comp, pointerState.position),
118 JUCE_MOUSE_EVENT_DBG (
"exit", pointerState.position)
120 SH::screenPosToLocalPos (comp, pointerState.position),
126 JUCE_MOUSE_EVENT_DBG (
"move", pointerState.position)
128 SH::screenPosToLocalPos (comp, pointerState.position),
134 JUCE_MOUSE_EVENT_DBG (
"down", pointerState.position)
136 pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)),
142 JUCE_MOUSE_EVENT_DBG (
"drag", pointerState.position)
144 pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)),
150 JUCE_MOUSE_EVENT_DBG (
"up", pointerState.position)
152 pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)),
159 JUCE_MOUSE_EVENT_DBG (
"wheel", screenPos)
161 SH::screenPosToLocalPos (comp, screenPos),
168 JUCE_MOUSE_EVENT_DBG (
"magnify", screenPos)
170 SH::screenPosToLocalPos (comp, screenPos),
175 #undef JUCE_MOUSE_EVENT_DBG
181 if (buttonState == newButtonState)
186 setPointerState (pointerState,
time,
false);
191 buttonState = newButtonState;
195 auto lastCounter = mouseEventCounter;
199 if (
auto* current = getComponentUnderMouse())
201 auto oldMods = getCurrentModifiers();
202 buttonState = newButtonState;
204 sendMouseUp (*current, pointerState.withPositionOffset (unboundedMouseOffset),
time, oldMods);
206 if (lastCounter != mouseEventCounter)
210 enableUnboundedMouseMovement (
false,
false);
213 buttonState = newButtonState;
219 if (
auto* current = getComponentUnderMouse())
221 registerMouseDown (pointerState.position,
time, *current, buttonState,
222 inputType == MouseInputSource::InputSourceType::touch);
223 sendMouseDown (*current, pointerState,
time);
227 return lastCounter != mouseEventCounter;
232 auto* current = getComponentUnderMouse();
234 if (newComponent != current)
237 auto originalButtonState = buttonState;
239 if (current !=
nullptr)
244 if (
auto oldComp = safeOldComp.
get())
246 componentUnderMouse = safeNewComp;
247 sendMouseExit (*oldComp, pointerState,
time);
250 buttonState = originalButtonState;
253 componentUnderMouse = safeNewComp.
get();
254 current = safeNewComp.
get();
256 if (current !=
nullptr)
257 sendMouseEnter (*current, pointerState,
time);
259 revealCursor (
false);
260 setButtons (pointerState,
time, originalButtonState);
266 if (&newPeer != lastPeer && ( findComponentAt (pointerState.position, &newPeer) !=
nullptr
267 || findComponentAt (pointerState.position, lastPeer) ==
nullptr))
269 setComponentUnderMouse (
nullptr, pointerState,
time);
271 setComponentUnderMouse (findComponentAt (pointerState.position, getPeer()), pointerState,
time);
277 const auto& newScreenPos = newPointerState.position;
280 setComponentUnderMouse (findComponentAt (newScreenPos, getPeer()), newPointerState,
time);
282 if ((newPointerState != lastPointerState) || forceUpdate)
286 lastPointerState = newPointerState;
288 if (
auto* current = getComponentUnderMouse())
292 registerMouseDrag (newScreenPos);
293 sendMouseDrag (*current, newPointerState.withPositionOffset (unboundedMouseOffset),
time);
295 if (isUnboundedMouseModeOn)
296 handleUnboundedDrag (*current);
300 sendMouseMove (*current, newPointerState,
time);
304 revealCursor (
false);
315 .withPressure (newPressure)
316 .withOrientation (newOrientation)
318 .withTiltX (pen.
tiltX)
319 .withTiltY (pen.
tiltY);
323 setPointerState (pointerState,
time,
false);
327 setPeer (newPeer, pointerState,
time);
329 if (
auto* peer = getPeer())
331 if (setButtons (pointerState,
time, newMods))
337 setPointerState (pointerState,
time,
false);
349 const auto pointerState = lastPointerState.withPosition (screenPos);
350 setPeer (peer, pointerState,
time);
351 setPointerState (pointerState,
time,
false);
354 return getComponentUnderMouse();
367 if (lastNonInertialWheelTarget ==
nullptr || ! wheel.
isInertial)
368 lastNonInertialWheelTarget = getTargetForGesture (peer, positionWithinPeer,
time, screenPos);
372 if (
auto target = lastNonInertialWheelTarget.get())
373 sendMouseWheel (*target, screenPos,
time, wheel);
381 if (
auto* current = getTargetForGesture (peer, positionWithinPeer,
time, screenPos))
382 sendMagnifyGesture (*current, screenPos,
time, scaleFactor);
386 Time getLastMouseDownTime()
const noexcept
388 return mouseDowns[0].time;
393 return SH::unscaledScreenPosToScaled (mouseDowns[0].position);
396 int getNumberOfMultipleClicks()
const noexcept
400 if (! isLongPressOrDrag())
414 bool isLongPressOrDrag()
const noexcept
416 return movedSignificantly ||
420 bool hasMovedSignificantlySincePressed()
const noexcept
422 return movedSignificantly;
426 bool hasMouseMovedSignificantlySincePressed()
const noexcept
428 return isLongPressOrDrag();
432 void triggerFakeMove()
439 setPointerState (lastPointerState,
444 void enableUnboundedMouseMovement (
bool enable,
bool keepCursorVisibleUntilOffscreen)
446 enable = enable && isDragging();
447 isCursorVisibleUntilOffscreen = keepCursorVisibleUntilOffscreen;
449 if (enable != isUnboundedMouseModeOn)
451 if ((! enable) && ((! isCursorVisibleUntilOffscreen) || ! unboundedMouseOffset.
isOrigin()))
454 if (
auto* current = getComponentUnderMouse())
455 setScreenPosition (current->getScreenBounds().toFloat()
456 .getConstrainedPoint (SH::unscaledScreenPosToScaled (lastPointerState.position)));
459 isUnboundedMouseModeOn = enable;
460 unboundedMouseOffset = {};
466 void handleUnboundedDrag (Component& current)
468 auto componentScreenBounds = SH::scaledScreenPosToUnscaled (current.getParentMonitorArea()
472 if (! componentScreenBounds.contains (lastPointerState.position))
474 auto componentCentre = current.getScreenBounds().toFloat().getCentre();
475 unboundedMouseOffset += (lastPointerState.position - SH::scaledScreenPosToUnscaled (componentCentre));
476 setScreenPosition (componentCentre);
478 else if (isCursorVisibleUntilOffscreen
479 && (! unboundedMouseOffset.
isOrigin())
480 && componentScreenBounds.contains (lastPointerState.position + unboundedMouseOffset))
482 MouseInputSource::setRawMousePosition (lastPointerState.position + unboundedMouseOffset);
483 unboundedMouseOffset = {};
488 void showMouseCursor (MouseCursor cursor,
bool forcedUpdate)
490 if (isUnboundedMouseModeOn && ((! unboundedMouseOffset.
isOrigin()) || ! isCursorVisibleUntilOffscreen))
496 if (forcedUpdate || cursor.getHandle() != currentCursorHandle)
498 currentCursorHandle = cursor.getHandle();
499 cursor.showInWindow (getPeer());
508 void revealCursor (
bool forcedUpdate)
512 if (
auto* current = getComponentUnderMouse())
513 mc = current->getLookAndFeel().getMouseCursorFor (*current);
515 showMouseCursor (mc, forcedUpdate);
521 Point<float> unboundedMouseOffset;
522 detail::PointerState lastPointerState;
523 ModifierKeys buttonState;
525 bool isUnboundedMouseModeOn =
false, isCursorVisibleUntilOffscreen =
false;
528 WeakReference<Component> componentUnderMouse, lastNonInertialWheelTarget;
529 ComponentPeer* lastPeer =
nullptr;
531 void* currentCursorHandle =
nullptr;
532 int mouseEventCounter = 0;
534 struct RecentMouseDown
536 RecentMouseDown() =
default;
538 Point<float> position;
540 ModifierKeys buttons;
542 bool isTouch =
false;
544 bool canBePartOfMultipleClickWith (
const RecentMouseDown& other,
int maxTimeBetweenMs)
const noexcept
547 && std::abs (position.x - other.position.x) < (
float) getPositionToleranceForInputType()
548 && std::abs (position.y - other.position.y) < (
float) getPositionToleranceForInputType()
549 && buttons == other.buttons
550 && peerID == other.peerID;
553 int getPositionToleranceForInputType() const noexcept {
return isTouch ? 25 : 8; }
556 RecentMouseDown mouseDowns[4];
558 bool movedSignificantly =
false;
560 void registerMouseDown (Point<float> screenPos, Time time, Component& component,
561 const ModifierKeys modifiers,
bool isTouchSource)
noexcept
564 mouseDowns[i] = mouseDowns[i - 1];
566 mouseDowns[0].position = screenPos;
567 mouseDowns[0].time =
time;
568 mouseDowns[0].buttons = modifiers.withOnlyMouseButtons();
569 mouseDowns[0].isTouch = isTouchSource;
571 if (
auto* peer = component.getPeer())
574 mouseDowns[0].peerID = 0;
576 movedSignificantly =
false;
577 lastNonInertialWheelTarget =
nullptr;
580 void registerMouseDrag (Point<float> screenPos)
noexcept
582 movedSignificantly = movedSignificantly || mouseDowns[0].position.getDistanceFrom (screenPos) >= 4;