Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions asciimatics/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class MouseEvent(Event):
LEFT_CLICK = 1
RIGHT_CLICK = 2
DOUBLE_CLICK = 4
# Note: older versions of curses (e.g. in pypy) do not support up/down
SCROLL_UP = 8
SCROLL_DOWN = 16

def __init__(self, x: int, y: int, buttons: int):
"""
Expand Down
16 changes: 14 additions & 2 deletions asciimatics/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2213,8 +2213,15 @@ def get_event(self):
button |= MouseEvent.LEFT_CLICK
if event.ButtonState & win32con.RIGHTMOST_BUTTON_PRESSED != 0:
button |= MouseEvent.RIGHT_CLICK
elif event.EventFlags & win32con.DOUBLE_CLICK != 0:
button |= MouseEvent.DOUBLE_CLICK
else:
if event.EventFlags & win32con.MOUSE_WHEELED:
direction = (event.ButtonState & 0xFFFF0000) // 0x10000
if direction & 0x8000 == 0:
button |= MouseEvent.SCROLL_UP
else:
button |= MouseEvent.SCROLL_DOWN
if event.EventFlags & win32con.DOUBLE_CLICK != 0:
button |= MouseEvent.DOUBLE_CLICK

return MouseEvent(event.MousePosition.X, event.MousePosition.Y, button)

Expand Down Expand Up @@ -2599,6 +2606,11 @@ def get_event(self) -> Optional[Event]:
buttons |= MouseEvent.LEFT_CLICK
if (bstate & curses.BUTTON3_PRESSED != 0 or bstate & curses.BUTTON3_CLICKED != 0):
buttons |= MouseEvent.RIGHT_CLICK
if hasattr(curses, "BUTTON5_PRESSED"):
if (bstate & curses.BUTTON4_PRESSED != 0 or bstate & curses.BUTTON4_CLICKED != 0):
buttons |= MouseEvent.SCROLL_UP
if (bstate & curses.BUTTON5_PRESSED != 0 or bstate & curses.BUTTON5_CLICKED != 0):
buttons |= MouseEvent.SCROLL_DOWN
if bstate & curses.BUTTON1_DOUBLE_CLICKED != 0:
buttons |= MouseEvent.DOUBLE_CLICK
return MouseEvent(x, y, buttons)
Expand Down
4 changes: 2 additions & 2 deletions asciimatics/widgets/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ def add_effect(self, effect: Effect):

:param effect: The Effect to be added.
"""
assert self._scene is not None
effect.register_scene(self._scene)
if self._scene:
effect.register_scene(self._scene)
self._effects.append(effect)

def fix(self):
Expand Down
6 changes: 6 additions & 0 deletions samples/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ def process_event(self, event):
elif event.buttons & MouseEvent.RIGHT_CLICK != 0:
# Try to whack the other sprites when mouse is clicked
self._sprite.whack("CRASH!")
elif event.buttons & MouseEvent.SCROLL_UP != 0:
# Try to whack the other sprites when mouse is clicked
self._sprite.whack("OOOOH!")
elif event.buttons & MouseEvent.SCROLL_DOWN != 0:
# Try to whack the other sprites when mouse is clicked
self._sprite.whack("AAAAH!")
else:
return event

Expand Down
31 changes: 30 additions & 1 deletion tests/test_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,19 +698,30 @@ def _inject_mouse(screen, x, y, button):
event.ButtonState |= win32con.FROM_LEFT_1ST_BUTTON_PRESSED
if button & MouseEvent.RIGHT_CLICK != 0:
event.ButtonState |= win32con.RIGHTMOST_BUTTON_PRESSED
if button & MouseEvent.SCROLL_UP != 0:
event.EventFlags |= win32con.MOUSE_WHEELED
event.ButtonState = 120
if button & MouseEvent.SCROLL_DOWN != 0:
event.EventFlags |= win32con.MOUSE_WHEELED
event.ButtonState = -120
if button & MouseEvent.DOUBLE_CLICK != 0:
event.EventFlags |= win32con.DOUBLE_CLICK
screen._stdin.WriteConsoleInput([event])
else:
# Curses doesn't like no value in some cases - use a dummy button
# click which we don't use instead.
bstate = curses.BUTTON4_CLICKED
bstate = curses.BUTTON2_CLICKED
if button & MouseEvent.LEFT_CLICK != 0:
bstate |= curses.BUTTON1_CLICKED
if button & MouseEvent.RIGHT_CLICK != 0:
bstate |= curses.BUTTON3_CLICKED
if button & MouseEvent.DOUBLE_CLICK != 0:
bstate |= curses.BUTTON1_DOUBLE_CLICKED
if sys.platform != "win32" and hasattr(curses, "BUTTON5_PRESSED"):
if button & MouseEvent.SCROLL_UP != 0:
bstate |= curses.BUTTON4_CLICKED
if button & MouseEvent.SCROLL_DOWN != 0:
bstate |= curses.BUTTON5_CLICKED
curses.ungetmouse(0, x, y, 0, bstate)

def test_key_input(self):
Expand Down Expand Up @@ -787,6 +798,24 @@ def internal_checks(screen):
self.assertEqual(ev.buttons, MouseEvent.DOUBLE_CLICK)
self.assertIsNone(screen.get_event())

# Not all curses versions support scrolling...
if sys.platform == "win32" or hasattr(curses, "BUTTON5_PRESSED"):
# Check scroll up
self._inject_mouse(screen, 1, 1, MouseEvent.SCROLL_UP)
ev = screen.get_event()
self.assertEqual(ev.x, 1)
self.assertEqual(ev.y, 1)
self.assertEqual(ev.buttons, MouseEvent.SCROLL_UP)
self.assertIsNone(screen.get_event())

# Check scroll up
self._inject_mouse(screen, 1, 1, MouseEvent.SCROLL_DOWN)
ev = screen.get_event()
self.assertEqual(ev.x, 1)
self.assertEqual(ev.y, 1)
self.assertEqual(ev.buttons, MouseEvent.SCROLL_DOWN)
self.assertIsNone(screen.get_event())

Screen.wrapper(internal_checks, height=15)

def test_windows_input(self):
Expand Down
Loading