#9375·kivy

touch.is_double_tap is affected by Shift modifier in mouse provider

Author: mushket-re0ahCreated Sep 12, 2026Updated Sep 12, 2026

Software Versions

  • Python: v3.14.6 (main, Jun 15 2026, 11:36:54) [GCC 16.1.1 20260430]
  • OS: arch linux desktop 7.1.2-arch3-1 #1 SMP PREEMPT_DYNAMIC Fri, 03 Jul 2026 23:25:36 +0000 x86_64 GNU/Linux
  • Kivy: 2.3.1
  • Kivy installation method: pip

also checked on

  • Python: v3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)]
  • OS: windows 7
  • Kivy: 2.3.1
  • Kivy installation method: pip

Describe the bug When using the mouse input provider, holding the Shift key affects the value of touch.is_double_tap.

With shift: single click -> True double click -> False

Without Shift the behavior as expected: single click -> False double click -> True

It will be work like:

             | not shift | with shift |
single click |   False   |   True     |
double click |   True    |   False    |

So holding shift is inverts the touch.is_double_tap.

This appears to be caused by the mouse provider explicitly setting is_double_tap based on the Shift modifier:

python
is_double_tap = 'shift' in modifiers

This behavior is present in on_mouse_press in kivy/input/providers/mouse (state of master branch. In 2.3.1 also in on_mouse_motion).

Expected behavior touch.is_double_tap should indicate whether the current touch is a double tap/click, independently of keyboard modifiers.

A single click should result in touch.is_double_tap == False, and a double click should result in touch.is_double_tap == True, regardless of whether Shift is held.

If the Shift behavior is intentional and required for mouse/touch emulation, it should at least be configurable so applications can disable it when they need the normal is_double_tap semantics. By kivy.config.

To Reproduce

python
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window

class Root(Widget):
    def on_touch_down(self, touch):
        print("is double click:", touch.is_double_tap, "is shift:", "shift" in Window.modifiers)
        return super().on_touch_down(touch)

class Test(App):
    def build(self):
        self.root = Root()
        return self.root

Test().run()

Why this is a problem is_double_tap is exposed as a property of the touch event and its name/meaning strongly suggests that it describes whether the touch is a double tap.

Keyboard modifier state is a separate concept.

For example, an application may legitimately need to distinguish these four cases:

python
if touch.is_double_tap:
    if "shift" in Window.modifiers:
        # double click + Shift
        ...
    else:
        # double click
        ...

With the current mouse provider, this is not possible because Shift changes the meaning of touch.is_double_tap.

A local workaround such as reversing inversion by create local variable:

python
shift = "shift" in Window.modifiers
is_double_tap = touch.is_double_tap
if shift:
    is_double_tap = not is_double_tap

Works only if this conversion is performed everywhere the application consumes the event. This is fragile for larger applications and makes the semantics of touch.is_double_tap dependent on an application-wide convention.

Possible solution Add the configuration option controlling the current Shift behavior in the mouse input provider.

Changing the current semantic may broke backward compatibility. So, preserving the current behavior as the default behavior. Just need the option in config.