Skip to content

Commit

Permalink
#1942 convert button-action to the more generic packet format
Browse files Browse the repository at this point in the history
  • Loading branch information
totaam committed Jan 4, 2023
1 parent 20e352d commit 5178602
Show file tree
Hide file tree
Showing 16 changed files with 120 additions and 73 deletions.
25 changes: 7 additions & 18 deletions xpra/client/client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,34 +950,23 @@ def _device_info(self, event):
except AttributeError:
return ""

def _button_action(self, button, event, depressed, *args):
def _button_action(self, button, event, depressed, props=None):
if self._client.readonly or self._client.server_readonly or not self._client.server_pointer:
return
pointer_data, modifiers, buttons = self._pointer_modifiers(event)
wid = self.get_mouse_event_wid(*pointer_data)
mouselog("_button_action(%s, %s, %s) wid=%s / focus=%s / window wid=%i, device=%s, pointer=%s, modifiers=%s, buttons=%s",
button, event, depressed, wid, self._client._focused, self._id, self._device_info(event), pointer_data, modifiers, buttons)
#map wheel buttons via translation table to support inverted axes:
server_button = button
if button>3:
server_button = self._client.wheel_map.get(button)
if not server_button:
return
server_buttons = []
for b in buttons:
if b>3:
sb = self._client.wheel_map.get(button)
if not sb:
continue
b = sb
server_buttons.append(b)
def send_button(pressed):
self._client.send_button(wid, server_button, pressed, pointer_data, modifiers, server_buttons, *args)
device_id = 0
def send_button(pressed, **kwargs):
sprops = props or {}
sprops.update(kwargs)
self._client.send_button(device_id, wid, button, pressed, pointer_data, modifiers, buttons, sprops)
pressed_state = self.button_state.get(button, False)
if SIMULATE_MOUSE_DOWN and pressed_state is False and depressed is False:
mouselog("button action: simulating missing mouse-down event for window %s before mouse-up", wid)
#(needed for some dialogs on win32):
send_button(True)
send_button(True, synthetic=True)
self.button_state[button] = depressed
send_button(depressed)

Expand Down
3 changes: 2 additions & 1 deletion xpra/client/gtk_base/gtk_client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2412,7 +2412,8 @@ def _do_scroll_event(self, event):
if event.direction==Gdk.ScrollDirection.SMOOTH:
mouselog("smooth scroll event: %s", event)
pointer = self.get_pointer_data(event)
self._client.wheel_event(self._id, event.delta_x, -event.delta_y, pointer)
device_id = -1
self._client.wheel_event(device_id, self._id, event.delta_x, -event.delta_y, pointer)
return
button_mapping = GDK_SCROLL_MAP.get(event.direction, -1)
mouselog("do_scroll_event device=%s, direction=%s, button_mapping=%s",
Expand Down
57 changes: 43 additions & 14 deletions xpra/client/mixins/window_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,18 +412,18 @@ def _process_pointer_position(self, packet):
value = None
show_pointer_overlay(value)

def send_wheel_delta(self, wid, button, distance, pointer=None, *args):
def send_wheel_delta(self, device_id, wid, button, distance, pointer=None, props=None):
modifiers = self.get_current_modifiers()
buttons = []
mouselog("send_wheel_delta(%i, %i, %.4f, %s) precise wheel=%s, modifiers=%s, pointer=%s",
wid, button, distance, args, self.server_precise_wheel, modifiers, pointer)
mouselog("send_wheel_deltas% precise wheel=%s, modifiers=%s, pointer=%s",
(device_id, wid, button, distance, pointer, props), self.server_precise_wheel, modifiers, pointer)
if self.server_precise_wheel:
#send the exact value multiplied by 1000 (as an int)
idist = round(distance*1000)
if abs(idist)>0:
packet = ["wheel-motion", wid,
button, idist,
pointer, modifiers, buttons] + list(args)
pointer, modifiers, buttons] + list((props or {}).values())
mouselog("send_wheel_delta(..) %s", packet)
self.send_positional(packet)
return 0
Expand All @@ -436,8 +436,8 @@ def send_wheel_delta(self, wid, button, distance, pointer=None, *args):
scaled_distance = math.sqrt(scaled_distance)
steps = round(scaled_distance)
for _ in range(steps):
self.send_button(wid, button, True, pointer, modifiers, buttons)
self.send_button(wid, button, False, pointer, modifiers, buttons)
for state in True, False:
self.send_button(device_id, wid, button, state, pointer, modifiers, buttons, props)
#return remainder:
scaled_remainder = steps
if MOUSE_SCROLL_SQRT_SCALE:
Expand All @@ -449,30 +449,59 @@ def send_wheel_delta(self, wid, button, distance, pointer=None, *args):
return float(distance) - signed_remain_distance


