Skip to content

Commit

Permalink
#1131: correctly handle win32 scrolling events
Browse files Browse the repository at this point in the history
* win32 event handlers now run before the default handler so they can now block propagation by returning any value
* use this to handle mouse wheel events ourselves and prevent GTK from seeing them
* aggregate the distance of all wheel events until we reach the threshold (WHEEL_DELTA)
* then send as many events as needed and store the remainder

git-svn-id: https://xpra.org/svn/Xpra/trunk@12285 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Mar 30, 2016
1 parent 3ca8c9d commit 4ec346c
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 12 deletions.
53 changes: 46 additions & 7 deletions src/xpra/platform/win32/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
grablog = Logger("win32", "grab")
screenlog = Logger("win32", "screen")
keylog = Logger("win32", "keyboard")
mouselog = Logger("win32", "mouse")

from xpra.platform.win32.win32_events import get_win32_event_listener
from xpra.platform.win32.window_hooks import Win32Hooks
Expand All @@ -37,7 +38,7 @@
DPI_AWARE = os.environ.get("XPRA_DPI_AWARE", "1")=="1"
DPI_AWARENESS = int(os.environ.get("XPRA_DPI_AWARENESS", "1"))
FORWARD_WINDOWS_KEY = os.environ.get("XPRA_FORWARD_WINDOWS_KEY", "0")=="1"
WHEEL_DEBUG = os.environ.get("XPRA_WHEEL_DEBUG", "0")=="1"
WHEEL = os.environ.get("XPRA_WHEEL", "1")=="1"


KNOWN_EVENTS = {}
Expand Down Expand Up @@ -377,21 +378,59 @@ def inputlangchange(hwnd, event, wParam, lParam):
log("WM_INPUTLANGCHANGE: character set: %i, input locale identifier: %i", wParam, lParam)
window.keyboard_layout_changed("WM_INPUTLANGCHANGE", wParam, lParam)
win32hooks.add_window_event_handler(win32con.WM_INPUTLANGCHANGE, inputlangchange)
if WHEEL_DEBUG:
#WHEEL_DELTA = 120
def wheel_log(event, wParam, lParam):
if WHEEL:
WHEEL_DELTA = 120
VERTICAL = "vertical"
HORIZONTAL = "horizontal"
class WheelEvent(AdHocStruct):
pass
def handle_wheel(orientation, wParam, lParam):
distance = wParam>>16
keys = wParam & 0xFFFF
y = lParam>>16
x = lParam & 0xFFFF
log.info("%s distance=%.1f, keys=%#x, x=%i, y=%i", event, distance, keys, x, y)
#FIXME: we should reset those values when the window loses focus..
cval = getattr(window, "_win32_%swheel" % orientation, 0)
nval = cval + distance
units = nval // WHEEL_DELTA
client = getattr(window, "_client")
wid = getattr(window, "_id", 0)
mouselog("mousewheel: orientation=%s distance=%.1f, units=%i, new value=%.1f, keys=%#x, x=%i, y=%i, client=%s, wid=%i", orientation, distance, units, nval, keys, x, y, client, wid)
if units!=0 and client and wid>0:
if orientation==VERTICAL:
button = 4 + int(units<0) #4 for UP, 5 for DOWN
else:
button = 6 + int(units<0) #6 for LEFT, 7 for RIGHT
buttons = []
modifiers = client.get_current_modifiers()
def send_button(pressed):
client.send_button(wid, button, pressed, (x, y), modifiers, buttons)
count = 0
v = nval
while abs(v)>=WHEEL_DELTA:
send_button(True)
send_button(False)
if v>0:
v -= WHEEL_DELTA
else:
v += WHEEL_DELTA
count += 1
mouselog("mousewheel: send %i wheel events to the server for distance=%s, remainder=%s", count, nval, v)
setattr(window, "_win32_%swheel" % orientation, v)
def mousewheel(hwnd, event, wParam, lParam):
wheel_log("MOUSEWHEEL", wParam, lParam)
handle_wheel(VERTICAL, wParam, lParam)
return 0
def mousehwheel(hwnd, event, wParam, lParam):
wheel_log("MOUSEHWHEEL", wParam, lParam)
handle_wheel(HORIZONTAL, wParam, lParam)
return 0
WM_MOUSEHWHEEL = 0x020E
win32hooks.add_window_event_handler(win32con.WM_MOUSEWHEEL, mousewheel)
win32hooks.add_window_event_handler(WM_MOUSEHWHEEL, mousehwheel)
def reset_wheel_counters(*args):
mouselog("window lost focus, resetting current wheel deltas")
for orientation in (VERTICAL, HORIZONTAL):
setattr(window, "_win32_%swheel" % orientation, 0)
window.connect("focus-out-event", reset_wheel_counters)


def remove_window_hooks(window):
Expand Down
18 changes: 13 additions & 5 deletions src/xpra/platform/win32/window_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def on_getminmaxinfo(self, hwnd, msg, wparam, lparam):
info.ptMaxSize = point
info.ptMaxTrackSize = point
log("on_getminmaxinfo window=%#x max_size=%s, frame=%sx%s, minmaxinfo size=%sx%s", hwnd, self.max_size, fw, fh, w, h)
else:
log("on_getminmaxinfo window=%#x max_size=%s", hwnd, self.max_size)
return 0
log("on_getminmaxinfo window=%#x max_size=%s", hwnd, self.max_size)

def cleanup(self, *args):
log("cleanup%s", args)
Expand All @@ -107,10 +107,18 @@ def cleanup(self, *args):
def _wndproc(self, hwnd, msg, wparam, lparam):
event_name = WNDPROC_EVENT_NAMES.get(msg, msg)
callback = self._message_map.get(msg)
v = CallWindowProc(self._oldwndproc, hwnd, msg, wparam, lparam)
vlog("_wndproc%s event name=%s, callback=%s", (hwnd, msg, wparam, lparam), event_name, callback)
v = None
if callback:
#run our callback
callback(hwnd, msg, wparam, lparam)
vlog("_wndproc%s return value=%s", (hwnd, msg, wparam, lparam), v)
try:
v = callback(hwnd, msg, wparam, lparam)
vlog("%s=%s", callback, (hwnd, msg, wparam, lparam), v)
except Exception as e:
log.error("Error: callback %s failed:", callback)
log.error(" %s", e)
#if our callback doesn't define the return value, use the default handler:
if v is None:
v = CallWindowProc(self._oldwndproc, hwnd, msg, wparam, lparam)
vlog("_wndproc%s return value=%s", (hwnd, msg, wparam, lparam), v)
return v

0 comments on commit 4ec346c

Please sign in to comment.