Пример #1
0
        /// <summary>Fires an event into the scene of the camera.</summary>
        internal void FireIntoScene(UIEvent e)
        {
            if (e == null)
            {
                return;
            }

            // Get coords relative to the element. These are non-standard convenience properties:
            float localX = e.localX;
            float localY = e.localY;

            // Flip Y because Unity is upside down relative to input coords:
            localY = ScreenInfo.ScreenY - 1 - localY;

            // Fire off an input event at that point:
            RaycastHit worldUIHit;

            if (Physics.Raycast(Camera.ScreenPointToRay(new Vector2(localX, localY)), out worldUIHit))
            {
                // Did it hit a worldUI?
                WorldUI worldUI = WorldUI.Find(worldUIHit);

                if (worldUI == null)
                {
                    // Nope!
                    return;
                }

                // Resolve the hit into a -0.5 to +0.5 point:
                float x;
                float y;
                worldUI.ResolvePoint(worldUIHit, out x, out y);

                // Map it from a relative point to a 'real' one:
                Vector2 point = worldUI.RelativePoint(x, y);

                // Apply to x/y:
                x = point.x;
                y = point.y;

                // Pull an element from that worldUI:
                Element el = worldUI.document.elementFromPointOnScreen(x, y);

                if (el != null)
                {
                    // Fire the event for that element:
                    el.dispatchEvent(e);
                }
            }
        }