def wheel_event(self, wid, deltax=0, deltay=0, pointer=(), deviceid=0):
def wheel_event(self, device_id=-1, wid=0, deltax=0, deltay=0, pointer=(), props=None):
#this is a different entry point for mouse wheel events,
#which provides finer grained deltas (if supported by the server)
#accumulate deltas:
self.wheel_deltax += deltax
self.wheel_deltay += deltay
button = self.wheel_map.get(6+int(self.wheel_deltax>0)) #RIGHT=7, LEFT=6
if button>0:
self.wheel_deltax = self.send_wheel_delta(wid, button, self.wheel_deltax, pointer, deviceid)
self.wheel_deltax = self.send_wheel_delta(device_id, wid, button, self.wheel_deltax, pointer, props)
button = self.wheel_map.get(5-int(self.wheel_deltay>0)) #UP=4, DOWN=5
if button>0:
self.wheel_deltay = self.send_wheel_delta(wid, button, self.wheel_deltay, pointer, deviceid)
self.wheel_deltay = self.send_wheel_delta(device_id, wid, button, self.wheel_deltay, pointer, props)
mouselog("wheel_event%s new deltas=%s,%s",
(wid, deltax, deltay, deviceid), self.wheel_deltax, self.wheel_deltay)
(device_id, wid, deltax, deltay), self.wheel_deltax, self.wheel_deltay)

def send_button(self, wid, button, pressed, pointer, modifiers, buttons, *args):
def send_button(self, device_id, wid, button, pressed, pointer, modifiers, buttons, props):
pressed_state = self._button_state.get(button, False)
if SKIP_DUPLICATE_BUTTON_EVENTS and pressed_state==pressed:
mouselog("button action: unchanged state, ignoring event")
return
#map wheel buttons via translation table to support inverted axes:
server_button = button
if button>3:
server_button = self.wheel_map.get(button, -1)
server_buttons = []
for b in buttons:
if b>3:
sb = self.wheel_map.get(button)
if not sb:
continue
b = sb
server_buttons.append(b)
self._button_state[button] = pressed
packet = ["button-action", wid,
button, pressed,
pointer, modifiers, buttons] + list(args)
if "pointer-button" in self.server_packet_types:
props = props or {}
if modifiers is not None:
props["modifiers"] = modifiers
props["buttons"] = server_buttons
if server_button!=button:
props["raw-button"] = button
if server_buttons!=buttons:
props["raw-buttons"] = buttons
seq = self.next_pointer_sequence(device_id)
packet = ["pointer-button", device_id, seq, wid,
server_button, pressed, pointer, props]
else:
if server_button==-1:
return
packet = ["button-action", wid,
server_button, pressed,
pointer, modifiers, server_buttons]
if props:
packet += list(props.values())
mouselog("button packet: %s", packet)
self.send_positional(packet)

Expand Down
2 changes: 1 addition & 1 deletion xpra/client/rfb_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def send_pointer_position(self, packet):
self.do_send_pointer_event(button_mask, x, y)

def send_button_action(self, packet):
log.warn("send_button_action(%s)", packet)
log("send_button_action(%s)", packet)
if not self.check_wid(packet[1]):
return
#["button-action", wid, button, pressed, (x, y), modifiers, buttons]
Expand Down
2 changes: 2 additions & 0 deletions xpra/net/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ class ConnectionClosedException(Exception):
"configure-override-redirect", "lost-window", "window-icon",
"draw",
"eos", "cursor", "bell",
#pointer motion and events:
"pointer-position", "pointer",
"button-action", "pointer-button",
"pointer-grab", "pointer-ungrab",
"webcam-stop", "webcam-ack",
"set-clipboard-enabled", "clipboard-token", "clipboard-request",
Expand Down
2 changes: 1 addition & 1 deletion xpra/net/quic/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

HttpConnection = Union[H0Connection, H3Connection]

DATAGRAM_PACKET_TYPES = os.environ.get("XPRA_QUIC_DATAGRAM_PACKET_TYPES", "pointer").split(",")
DATAGRAM_PACKET_TYPES = os.environ.get("XPRA_QUIC_DATAGRAM_PACKET_TYPES", "pointer,pointer-button").split(",")


