touch.is_double_tap is affected by Shift modifier in mouse provider
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
#1SMP 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:
is_double_tap = 'shift' in modifiersThis 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
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:
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:
shift = "shift" in Window.modifiers
is_double_tap = touch.is_double_tap
if shift:
is_double_tap = not is_double_tapWorks 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.
Source: kivy/kivy