2024-04-19 15:48 BST

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0002843NetSurf[All Projects] Generalpublic2022-08-28 16:51
ReporterCameron Cawley 
Assigned To 
SeverityminorReproducibilityhave not tried 
StatusacknowledgedResolutionopen 
Product Version3.11 
Target VersionFixed in Version 
Summary0002843: [PATCH] windows: Improve keyboard and mouse input in core windows
DescriptionThis patch implements mouse dragging and modifiers, as well as keyboard input.
TagsNo tags attached.
Fixed in CI build #
Reported in CI build #
URL of problem page
Attached Files
  • patch file icon 0001-windows-Improve-keyboard-and-mouse-input-in-core-win.patch (11,069 bytes) 2022-02-19 21:27 -
    From 17725fba789c83855bbadd31c74b3e525489d136 Mon Sep 17 00:00:00 2001
    From: Cameron Cawley <ccawley2011@gmail.com>
    Date: Sat, 19 Feb 2022 15:47:36 +0000
    Subject: [PATCH] windows: Improve keyboard and mouse input in core windows
    
    ---
     frontends/windows/corewindow.c | 302 ++++++++++++++++++++++++++++++++-
     frontends/windows/corewindow.h |  15 ++
     2 files changed, 309 insertions(+), 8 deletions(-)
    
    diff --git a/frontends/windows/corewindow.c b/frontends/windows/corewindow.c
    index 9a26efb43..1287966db 100644
    --- a/frontends/windows/corewindow.c
    +++ b/frontends/windows/corewindow.c
    @@ -300,10 +300,11 @@ nsw32_corewindow_hscroll(struct nsw32_corewindow *nsw32_cw,
     
     static LRESULT
     nsw32_corewindow_mousedown(struct nsw32_corewindow *nsw32_cw,
    -			 HWND hwnd,
    +			   HWND hwnd,
     			   int x, int y,
     			   browser_mouse_state button)
     {
    +	struct nsw32_corewindow_mouse *mouse = &nsw32_cw->mouse_state;
     	SCROLLINFO si; /* scroll information */
     
     	/* get scroll positions */
    @@ -314,7 +315,21 @@ nsw32_corewindow_mousedown(struct nsw32_corewindow *nsw32_cw,
     	GetScrollInfo(hwnd, SB_VERT, &si);
     	y += si.nPos;
     
    -	nsw32_cw->mouse(nsw32_cw, button, x, y);
    +	/* record event information for potentially starting a drag. */
    +	mouse->pressed_x = mouse->last_x = x;
    +	mouse->pressed_y = mouse->last_y = y;
    +	mouse->pressed = true;
    +
    +	mouse->state = button;
    +	if ((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000)
    +		mouse->state |= BROWSER_MOUSE_MOD_1;
    +	if ((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000)
    +		mouse->state |= BROWSER_MOUSE_MOD_2;
    +	if ((GetKeyState(VK_MENU) & 0x8000) == 0x8000)
    +		mouse->state |= BROWSER_MOUSE_MOD_3;
    +
    +	nsw32_cw->mouse(nsw32_cw, mouse->state, x, y);
    +
     	return 0;
     }
     
    @@ -324,6 +339,82 @@ nsw32_corewindow_mouseup(struct nsw32_corewindow *nsw32_cw,
     			 int x, int y,
     			 browser_mouse_state button)
     {
    +	struct nsw32_corewindow_mouse *mouse = &nsw32_cw->mouse_state;
    +	bool was_drag = false;
    +	SCROLLINFO si; /* scroll information */
    +
    +	/* get scroll positions */
    +	si.cbSize = sizeof(si);
    +	si.fMask = SIF_POS;
    +	GetScrollInfo(hwnd, SB_HORZ, &si);
    +	x += si.nPos;
    +	GetScrollInfo(hwnd, SB_VERT, &si);
    +	y += si.nPos;
    +
    +	/* only button 1 clicks are considered double clicks. If the
    +	 * mouse state is PRESS then we are waiting for a release to
    +	 * emit a click event, otherwise just reset the state to nothing.
    +	 */
    +	if (mouse->state & BROWSER_MOUSE_DOUBLE_CLICK) {
    +		if (mouse->state & BROWSER_MOUSE_PRESS_1) {
    +			mouse->state ^= BROWSER_MOUSE_PRESS_1 |
    +					BROWSER_MOUSE_CLICK_1;
    +		} else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
    +			mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
    +					BROWSER_MOUSE_CLICK_2 |
    +					BROWSER_MOUSE_DOUBLE_CLICK);
    +		}
    +	} else if (mouse->state & BROWSER_MOUSE_PRESS_1) {
    +		mouse->state ^= (BROWSER_MOUSE_PRESS_1 |
    +				 BROWSER_MOUSE_CLICK_1);
    +	} else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
    +		mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
    +				 BROWSER_MOUSE_CLICK_2);
    +	} else if (mouse->state & BROWSER_MOUSE_HOLDING_1) {
    +		mouse->state ^= (BROWSER_MOUSE_HOLDING_1 |
    +				 BROWSER_MOUSE_DRAG_ON);
    +		was_drag = true;
    +	} else if (mouse->state & BROWSER_MOUSE_HOLDING_2) {
    +		mouse->state ^= (BROWSER_MOUSE_HOLDING_2 |
    +				 BROWSER_MOUSE_DRAG_ON);
    +		was_drag = true;
    +	}
    +
    +	/* Handle modifiers being removed */
    +	if ((mouse->state & BROWSER_MOUSE_MOD_1) &&
    +	    !((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000)) {
    +		mouse->state ^= BROWSER_MOUSE_MOD_1;
    +	}
    +	if ((mouse->state & BROWSER_MOUSE_MOD_2) &&
    +	    !((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000)) {
    +		mouse->state ^= BROWSER_MOUSE_MOD_2;
    +	}
    +	if ((mouse->state & BROWSER_MOUSE_MOD_3) &&
    +	    !((GetKeyState(VK_MENU) & 0x8000) == 0x8000)) {
    +		mouse->state ^= BROWSER_MOUSE_MOD_3;
    +	}
    +
    +	/* end drag with modifiers */
    +	if (was_drag && (mouse->state & (
    +			BROWSER_MOUSE_MOD_1 |
    +			BROWSER_MOUSE_MOD_2 |
    +			BROWSER_MOUSE_MOD_3))) {
    +		mouse->state = BROWSER_MOUSE_HOVER;
    +	}
    +
    +	nsw32_cw->mouse(nsw32_cw, mouse->state, x, y);
    +
    +	mouse->pressed = false;
    +
    +	return 0;
    +}
    +
    +static LRESULT
    +nsw32_corewindow_mousemove(struct nsw32_corewindow *nsw32_cw,
    +			   HWND hwnd,
    +			   int x, int y)
    +{
    +	struct nsw32_corewindow_mouse *mouse = &nsw32_cw->mouse_state;
     	SCROLLINFO si; /* scroll information */
     
     	/* get scroll positions */
    @@ -334,7 +425,175 @@ nsw32_corewindow_mouseup(struct nsw32_corewindow *nsw32_cw,
     	GetScrollInfo(hwnd, SB_VERT, &si);
     	y += si.nPos;
     
    -	nsw32_cw->mouse(nsw32_cw, button, x, y);
    +	if (!mouse->pressed) {
    +		nsw32_cw->mouse(nsw32_cw,
    +				BROWSER_MOUSE_HOVER,
    +				x,
    +				y);
    +		return 0;
    +	}
    +
    +	if ((abs(x - mouse->last_x) < 5) &&
    +	    (abs(y - mouse->last_y) < 5)) {
    +		/* Mouse hasn't moved far enough from press coordinate
    +		 * for this to be considered a drag.
    +		 */
    +		return 1;
    +	}
    +
    +	/* This is a drag, ensure it's always treated as such, even if
    +	 * we drag back over the press location.
    +	 */
    +	mouse->last_x = INT_MIN;
    +	mouse->last_y = INT_MIN;
    +
    +
    +	if (mouse->state & BROWSER_MOUSE_PRESS_1) {
    +		/* Start button 1 drag */
    +		nsw32_cw->mouse(nsw32_cw,
    +				BROWSER_MOUSE_DRAG_1,
    +				mouse->pressed_x,
    +				mouse->pressed_y);
    +
    +		/* Replace PRESS with HOLDING and declare drag in progress */
    +		mouse->state ^= (BROWSER_MOUSE_PRESS_1 |
    +				 BROWSER_MOUSE_HOLDING_1);
    +		mouse->state |= BROWSER_MOUSE_DRAG_ON;
    +
    +	} else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
    +		/* Start button 2s drag */
    +		nsw32_cw->mouse(nsw32_cw,
    +				BROWSER_MOUSE_DRAG_2,
    +				mouse->pressed_x,
    +				mouse->pressed_y);
    +
    +		/* Replace PRESS with HOLDING and declare drag in progress */
    +		mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
    +				 BROWSER_MOUSE_HOLDING_2);
    +		mouse->state |= BROWSER_MOUSE_DRAG_ON;
    +
    +	} else {
    +		/* continue drag */
    +
    +		/* Handle modifiers being removed */
    +		if ((mouse->state & BROWSER_MOUSE_MOD_1) &&
    +		    !((GetKeyState(VK_SHIFT) & 0x8000) == 0x8000)) {
    +			mouse->state ^= BROWSER_MOUSE_MOD_1;
    +		}
    +		if ((mouse->state & BROWSER_MOUSE_MOD_2) &&
    +		    !((GetKeyState(VK_CONTROL) & 0x8000) == 0x8000)) {
    +			mouse->state ^= BROWSER_MOUSE_MOD_2;
    +		}
    +		if ((mouse->state & BROWSER_MOUSE_MOD_3) &&
    +		    !((GetKeyState(VK_MENU) & 0x8000) == 0x8000)) {
    +			mouse->state ^= BROWSER_MOUSE_MOD_3;
    +		}
    +
    +		if (mouse->state &
    +		    (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2)) {
    +			nsw32_cw->mouse(nsw32_cw,
    +					mouse->state,
    +					x, y);
    +		}
    +	}
    +
    +	return 0;
    +}
    +
    +static LRESULT
    +nsw32_corewindow_unichar(struct nsw32_corewindow *nsw32_cw, WPARAM wparam)
    +{
    +	uint32_t nskey;
    +
    +	if (wparam == UNICODE_NOCHAR) {
    +		return 1;
    +	}
    +
    +	nskey = wparam;
    +	nsw32_cw->key(nsw32_cw, nskey);
    +	return 0;
    +}
    +
    +static LRESULT
    +nsw32_corewindow_char(struct nsw32_corewindow *nsw32_cw, WPARAM wparam)
    +{
    +	uint32_t nskey;
    +
    +	nskey = wparam;
    +
    +	const uint32_t utf16_hi_surrogate_start = 0xD800;
    +	const uint32_t utf16_lo_surrogate_start = 0xDC00;
    +	const uint32_t utf16_surrogate_end = 0xDFFF;
    +
    +	static uint32_t highSurrogate = 0;
    +
    +	if ((nskey >= utf16_hi_surrogate_start) &&
    +	    (nskey < utf16_lo_surrogate_start) ) {
    +		highSurrogate = nskey;
    +	} else {
    +		if ((nskey >= utf16_lo_surrogate_start) &&
    +		    (nskey <= utf16_surrogate_end)) {
    +			uint32_t lowSurrogate = nskey;
    +			nskey = (highSurrogate - utf16_hi_surrogate_start) << 10;
    +			nskey |= ( lowSurrogate - utf16_lo_surrogate_start );
    +			nskey += 0x10000;
    +		}
    +		highSurrogate = 0;
    +
    +		nsw32_cw->key(nsw32_cw, nskey);
    +	}
    +
    +	return 0;
    +}
    +
    +static LRESULT
    +nsw32_corewindow_keydown(struct nsw32_corewindow *nsw32_cw, WPARAM wparam)
    +{
    +	uint32_t i;
    +
    +	switch(wparam) {
    +	case VK_LEFT:
    +		i = NS_KEY_LEFT;
    +		break;
    +
    +	case VK_RIGHT:
    +		i = NS_KEY_RIGHT;
    +		break;
    +
    +	case VK_UP:
    +		i = NS_KEY_UP;
    +		break;
    +
    +	case VK_DOWN:
    +		i = NS_KEY_DOWN;
    +		break;
    +
    +	case VK_HOME:
    +		i = NS_KEY_LINE_START;
    +		break;
    +
    +	case VK_END:
    +		i = NS_KEY_LINE_END;
    +		break;
    +
    +	case VK_DELETE:
    +		i = NS_KEY_DELETE_RIGHT;
    +		break;
    +
    +	case VK_NEXT:
    +		i = NS_KEY_PAGE_DOWN;
    +		break;
    +
    +	case VK_PRIOR:
    +		i = NS_KEY_PAGE_UP;
    +		break;
    +
    +	default:
    +		return 1;
    +	}
    +
    +	nsw32_cw->key(nsw32_cw, i);
    +
     	return 0;
     }
     
    @@ -383,6 +642,11 @@ nsw32_window_corewindow_event_callback(HWND hwnd,
     		case WM_HSCROLL:
     			return nsw32_corewindow_hscroll(nsw32_cw, hwnd, wparam);
     
    +		case WM_MOUSEMOVE:
    +			return nsw32_corewindow_mousemove(nsw32_cw, hwnd,
    +							  GET_X_LPARAM(lparam),
    +							  GET_Y_LPARAM(lparam));
    +
     		case WM_LBUTTONDOWN:
     			return nsw32_corewindow_mousedown(nsw32_cw, hwnd,
     							  GET_X_LPARAM(lparam),
    @@ -395,6 +659,18 @@ nsw32_window_corewindow_event_callback(HWND hwnd,
     							   GET_Y_LPARAM(lparam),
     							   BROWSER_MOUSE_PRESS_2);
     
    +		case WM_LBUTTONDBLCLK:
    +			return nsw32_corewindow_mousedown(nsw32_cw, hwnd,
    +							  GET_X_LPARAM(lparam),
    +							  GET_Y_LPARAM(lparam),
    +							  BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_DOUBLE_CLICK);
    +
    +		case WM_RBUTTONDBLCLK:
    +			return nsw32_corewindow_mousedown(nsw32_cw, hwnd,
    +							   GET_X_LPARAM(lparam),
    +							   GET_Y_LPARAM(lparam),
    +							   BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_DOUBLE_CLICK);
    +
     		case WM_LBUTTONUP:
     			return nsw32_corewindow_mouseup(nsw32_cw, hwnd,
     							GET_X_LPARAM(lparam),
    @@ -407,6 +683,18 @@ nsw32_window_corewindow_event_callback(HWND hwnd,
     							GET_Y_LPARAM(lparam),
     							BROWSER_MOUSE_CLICK_2);
     
    +		case WM_KEYDOWN:
    +			if (nsw32_corewindow_keydown(nsw32_cw, wparam) == 0) {
    +				return 0;
    +			}
    +			break;
    +
    +		case WM_CHAR:
    +			return nsw32_corewindow_char(nsw32_cw, wparam);
    +
    +		case WM_UNICHAR:
    +			return nsw32_corewindow_unichar(nsw32_cw, wparam);
    +
     		case WM_CLOSE:
     			return nsw32_corewindow_close(nsw32_cw);
     		}
    @@ -550,15 +838,13 @@ nsw32_corewindow_init(HINSTANCE hInstance,
     
     	if (hWndParent != NULL) {
     		dwStyle = WS_CHILDWINDOW |
    -			WS_VISIBLE |
    -			CS_DBLCLKS;
    +			WS_VISIBLE;
     	} else {
     		dwStyle = WS_OVERLAPPEDWINDOW |
     			WS_HSCROLL |
     			WS_VSCROLL |
     			WS_CLIPSIBLINGS |
    -			WS_CLIPCHILDREN |
    -			CS_DBLCLKS;
    +			WS_CLIPCHILDREN;
     	}
     
     	NSLOG(netsurf, INFO, "creating hInstance %p core window", hInstance);
    @@ -607,7 +893,7 @@ nserror nsw32_create_corewindow_class(HINSTANCE hInstance)
     
     	/* drawable area */
     	wc.cbSize = sizeof(WNDCLASSEX);
    -	wc.style = 0;
    +	wc.style = CS_DBLCLKS;
     	wc.lpfnWndProc = nsw32_window_corewindow_event_callback;
     	wc.cbClsExtra = 0;
     	wc.cbWndExtra = 0;
    diff --git a/frontends/windows/corewindow.h b/frontends/windows/corewindow.h
    index b91787a85..4678f5b50 100644
    --- a/frontends/windows/corewindow.h
    +++ b/frontends/windows/corewindow.h
    @@ -21,6 +21,18 @@
     
     #include "netsurf/core_window.h"
     
    +/**
    + * nsw32 core window mouse state
    + */
    +struct nsw32_corewindow_mouse {
    +	browser_mouse_state state; /**< last event status */
    +	bool pressed;
    +	int pressed_x;
    +	int pressed_y;
    +	int last_x;
    +	int last_y;
    +};
    +
     /**
      * nsw32 core window state
      */
    @@ -40,6 +52,9 @@ struct nsw32_corewindow {
     	/** window menu */
     	HMENU menu;
     
    +	/** mouse state */
    +	struct nsw32_corewindow_mouse mouse_state;
    +
             /** drag status set by core */
             core_window_drag_status drag_status;
     
    -- 
    2.30.2
    
    

-Relationships
+Relationships

-Notes
Vincent Sanders

~0002403

Vincent Sanders (administrator)

inspected patch, looks reasonable
+Notes

-Issue History
Date Modified Username Field Change
2022-02-19 21:27 Cameron Cawley New Issue
2022-02-19 21:27 Cameron Cawley File Added: 0001-windows-Improve-keyboard-and-mouse-input-in-core-win.patch
2022-08-28 16:44 Vincent Sanders Project Buildsystem => NetSurf
2022-08-28 16:51 Vincent Sanders Status new => acknowledged
2022-08-28 16:51 Vincent Sanders Product Version => 3.11
2022-08-28 16:51 Vincent Sanders Note Added: 0002403
+Issue History