class XpraQuicConnection(Connection):
Expand Down
3 changes: 2 additions & 1 deletion xpra/platform/darwin/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,8 @@ def normalize_precision(distance):
client = window._client
wid = window._id
pointer = window.get_mouse_position()
client.wheel_event(wid, dx, dy, pointer)
device_id = -1
client.wheel_event(device_id, wid, dx, dy, pointer)
return True

@objc.python_method
Expand Down
10 changes: 5 additions & 5 deletions xpra/platform/darwin/shadow_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,14 @@ def fake_key(self, keycode, press):
#this causes crashes, don't do it!
#CG.CFRelease(e)

def do_process_button_action(self, proto, wid, button, pressed, pointer, modifiers, *args):
self._update_modifiers(proto, wid, modifiers)
device_id = -1
def do_process_button_action(self, proto, device_id, wid, button, pressed, pointer, props):
if "modifiers" in props:
self._update_modifiers(proto, wid, props.get("modifiers"))
pointer = self._process_mouse_common(proto, device_id, wid, pointer)
if pointer:
self.button_action(wid, pointer, button, pressed, -1, *args)
self.button_action(device_id, wid, pointer, button, pressed, props)

def button_action(self, wid, pointer, button, pressed, _deviceid=-1, *_args):
def button_action(self, device_id, wid, pointer, button, pressed, props):
if button<=3:
#we should be using CGEventCreateMouseEvent
#instead we clear previous clicks when a "higher" button is pressed... oh well
Expand Down
3 changes: 2 additions & 1 deletion xpra/platform/win32/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,8 @@ def handle_wheel(orientation, wParam, lParam):
deltax = units
deltay = 0
pointer = window.get_mouse_position()
client.wheel_event(wid, deltax, deltay, pointer)
device_id = -1
client.wheel_event(device_id, wid, deltax, deltay, pointer)
def mousewheel(_hwnd, _event, wParam, lParam):
handle_wheel(VERTICAL, wParam, lParam)
return 0
Expand Down
9 changes: 5 additions & 4 deletions xpra/platform/win32/shadow_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,15 +585,16 @@ def get_keyboard_config(self, _props=None):
def fake_key(self, keycode, press):
fake_key(keycode, press)

def do_process_button_action(self, proto, wid, button, pressed, pointer, modifiers, *args):
self._update_modifiers(proto, wid, modifiers)
def do_process_button_action(self, proto, device_id, wid, button, pressed, pointer, props):
if "modifiers" in props:
self._update_modifiers(proto, wid, props.get("modifiers"))
device_id = -1
pointer = self._process_mouse_common(proto, device_id, wid, pointer)
if pointer:
self.get_server_source(proto).user_event()
self.button_action(wid, pointer, button, pressed, -1, *args)
self.button_action(device_id, wid, pointer, button, pressed, props)

def button_action(self, wid, pointer, button, pressed, deviceid=-1, *args):
def button_action(self, device_id, wid, pointer, button, pressed, props):
event = BUTTON_EVENTS.get((button, pressed))
if event is None:
log.warn("no matching event found for button=%s, pressed=%s", button, pressed)
Expand Down
8 changes: 4 additions & 4 deletions xpra/platform/xposix/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,8 +669,8 @@ def do_xi_button(self, event, device):
return
button = event.detail
depressed = (event.name == "XI_ButtonPress")
args = self.get_pointer_extra_args(event)
window._button_action(button, event, depressed, *args)
props = self.get_pointer_extra_args(event)
window._button_action(button, event, depressed, props)

def do_xi_motion(self, event, device):
window = self.window
Expand Down Expand Up @@ -727,17 +727,17 @@ def do_xi_motion(self, event, device):
#whatever happens, update our motion cached values:
mv.update(event.valuators)
#send plain motion first, if any:
props = self.get_pointer_extra_args(event)
if unused_valuators:
xinputlog("do_xi_motion(%s, %s) wid=%s / focus=%s / window wid=%i, device=%s, pointer=%s, modifiers=%s, buttons=%s",
event, device, wid, window._client._focused, window._id, event.device, pointer_data, modifiers, buttons)
device_id = 0
props = self.get_pointer_extra_args(event)
client.send_mouse_position(device_id, wid, pointer_data, modifiers, buttons, props)
#now see if we have anything to send as a wheel event:
if dx!=0 or dy!=0:
xinputlog("do_xi_motion(%s, %s) wheel deltas: dx=%i, dy=%i", event, device, dx, dy)
#normalize (xinput is always using 15 degrees?)
client.wheel_event(wid, dx/XINPUT_WHEEL_DIV, dy/XINPUT_WHEEL_DIV, pointer_data, event.device)
client.wheel_event(event.device, wid, dx/XINPUT_WHEEL_DIV, dy/XINPUT_WHEEL_DIV, pointer_data, props)

