Kivy - Inputs



The Kivy framework is equipped to receive and process different types of inputs from mouse, touchscreen, gyroscope, accelerometer, etc. Most of the times, Kivy automatically detects available hardware. However, if you want to support custom hardware, you will need to configure kivy accordingly.

All the events generated by different input sources are represented by corresponding event classes. The MotionEvent is the base class used for events provided by pointing devices - both touch and non-touch events.

  • Touch events − a motion event that contains at least an X and Y position. All the touch events are dispatched across the Widget tree.

  • No-touch events − An example of non-touch event is the accelerometer as it is a continuous event, without position. It never starts or stops. These events are not dispatched across the Widget tree.

Kivy applies post-processing to the input and analyzes it to make meaningful interpretations like −

  • Is it a Double/triple-tap detection? (according to a distance and time threshold)

  • Making events more accurate when the hardware is not accurate

  • Reducing the amount of generated events if the native touch hardware is sending events with nearly the same position

After processing, the motion event is dispatched to the Window. if it's only a motion event, it will be dispatched to on_motion(). On the other hand, 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 −

  • on_touch_down()
  • on_touch_move()
  • on_touch_up()

Example

In the following example, we've defined a new class, called widget, which inherits from Widget. We need to import the Widget class with the following statement −

from kivy.uix.widget import Widget

There are three methods in the widget class −

  • on_touch_down − It is the initial press.

  • on_touch_move − It is the movement following and while there is a press.

  • on_touch_up − It is the "release" of a press.

class widget(Widget):
   def on_touch_down(self, touch):
      print("Down:",touch)
   def on_touch_move(self, touch):
      print("Move:",touch)
   def on_touch_up(self, touch):
      print("UP!",touch)

Next, the build() method of App class, returns the widget() object.

class MotionApp(App):
   def build(self):
      return widget()

You can test the code by clicking and dragging on the screen. You should see the mouse's location for all the movement and pressing you do.

Here is the complete code. You can save and run it −

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.config import Config

# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')

class widget(Widget):
   def on_touch_down(self, touch):
      print("Down:",touch)
   def on_touch_move(self, touch):
      print("Move:",touch)
   def on_touch_up(self, touch):
      print("UP!",touch)

class MotionApp(App):
   def build(self):
      return widget()

if __name__ == '__main__':
   MotionApp().run()

Output

The output is an empty application window without any UI widgets in it.

Click with the mouse anywhere in the window. Both the "on_touch_down" and "on_touch_up" events will be captured, showing the location of the mouse touch as follows −

Down: <MouseMotionEvent spos=(0.4228094575799722, 0.38596491228070173) pos=(304.0, 154.0)>
UP! <MouseMotionEvent spos=(0.4228094575799722, 0.38596491228070173) pos=(304.0, 154.0)>
Down: <MouseMotionEvent spos=(0.5730180806675939, 0.5137844611528822) pos=(412.0, 205.0)>
UP! <MouseMotionEvent spos=(0.5730180806675939, 0.5137844611528822) pos=(412.0, 205.0)>
Down: <MouseMotionEvent spos=(0.2517385257301808, 0.5588972431077694) pos=(181.0, 223.0)>
UP! <MouseMotionEvent spos=(0.2517385257301808, 0.5588972431077694) pos=(181.0, 223.0)>

The spos property of the MouseMotionEvent gives a relative location in the 0-1 coordinate system. The bottom-left corner of the application window corresponds to (0,0) and right-up corner corresponds to (1,1)

The pos property shows the actual coordinates where the mouse was clicked. In the above example, it is 378.85 to right and 281.39 pixels upwards from the (0,0) position.

Keep the mouse pressed and move it across the window, you will get the instantaneously changing values of the spos and pos properties. For example −

Move: <MouseMotionEvent spos=(0.41863699582753827, 0.5338345864661654) pos=(376.3546592489569, 266.38345864661653)>
Move: <MouseMotionEvent spos=(0.4172461752433936, 0.531328320802005) pos=(375.1043115438108, 265.1328320802005)>
Move: <MouseMotionEvent spos=(0.41585535465924894, 0.5288220551378446) pos=(373.8539638386648, 263.88220551378447)>

Event Profiles

Based on the input provider and the type of the hardware being used, the event profile contains more information about the input event. The profile is a device specific property if the MotionEvent object. For example, a touch input has an (x,y) position, but might also have pressure information, blob size, an acceleration vector, etc.

By adding the following statement in the touch_down event handler, we can find out the features supported by the current device.

def on_touch_down(self, touch):
   print(touch.profile)

The output will depend on the type of device. It could be −

['pos', 'button']

Or,

['pos', 'angle']

Profile Values

The following are some of the profile values supported by default.

Sr.No Profile value & Description
1 Angle

2D angle. Accessed via the "a" property.

2 Button

Mouse button ('left', 'right', 'middle', 'scrollup' or 'scrolldown'). Accessed via the button property.

3 Markerid

Marker or Fiducial ID. Accessed via the fid property.

4 Pos

2D position. Accessed via the x, y or pos properties.

5 pos3d

3D position. Accessed via the x, y or z properties.

6 Pressure

Pressure of the contact. Accessed via the pressure property.

7 Shape

Contact shape. Accessed via the shape property.

Touch Shape

In Kivy, the area of interaction during touch event is represented by the term "touch shape". It refers to the geometric shape used to represent a touch or touch event on the screen. If the touch has a shape, it will be reflected in the 'shape' property.

Different touch shapes supported by Kivy are ellipse, rectangle, circle and square.

Double / Triple Tap

In the context of multi-touch devices, a double tap is the action of tapping twice within a stipulated time and a distance. Similarly a device can recognize a "triple tap" action.

The event object has an "is_double_tap" property as well as an "is_triple_tap" property, both evaluating to True or False. 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)

Press the mouse button twice in quick succession. You may obtain a result similar to the one shown below −

Touch is a double tap!
- interval is 0.17462420463562012
- distance between previous is 0.0
Advertisements