Input management
================

Input architecure
-----------------

Kivy is able to handling almost all types of inputs: mouse, touchscreen,
accelerator, gyroscope, etc. It handle natively multitouch protocol on every
platforms: Tuio, WM_Touch, MacMultitouchSupport, MT Protocol A/B, Android.

The global architecture can be resumed like that::

    Input providers -> Motion event -> Post processing -> Dispatch to Window

The class for all input events is the
:class:`~kivy.input.motionevent.MotionEvent`. From this, they are 2 kinds of
events:

    - Touch events: it's a motion event that contain at least X and Y position.
      All the touch events are dispatched accross the Widget tree.
    - No-touch events: it's all the rest. For example, accelerator is a
      continuous event, without position. It never start or stop. Theses events
      are not dispatched accross the Widget tree.


A Motion event is generated by a Input Provider. An input provider is responsible of reading the input event of one operating system, from the network of even from another application. Severals inputs providers exist, like:

    - :class:`~kivy.input.providers.tuio.TuioMotionEventProvider`: create an
      UDP server and listening for TUIO/OSC message.
    - :class:`~kivy.input.providers.wm_touch.WM_MotionEventProvider`: use the
      windows API for reading multitouch information and sending back to Kivy
    - :class:`~kivy.input.providers.probesysfs.ProbeSysfsHardwareProbe`:
      iterate over all the hardaware connected to the computer on linux, and
      attach multitouch input provider for all the multitouch hardware found.
    - and lot more !

When you write an application, you don't need to create input provider. Kivy try to detect automatically the hardware available on the user computer. If the user want to support custom hardware, he will configure kivy to make it work.

Before the newly Motion Event is passed to the user, we are applying Input post-processors. For every motion event, we are analysis them to detect and correct the inputs like:

    - the detection of a double-tap according to a distance and time threshold
    - correcting events when the hardware is not accurate
    - reducing the amount of event if the touch is sending nearly the same
      position

Then, the motion event is dispatched to the Window. But as explained at the start, all the events are not dispatched to the whole widget tree, the window is filtering them.

    - if it's only a motion event, it will be dispatched to :meth:`~kivy.core.window.WindowBase.on_motion`
    - if it's a touch event, the x/y position of the touch (0-1 range) will be scaled to the Window size (width/height), and dispatched to:

      - :meth:`~kivy.uix.widget.Widget.on_touch_down`
      - :meth:`~kivy.uix.widget.Widget.on_touch_move`
      - :meth:`~kivy.uix.widget.Widget.on_touch_up`


Motion event profiles
---------------------

Depending of your hardware and the input providers used, you can have more
information. For example, a touch have x/y position, but might have pressure
information, blob size, acceleration vector etc.

A profile is a string that indicate what features is available inside the
motion event. For example, let's imagine that you are in a on_touch_move
method::

    def on_touch_move(self, touch):
        print touch.profiles
        return super(..., self).on_touch_move(touch)

The print could output::

    ['pos', 'angle']

.. warning::

    Most peoples are mixing the profile name and the properties available.
    Checking for 'angle' in profiles doesn't mean that a properties 'angle'
    exist.

The 'pos' profile mean that the properties 'pos', 'x' and 'y' will be
available. The 'angle' profile mean that the property 'a' will be available. As
we said, for touch event, pos is a mandatory profile. But not angle. You can
extend your interaction by checking if the angle profile exist::

    def on_touch_move(self, touch):
        print 'The touch is at position', touch.pos
        if 'angle' in touch.profiles:
            print 'The touch angle is', touch.a

You can find a list of available profiles in the :ref:`motionevent`
documentation.

Touch events
------------

A touch event is a specialized :class:`~kivy.input.motionevent.MotionEvent`
with the property :data:`~kivy.input.motionevent.MotionEvent.is_touch` to True.
For all touch event, you have automatically the X and Y position available,
scaled to the Window width and height.

All the touch event have also the "pos" profile.

You must take care about matrix transformation in your touch as soon as you use
a widget with matrix transformation. Some widgets as Scatter have their own
matrix transformation, mean the touch must be multiply by the matrix scatter to
be able to correctly dispatch touch position in the Scatter's children.

    - Get coordinate from parent space to local space:
      :meth:`~kivy.uix.widget.Widget.to_local`
    - Get coordinate from local space to parent space:
      :meth:`~kivy.uix.widget.Widget.to_parent`
    - Get coordinate from local space to window space:
      :meth:`~kivy.uix.widget.Widget.to_window`
    - Get coordinate from window space to local space:
      :meth:`~kivy.uix.widget.Widget.to_widget`

You must use one of them to get the good coordinate. Let's take the scatter
implementation::

    def on_touch_down(self, touch):
        # push the current coordinate, to be able to restore them later.
        touch.push()

        # transform the touch coordinate to local space
        touch.apply_transform_2d(self.to_local)

        # dispatch the touch as usual to children
        # the coordinate in the touch are now in local space
        ret = super(..., self).on_touch_down(touch)

        # whatever is the result, don't forget to pop the transformation
        # after the call, the coordinate will be in parent space
        touch.pop()

        # return the result (depending what you want.)
        return ret


Touch shapes
~~~~~~~~~~~~

If the touch have a shape, it will be reflected in the 'shape' property. Right now, only a :class:`~kivy.input.shape.ShapeRect` could be exposed::

    from kivy.input.shape import ShapeRect

    def on_touch_move(self, touch):
        if isinstance(touch.shape, ShapeRect):
            print 'My touch have a rectangle shape of size', \
                (touch.shape.width, touch.shape.height)
        # ...

Double tap
~~~~~~~~~~

The double tap is the action of tapping twice in within a time and a distance.
It's calculated by the doubletap post-processing module. You can test if the
current touch is one of a double tap or not::

    def on_touch_down(self, touch):
        if touch.is_double_tap:
            print 'Touch is a double tap !'
            print ' - interval is', touch.double_tap_time
            print ' - distance between previous is', touch.double_tap_distance
        # ...


Grabbing touches
~~~~~~~~~~~~~~~~

It can happen that your parent dispatch to you a touch in on_touch_down but not
in on_touch_move and on_touch_up. They might have severals reasons, like the
touch movement is outside the bounding box of your parent, and the parent think
that you don't need to know about it.

But you might want to do an action when the touch is going up. If you have
started something at the down event, like playing a sound, how can you do to
have the touch up ? Grabbing is made for that.

When you grab a touch, you will always receive the move and up event. But they are some limitations to that:

    - You will receive the event at least twice: one time from your parent (the
      normal thing), and one time by the window (grab).
    - You might receive an event with a grab touch, but not from you: it can be
      because the parent have sent the touch to the children, while it was in
      grabbed state.
    - The touch coordinate is not translated to your widget space. BBecause the
      touch is coming directly from the Window. It's your job to convert the
      coordinate to your local space.

Here is an example about how to use it::

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):

            # if the touch is colliding to our widget, let's grab it.
            touch.grab(self)

            # and accept the touch.
            return True

    def on_touch_up(self, touch):
        # here, you don't check if the touch is colliding or things like that.
        # you just need to check if it's a grabbed touch event
        if touch.grab_current is self:

            # ok, the current touch is dispatched for us.
            # do something interesting here
            print 'Hello world!'

            # don't forget to ungrab ourself, or you might have counter effects
            touch.ungrab(self)

            # and accept the last up
            return True