def get_pointer_extra_args(self, event):
def intscaled(f):
Expand Down
2 changes: 1 addition & 1 deletion xpra/server/dbus/dbus_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def MouseClick(self, button, pressed):
button, pressed = ni(button), nb(pressed)
self.log(".MouseClick%s", (button, pressed))
device_id = -1
self.server.button_action(0, None, button, pressed, device_id)
self.server.button_action(device_id, 0, None, button, pressed)


@dbus.service.method(INTERFACE, in_signature='iiii')
Expand Down
36 changes: 31 additions & 5 deletions xpra/server/mixins/input_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,25 @@ def _process_mouse_common(self, proto, device_id, wid, opointer, props=None):
def do_process_mouse_common(self, proto, device_id, wid, pointer, props):
return True

def _process_pointer_button(self, proto, packet):
mouselog("process_pointer_button(%s, %s)", proto, packet)
if self.readonly:
return
ss = self.get_server_source(proto)
if ss is None:
return
ss.user_event()
self.last_mouse_user = ss.uuid
self.set_ui_driver(ss)
device_id, seq, wid, button, pressed, pointer, props = packet[1:8]
if device_id>=0:
highest_seq = self.pointer_sequence.get(device_id, 0)
if 0<=seq<=highest_seq:
mouselog(f"dropped outdated sequence {seq}, latest is {highest_seq}")
return
self.pointer_sequence[device_id] = seq
self.do_process_button_action(proto, device_id, wid, button, pressed, pointer, props)

def _process_button_action(self, proto, packet):
mouselog("process_button_action(%s, %s)", proto, packet)
if self.readonly:
Expand All @@ -376,9 +395,15 @@ def _process_button_action(self, proto, packet):
ss.user_event()
self.last_mouse_user = ss.uuid
self.set_ui_driver(ss)
self.do_process_button_action(proto, *packet[1:])
wid, button, pressed, pointer, modifiers, buttons = packet[1:7]
device_id = 0
props = {
"modifiers" : modifiers,
"buttons" : buttons,
}
self.do_process_button_action(proto, device_id, wid, button, pressed, pointer, props)

def do_process_button_action(self, proto, wid, button, pressed, pointer, modifiers, *args):
def do_process_button_action(self, proto, device_id, wid, button, pressed, pointer, props):
""" all servers should implement this method """


Expand Down Expand Up @@ -472,9 +497,10 @@ def init_packet_handlers(self):
"layout-changed" : self._process_layout,
"keymap-changed" : self._process_keymap,
#mouse:
"button-action" : self._process_button_action,
"pointer" : self._process_pointer,
"pointer-position" : self._process_pointer_position,
"pointer-button" : self._process_pointer_button, #v5
"button-action" : self._process_button_action, #pre v5
"pointer" : self._process_pointer, #v5
"pointer-position" : self._process_pointer_position, #pre v5
#setup:
"input-devices" : self._process_input_devices,
})
2 changes: 1 addition & 1 deletion xpra/server/rfb/rfb_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def process_pointer_event():
if buttons & mask != self.rfb_buttons & mask:
pressed = bool(buttons & mask)
mouselog(" %spressing button %i", ["un",""][pressed], 1+button)
self.button_action(0, (x, y), 1+button, pressed, -1)
self.button_action(device_id, 0, (x, y), 1+button, pressed)
self.rfb_buttons = buttons
self.idle_add(process_pointer_event)

Expand Down
2 changes: 1 addition & 1 deletion xpra/x11/uinput_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def __init__(self, device, device_path):
if v<=(2, 2):
self.wheel_motion(4, 1)

def click(self, button, pressed, *_args):
def click(self, button, pressed, props):
#this multiplier is based on the values defined in 71-xpra-virtual-pointer.rules as:
#MOUSE_WHEEL_CLICK_COUNT=360
#MOUSE_WHEEL_CLICK_ANGLE=1
Expand Down
Loading

0 comments on commit 5178602

Please sign in to comment.