Пример #2
0
        /// <summary>Updates mouse overs, touches and the mouse position.</summary>
        public static void Update()
        {
            InputPointer pointer;

            // Look out for any 'new' touch events:
            int touchCount = UnityEngine.Input.touchCount;

            if (touchCount > 0)
            {
                Debug.Log("HiInput TouchCount: " + touchCount.ToString());

                // For each one..
                for (int i = 0; i < touchCount; i++)
                {
                    // Get the info:
                    Touch touch = UnityEngine.Input.GetTouch(i);

                    pointer = null;

                    // Already seen this one?
                    // There won't be many touches so a straight linear scan is by far the fastest option here.
                    // (It's much better than a dictionary).
                    for (int p = InputPointer.PointerCount - 1; p >= 0; p--)
                    {
                        // Get the pointer:
                        pointer = InputPointer.AllRaw[p];

                        if (pointer.ID == touch.fingerId)
                        {
                            // Got it!
                            break;
                        }
                    }

                    TouchPointer tp = null;

                    if (pointer == null)
                    {
                        // Touch start! A new finger has been seen for the first time.
                                                #if UNITY_5_3_OR_NEWER
                        // Could be a stylus:
                        if (touch.type == TouchType.Stylus)
                        {
                            tp = new StylusPointer();
                        }
                        else
                        {
                            tp = new FingerPointer();
                        }
                                                #else
                        // Can only assume it's a finger here:
                        tp = new FingerPointer();
                                                #endif

                        // Add it to the available set:
                        tp.Add();
                    }
                    else
                    {
                        // Apply latest info:
                        tp = (pointer as TouchPointer);
                    }

                    // Mark it as still alive so it doesn't get removed shortly.
                    tp.StillAlive     = true;
                    tp.LatestPosition = touch.position;

                                        #if UNITY_5_3_OR_NEWER
                    tp.LatestPressure = touch.pressure;
                    tp.Radius         = touch.radius;
                    tp.RadiusVariance = touch.radiusVariance;

                    // Is it a stylus?
                    if (tp is StylusPointer)
                    {
                        tp.UpdateStylus(touch.azimuthAngle, touch.altitudeAngle);
                    }

                    // Always a pressure of 1 otherwise (which is set by default).
                                        #endif
                }
            }

            // Update each pointer, invalidating itself only if it has moved:
            bool pointerRemoved = false;

            for (int i = InputPointer.PointerCount - 1; i >= 0; i--)
            {
                // Get the pointer:
                pointer = InputPointer.AllRaw[i];

                // Update its position and state now:
                Vector2 delta;
                bool    moved = pointer.Relocate(out delta);

                if (pointer.Removed)
                {
                    // It got removed! (E.g. a finger left the screen).
                    pointerRemoved = true;
                    continue;
                }

                // If the pointer is invalid or they all are:
                if (moved || PointersInvalid)
                {
                    // Figure out what's under it. This takes its pos on the screen
                    // and figures out what's there, as well as converting the position
                    // to one which is relative to the document (used by e.g. a WorldUI).
                    float   documentX     = pointer.ScreenX;
                    float   documentY     = pointer.ScreenY;
                    Element newActiveOver = ElementFromPoint(ref documentX, ref documentY, pointer);

                    // Update docX/Y:
                    pointer.DocumentX = documentX;
                    pointer.DocumentY = documentY;

                    // Get the old one:
                    Element oldActiveOver = pointer.ActiveOver;

                    // Shared event:
                    MouseEvent mouseEvent = new MouseEvent(documentX, documentY, pointer.ButtonID, pointer.IsDown);
                    mouseEvent.trigger = pointer;
                    mouseEvent.clientX = pointer.DocumentX;
                    mouseEvent.clientY = pointer.DocumentY;
                    mouseEvent.SetModifiers();
                    mouseEvent.SetTrusted();

                    // If overElement has changed from the previous one..
                    if (newActiveOver != oldActiveOver)
                    {
                        if (oldActiveOver != null)
                        {
                            // Trigger a mouseout (bubbles):
                            mouseEvent.EventType = "mouseout";
                            mouseEvent.SetTrusted();
                            mouseEvent.relatedTarget = newActiveOver;
                            oldActiveOver.dispatchEvent(mouseEvent);

                            // And a mouseleave (doesn't bubble).
                            // Only triggered if newActiveOver is *not* the parent of oldActiveOver.
                            if (oldActiveOver.parentNode_ != newActiveOver)
                            {
                                mouseEvent.Reset();
                                mouseEvent.bubbles       = false;
                                mouseEvent.EventType     = "mouseleave";
                                mouseEvent.relatedTarget = newActiveOver;
                                oldActiveOver.dispatchEvent(mouseEvent);
                            }
                        }

                        // Update it:
                        pointer.ActiveOver = newActiveOver;

                        if (oldActiveOver != null)
                        {
                            // Update the CSS (hover; typically out):
                            (oldActiveOver as IRenderableNode).ComputedStyle.RefreshLocal(true);
                        }

                        if (newActiveOver != null)
                        {
                            // Update the CSS (hover; typically in)
                            (newActiveOver as IRenderableNode).ComputedStyle.RefreshLocal(true);
                        }

                        // Trigger a mouseover (bubbles):
                        mouseEvent.Reset();
                        mouseEvent.bubbles       = true;
                        mouseEvent.relatedTarget = oldActiveOver;
                        mouseEvent.EventType     = "mouseover";

                        if (newActiveOver == null)
                        {
                            // Clear the main UI tooltip:
                            UI.document.tooltip = null;

                            // Dispatch to unhandled:
                            Unhandled.dispatchEvent(mouseEvent);
                        }
                        else
                        {
                            newActiveOver.dispatchEvent(mouseEvent);

                            // Set the tooltip if we've got one:
                            UI.document.tooltip = newActiveOver["title"];

                            // And a mouseenter (doesn't bubble).
                            // Only triggered if newActiveOver is *not* a child of oldActiveOver.
                            if (newActiveOver.parentNode_ != oldActiveOver)
                            {
                                mouseEvent.Reset();
                                mouseEvent.bubbles       = false;
                                mouseEvent.EventType     = "mouseenter";
                                mouseEvent.relatedTarget = oldActiveOver;
                                newActiveOver.dispatchEvent(mouseEvent);
                            }
                        }
                    }

                    if (moved)
                    {
                        // Trigger a mousemove event:
                        mouseEvent.Reset();
                        mouseEvent.bubbles   = true;
                        mouseEvent.EventType = "mousemove";

                        if (newActiveOver == null)
                        {
                            Unhandled.dispatchEvent(mouseEvent);
                        }
                        else
                        {
                            newActiveOver.dispatchEvent(mouseEvent);
                        }
                    }
                }

                // If the pointer requires pressure changes..
                if (pointer.FireTouchEvents)
                {
                    // Set the pressure (which triggers mousedown/up for us too):
                    TouchPointer tp = (pointer as TouchPointer);

                    if (tp.LatestPressure != tp.Pressure)
                    {
                        tp.SetPressure(tp.LatestPressure);
                    }

                    // We test touch move down here because it must happen after we've
                    // transferred 'ActiveOver' to 'ActiveDown' which happens inside SetPressure.

                    // Touch events are triggered on the element that was pressed down on
                    // (even if we've moved beyond it's bounds).
                    if (moved)
                    {
                        // Trigger a touchmove event too:
                        TouchEvent te = new TouchEvent("touchmove");
                        te.trigger = pointer;
                        te.SetTrusted();
                        te.clientX = pointer.DocumentX;
                        te.clientY = pointer.DocumentY;
                        te.SetModifiers();


                        if (pointer.ActivePressed == null)
                        {
                            // Trigger on unhandled:
                            Unhandled.dispatchEvent(te);
                        }
                        else
                        {
                            pointer.ActivePressed.dispatchEvent(te);
                        }
                    }
                }

                // Test for dragstart
                if (pointer.IsDown && moved)
                {
                    // How far has it moved since it went down?
                    if (pointer.DragStatus == InputPointer.DRAG_UNKNOWN)
                    {
                        // Is the element we pressed (or any of its parents) draggable?
                        if (pointer.MinDragDistance == 0f)
                        {
                            // Find if we've got a draggable element:
                            pointer.ActiveUpdating = GetDraggable(pointer.ActivePressed);

                            // Find the min drag distance:
                            pointer.MinDragDistance = pointer.GetMinDragDistance();
                        }

                        if (pointer.MovedBeyondDragDistance)
                        {
                            // Possibly dragging.

                            // Actually marked as 'draggable'?
                            if (pointer.ActiveUpdating != null)
                            {
                                // Try start drag:
                                DragEvent de = new DragEvent("dragstart");
                                de.trigger = pointer;
                                de.SetModifiers();
                                de.SetTrusted();
                                de.deltaX  = delta.x;
                                de.deltaY  = delta.y;
                                de.clientX = pointer.DocumentX;
                                de.clientY = pointer.DocumentY;

                                if (pointer.ActivePressed.dispatchEvent(de))
                                {
                                    // We're now dragging!
                                    pointer.DragStatus = InputPointer.DRAGGING;
                                }
                                else
                                {
                                    // It didn't allow it. This status prevents it from spamming dragstart.
                                    pointer.DragStatus = InputPointer.DRAG_NOT_AVAILABLE;
                                }
                            }
                            else
                            {
                                // Selectable?
                                ComputedStyle cs         = (pointer.ActivePressed as IRenderableNode).ComputedStyle;
                                Css.Value     userSelect = cs[Css.Properties.UserSelect.GlobalProperty];

                                if (userSelect != null && !(userSelect.IsType(typeof(Css.Keywords.None))) && !userSelect.IsAuto)
                                {
                                    // Selectable!
                                    Css.Properties.UserSelect.BeginSelect(pointer, userSelect);

                                    // Set status:
                                    pointer.DragStatus = InputPointer.SELECTING;

                                    // Focus it if needed:
                                    HtmlElement html = (pointer.ActivePressed as HtmlElement);

                                    if (html != null)
                                    {
                                        html.focus();
                                    }
                                }
                                else
                                {
                                    // This status prevents it from spamming, at least until we release.
                                    pointer.DragStatus = InputPointer.DRAG_NOT_AVAILABLE;
                                }
                            }
                        }
                    }
                    else if (pointer.DragStatus == InputPointer.DRAGGING)
                    {
                        // Move the dragged element (the event goes to everybody):
                        if (pointer.ActivePressed != null)
                        {
                            DragEvent de = new DragEvent("drag");
                            de.trigger = pointer;
                            de.SetModifiers();
                            de.SetTrusted();
                            de.deltaX  = delta.x;
                            de.deltaY  = delta.y;
                            de.clientX = pointer.DocumentX;
                            de.clientY = pointer.DocumentY;

                            if (pointer.ActivePressed.dispatchEvent(de))
                            {
                                // Note that onDrag runs on the *dragging* element only.
                                Element dragging = (pointer.ActiveUpdating == null)? pointer.ActivePressed : pointer.ActiveUpdating;

                                if (dragging.OnDrag(de))
                                {
                                    // Run the PowerUI default - move the element:
                                    RenderableData renderData = (dragging as IRenderableNode).RenderData;

                                    // Get the "actual" left/top values:
                                    if (renderData.FirstBox != null)
                                    {
                                        // Get computed style:
                                        ComputedStyle cs = renderData.computedStyle;

                                        // Fix if it isn't already:
                                        if (renderData.FirstBox.PositionMode != PositionMode.Fixed)
                                        {
                                            cs.ChangeTagProperty("position", "fixed");
                                        }

                                        // Get top/left pos:
                                        float left = renderData.FirstBox.X + delta.x;
                                        float top  = renderData.FirstBox.Y + delta.y;

                                        // Write it back out:
                                        cs.ChangeTagProperty("left", new Css.Units.DecimalUnit(left));
                                        cs.ChangeTagProperty("top", new Css.Units.DecimalUnit(top));
                                    }
                                }
                            }
                        }
                    }
                    else if (pointer.DragStatus == InputPointer.SELECTING)
                    {
                        // Update the selection.

                        if (pointer.ActivePressed != null)
                        {
                            DragEvent de = new DragEvent("drag");
                            de.trigger = pointer;
                            de.SetModifiers();
                            de.SetTrusted();
                            de.clientX = pointer.DocumentX;
                            de.clientY = pointer.DocumentY;

                            if (pointer.ActivePressed.dispatchEvent(de))
                            {
                                // Get the current selection:
                                Selection s = (pointer.ActivePressed.document as HtmlDocument).getSelection();

                                // Safety check:
                                if (s.ranges.Count > 0)
                                {
                                    // Get the range:
                                    Range range = s.ranges[0];

                                    // Get text node:
                                    RenderableTextNode htn = (range.startContainer as RenderableTextNode);

                                    if (htn != null)
                                    {
                                        // Get the new end index:
                                        int endIndex = htn.LetterIndex(pointer.DocumentX, pointer.DocumentY);

                                        // Update:
                                        range.endOffset = endIndex;

                                        // Flush:
                                        s.UpdateSelection(true, range);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (pointerRemoved)
            {
                // Tidy the removed ones:
                InputPointer.Tidy();
            }

            // Clear invalidated state:
            PointersInvalid = false;

                        #if MOBILE
            // Handle mobile keyboard:
            if (MobileKeyboard != null)
            {
                HandleMobileKeyboardInput();
            }
                        #endif
        }
Пример #3
0
        /// <summary>Sets the pressure level.</summary>
        public void SetPressure(float v)
        {
            // Was it up before?
            bool wasUp = (Pressure == 0f);

            // Set pressure:
            Pressure = v;

            // If it's non-zero then we'll need to grab the clicked object:
            if (v == 0f)
            {
                if (wasUp)
                {
                    // No change.
                }
                else
                {
                    // It's up now. Clear:
                    Element oldActivePressed = ActivePressed;

                    // Clear:
                    ActivePressed = null;

                    if (oldActivePressed != null)
                    {
                        // Refresh CSS (active):
                        (oldActivePressed as IRenderableNode).ComputedStyle.RefreshLocal();
                    }

                    // Trigger up event.
                    MouseEvent e = new MouseEvent(DocumentX, DocumentY, ButtonID, false);
                    e.trigger = this;
                    e.SetModifiers();
                    e.EventType = "mouseup";

                    if (oldActivePressed == null)
                    {
                        Input.Unhandled.dispatchEvent(e);
                    }
                    else
                    {
                        oldActivePressed.dispatchEvent(e);
                    }

                    // Click if needed:
                    if (oldActivePressed == ActiveOver && DragStatus == 0)
                    {
                        // Click!
                        e.Reset();
                        e.trigger = this;
                        e.SetModifiers();
                        e.EventType = "click";

                        if (oldActivePressed == null)
                        {
                            Input.Unhandled.dispatchEvent(e);
                        }
                        else if (oldActivePressed.dispatchEvent(e))
                        {
                            // Perform the default:
                            HtmlElement h = (oldActivePressed as HtmlElement);

                            if (h != null)
                            {
                                h.OnClickEvent(e);
                            }

                            // Clear selection if there is one:
                            (oldActivePressed.document as HtmlDocument).clearSelection();
                        }
                    }

                    if (FireTouchEvents)
                    {
                        // Trigger a touchend event too:
                        TouchEvent te = new TouchEvent("touchend");
                        te.trigger = this;
                        te.SetModifiers();
                        te.SetTrusted();
                        te.clientX = DocumentX;
                        te.clientY = DocumentY;

                        if (oldActivePressed == null)
                        {
                            Input.Unhandled.dispatchEvent(te);
                        }
                        else
                        {
                            oldActivePressed.dispatchEvent(te);
                        }
                    }

                    if (DragStatus == DRAGGING)
                    {
                        // Trigger dragend:
                        DragEvent de = new DragEvent("dragend");
                        de.trigger = this;
                        de.SetModifiers();
                        de.SetTrusted();
                        de.clientX = ScreenX;
                        de.clientY = ScreenY;

                        if (oldActivePressed.dispatchEvent(de))
                        {
                            // Trigger a drop event next:
                            de.Reset();
                            de.EventType = "drop";
                            if (ActiveOver != null && ActiveOver.dispatchEvent(de))
                            {
                                // Proceed to try and drop it into the dropzone (ActiveOver).
                            }
                        }
                    }
                    else if (DragStatus == SELECTING)
                    {
                        // Finished selection - trigger selectionend:
                        Dom.Event sc = new Dom.Event("selectionend");
                        sc.SetTrusted();

                        // Dispatch on the element:
                        oldActivePressed.dispatchEvent(sc);
                    }

                    // Always clear drag status:
                    DragStatus      = 0;
                    MinDragDistance = 0f;
                }
            }
            else if (wasUp)
            {
                // It was up and it's now just gone down.

                // Cache position:
                DownDocumentX = DocumentX;
                DownDocumentY = DocumentY;

                // Cache down:
                ActivePressed = ActiveOver;

                // Trigger down event.

                if (ActivePressed != null)
                {
                    // Refresh CSS (active):
                    (ActivePressed as IRenderableNode).ComputedStyle.RefreshLocal();
                }

                // Trigger down event.
                MouseEvent e = new MouseEvent(DocumentX, DocumentY, ButtonID, true);
                e.trigger   = this;
                e.EventType = "mousedown";
                e.SetModifiers();

                if (ActivePressed == null)
                {
                    Input.Unhandled.dispatchEvent(e);
                }
                else
                {
                    ActivePressed.dispatchEvent(e);
                }

                if (FireTouchEvents)
                {
                    // Trigger a touchend event too:
                    TouchEvent te = new TouchEvent("touchstart");
                    te.trigger = this;
                    te.clientX = DocumentX;
                    te.clientY = DocumentY;
                    te.SetTrusted();
                    te.SetModifiers();

                    if (ActivePressed == null)
                    {
                        Input.Unhandled.dispatchEvent(te);
                    }
                    else
                    {
                        ActivePressed.dispatchEvent(te);
                    }
                }
            }
        }