Closed mal closed 7 months ago
Is there an application for this?
Since pygame was ported to SDL2, pygame_sdl2 only exists to support Ren'Py. And I don't think it makes sense to allow CDDs to trap the mouse like this.
Trapping the mouse in this way is already possible. This just fixes the relative mouse movement values so that it can be made good use of in such cases as I highlighted in the "benefits" section above.
I arrived here after trying to make a CDD-based mini game where some items are heavier than others, so I wanted to adjust mouse sensitivity within the game while dragging the different items around based on their weight.
Another good, though advanced, case for this is facilitating player navigation around an equirectangular panoramic.
Between SDL1.2 and SDL2 the method for switching to relative mouse mode changed, breaking pygame's virtual input mode. This patch is based on a change in pygame proper from 2019 made to address this issue.
Current behaviour
Despite using
pygame.event.set_grab(True)
andpygame.mouse.set_visible(False)
at the same time, the (hidden) cursor is limited to the confines of the window and the relative mouse movement values stop progressing at that point.Expected behaviour / with this patch
Using
pygame.event.set_grab(True)
andpygame.mouse.set_visible(False)
at the same time acitvates "virtual input" mode as documented bypygame
near the top of this page. The (hidden) cursor and its reported position are still (correctly) limited to the confines of the window as before, however the relative mouse movement values no longer stop progressing at the window edge.Benefits
This allows advanced CDDs to enter virtual input mode in order to facilitate seamless mouse-controlled panning, dragging, etc. It also becomes possible to simulate mouse sensitivity and acceleration changes by adjusting the relative movement values before accumulating them.
Test game (click and hold to switch into virtual input mode)
```rpy label main_menu: $ _confirm_quit = False return label start: scene black call screen test() return screen test(): grid 2 3: align (.5, .2) spacing 10 xsize .4 text 'real pos' xalign 1. text '[data["pos"]]' text 'most recent delta' xalign 1. text '[data["mov"]]' text 'virtual pos' xalign 1. if 'vir' in data: text '[data["vir"]]' color '7fa' else: text 'off' add MousePosReporter() init python: import collections import pygame v = collections.namedtuple('vector', 'x y') v.__iadd__ = lambda self, o: v(self[0] + o[0], self[1] + o[1]) data = _dict(pos=None, mov=None) def virtual_input(toggle): # per https://www.pygame.org/docs/ref/mouse.html pygame.mouse.set_visible(not toggle) pygame.event.set_grab(toggle) class MousePosReporter(Null): def event(self, ev, x, y, st): if ev.type == pygame.MOUSEMOTION: data['pos'] = x, y data['mov'] = ev.rel # same value as from pygame.mouse.get_rel() if 'vir' in data: data['vir'] += ev.rel renpy.restart_interaction() elif ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 1: virtual_input(True) data['end'] = data['vir'] = v(x, y) elif ev.type == pygame.MOUSEBUTTONUP and ev.button == 1: virtual_input(False) del data['vir'] renpy.set_mouse_pos(*data['end']) else: return None renpy.restart_interaction() raise renpy.display.core.IgnoreEvent ```Tested successfully on Ubuntu 22.04 using
fix
branches plus this change.