Skip to content

Commit 7f86687

Browse files
Jonathan Slendersjonathanslenders
Jonathan Slenders
authored andcommitted
Improved mouse support on Windows.
- Handle mouse move events. - Handle scroll wheel events. - Better handle up/down events.
1 parent 5005863 commit 7f86687

File tree

3 files changed

+49
-18
lines changed

3 files changed

+49
-18
lines changed

prompt_toolkit/input/win32.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,13 @@ def _is_paste(keys) -> bool:
318318

319319
return newline_count >= 1 and text_count > 1
320320

321-
def _event_to_key_presses(self, ev):
321+
def _event_to_key_presses(self, ev: KEY_EVENT_RECORD) -> List[KeyPress]:
322322
"""
323323
For this `KEY_EVENT_RECORD`, return a list of `KeyPress` instances.
324324
"""
325325
assert type(ev) == KEY_EVENT_RECORD and ev.KeyDown
326326

327-
result = None
327+
result: Optional[KeyPress] = None
328328

329329
u_char = ev.uChar.UnicodeChar
330330
ascii_char = u_char.encode("utf-8")
@@ -356,7 +356,7 @@ def _event_to_key_presses(self, ev):
356356
and ev.ControlKeyState & self.SHIFT_PRESSED
357357
and result
358358
):
359-
result.key = {
359+
mapping: Dict[str, str] = {
360360
Keys.Left: Keys.ControlShiftLeft,
361361
Keys.Right: Keys.ControlShiftRight,
362362
Keys.Up: Keys.ControlShiftUp,
@@ -366,14 +366,15 @@ def _event_to_key_presses(self, ev):
366366
Keys.Insert: Keys.ControlShiftInsert,
367367
Keys.PageUp: Keys.ControlShiftPageUp,
368368
Keys.PageDown: Keys.ControlShiftPageDown,
369-
}.get(result.key, result.key)
369+
}
370+
result.key = mapping.get(result.key, result.key)
370371

371372
# Correctly handle Control-Arrow/Home/End and Control-Insert keys.
372373
if (
373374
ev.ControlKeyState & self.LEFT_CTRL_PRESSED
374375
or ev.ControlKeyState & self.RIGHT_CTRL_PRESSED
375376
) and result:
376-
result.key = {
377+
mapping = {
377378
Keys.Left: Keys.ControlLeft,
378379
Keys.Right: Keys.ControlRight,
379380
Keys.Up: Keys.ControlUp,
@@ -383,12 +384,13 @@ def _event_to_key_presses(self, ev):
383384
Keys.Insert: Keys.ControlInsert,
384385
Keys.PageUp: Keys.ControlPageUp,
385386
Keys.PageDown: Keys.ControlPageDown,
386-
}.get(result.key, result.key)
387+
}
388+
result.key = mapping.get(result.key, result.key)
387389

388390
# Turn 'Tab' into 'BackTab' when shift was pressed.
389391
# Also handle other shift-key combination
390392
if ev.ControlKeyState & self.SHIFT_PRESSED and result:
391-
result.key = {
393+
mapping = {
392394
Keys.Tab: Keys.BackTab,
393395
Keys.Left: Keys.ShiftLeft,
394396
Keys.Right: Keys.ShiftRight,
@@ -399,7 +401,8 @@ def _event_to_key_presses(self, ev):
399401
Keys.Insert: Keys.ShiftInsert,
400402
Keys.PageUp: Keys.ShiftPageUp,
401403
Keys.PageDown: Keys.ShiftPageDown,
402-
}.get(result.key, result.key)
404+
}
405+
result.key = mapping.get(result.key, result.key)
403406

404407
# Turn 'Space' into 'ControlSpace' when control was pressed.
405408
if (
@@ -443,23 +446,42 @@ def _event_to_key_presses(self, ev):
443446
else:
444447
return []
445448

446-
def _handle_mouse(self, ev):
449+
def _handle_mouse(self, ev: MOUSE_EVENT_RECORD) -> List[KeyPress]:
447450
"""
448451
Handle mouse events. Return a list of KeyPress instances.
449452
"""
450453
FROM_LEFT_1ST_BUTTON_PRESSED = 0x1
454+
MOUSE_MOVED = 0x0001
455+
MOUSE_WHEELED = 0x0004
451456

452457
result = []
458+
event_type: Optional[MouseEventType] = None
453459

454-
# Check event type.
455-
if ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED:
456-
# On a key press, generate both the mouse down and up event.
457-
for event_type in [MouseEventType.MOUSE_DOWN, MouseEventType.MOUSE_UP]:
458-
data = ";".join(
459-
[event_type.value, str(ev.MousePosition.X), str(ev.MousePosition.Y)]
460-
)
461-
result.append(KeyPress(Keys.WindowsMouseEvent, data))
460+
# Move events.
461+
if ev.EventFlags & MOUSE_MOVED:
462+
if ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED:
463+
event_type = MouseEventType.MOUSE_DOWN_MOVE
462464

465+
# Scroll events.
466+
elif ev.EventFlags & MOUSE_WHEELED:
467+
if ev.ButtonState > 0:
468+
event_type = MouseEventType.SCROLL_UP
469+
else:
470+
event_type = MouseEventType.SCROLL_DOWN
471+
472+
# Mouse down (left button).
473+
elif ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED:
474+
event_type = MouseEventType.MOUSE_DOWN
475+
476+
# No key pressed anymore: mouse up.
477+
else:
478+
event_type = MouseEventType.MOUSE_UP
479+
480+
if event_type is not None:
481+
data = ";".join(
482+
[event_type.value, str(ev.MousePosition.X), str(ev.MousePosition.Y)]
483+
)
484+
result.append(KeyPress(Keys.WindowsMouseEvent, data))
463485
return result
464486

465487

prompt_toolkit/layout/controls.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,14 +856,22 @@ def mouse_handler(self, mouse_event: MouseEvent) -> "NotImplementedOrNone":
856856
buffer.exit_selection()
857857
buffer.cursor_position = index
858858

859+
elif mouse_event.event_type == MouseEventType.MOUSE_DOWN_MOVE:
860+
if buffer.selection_state is None:
861+
buffer.start_selection(selection_type=SelectionType.CHARACTERS)
862+
buffer.cursor_position = index
863+
859864
elif mouse_event.event_type == MouseEventType.MOUSE_UP:
860865
# When the cursor was moved to another place, select the text.
861866
# (The >1 is actually a small but acceptable workaround for
862867
# selecting text in Vi navigation mode. In navigation mode,
863868
# the cursor can never be after the text, so the cursor
864869
# will be repositioned automatically.)
865870
if abs(buffer.cursor_position - index) > 1:
866-
buffer.start_selection(selection_type=SelectionType.CHARACTERS)
871+
if buffer.selection_state is None:
872+
buffer.start_selection(
873+
selection_type=SelectionType.CHARACTERS
874+
)
867875
buffer.cursor_position = index
868876

869877
# Select word around cursor on double click.

prompt_toolkit/mouse_events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
class MouseEventType(Enum):
2626
MOUSE_UP = "MOUSE_UP"
2727
MOUSE_DOWN = "MOUSE_DOWN"
28+
MOUSE_DOWN_MOVE = "MOUSE_DOWN_MOVE"
2829
SCROLL_UP = "SCROLL_UP"
2930
SCROLL_DOWN = "SCROLL_DOWN"
3031

0 commit comments

Comments
 (0)