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