use netsurf's mousevent

This commit is contained in:
Karl Seguin
2025-04-07 11:50:45 +08:00
parent 0253de80de
commit b76875bf5d
4 changed files with 113 additions and 21 deletions

View File

@@ -431,14 +431,34 @@ pub const Page = struct {
navigate: std.Uri,
};
pub fn click(self: *Page, allocator: Allocator, x: u32, y: u32) !?ClickResult {
const element = self.renderer.getElementAtPosition(x, y) orelse return null;
pub const MouseEvent = struct {
x: i32,
y: i32,
type: Type,
const event = try parser.eventCreate();
defer parser.eventDestroy(event);
const Type = enum {
pressed,
released,
};
};
try parser.eventInit(event, "click", .{ .bubbles = true, .cancelable = true });
if ((try parser.eventDefaultPrevented(event)) == true) {
pub fn mouseEvent(self: *Page, allocator: Allocator, me: MouseEvent) !?ClickResult {
if (me.type != .pressed) {
return null;
}
const element = self.renderer.getElementAtPosition(me.x, me.y) orelse return null;
const event = try parser.mouseEventCreate();
defer parser.mouseEventDestroy(event);
try parser.mouseEventInit(event, "click", .{
.bubbles = true,
.cancelable = true,
.x = me.x,
.y = me.y,
});
if ((try parser.mouseEventDefaultPrevented(event)) == true) {
return null;
}
@@ -838,13 +858,13 @@ const FlatRenderer = struct {
return 1;
}
pub fn getElementAtPosition(self: *const FlatRenderer, x: u32, y: u32) ?*parser.Element {
if (y > 1) {
pub fn getElementAtPosition(self: *const FlatRenderer, x: i32, y: i32) ?*parser.Element {
if (y != 1 or x < 0) {
return null;
}
const elements = self.elements.items;
return if (x < elements.len) @ptrFromInt(elements[x]) else null;
return if (x < elements.len) @ptrFromInt(elements[@intCast(x)]) else null;
}
};

View File

@@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
const Page = @import("../../browser/browser.zig").Page;
pub fn processMessage(cmd: anytype) !void {
const action = std.meta.stringToEnum(enum {
@@ -31,20 +32,39 @@ pub fn processMessage(cmd: anytype) !void {
// https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchMouseEvent
fn dispatchMouseEvent(cmd: anytype) !void {
const params = (try cmd.params(struct {
type: []const u8,
x: u32,
y: u32,
x: i32,
y: i32,
type: Type,
const Type = enum {
mousePressed,
mouseReleased,
mouseMoved,
mouseWheel,
};
})) orelse return error.InvalidParams;
try cmd.sendResult(null, .{});
if (std.ascii.eqlIgnoreCase(params.type, "mousePressed") == false) {
return;
// quickly ignore types we know we don't handle
switch (params.type) {
.mouseMoved, .mouseWheel => return,
else => {},
}
const bc = cmd.browser_context orelse return;
const page = bc.session.currentPage() orelse return;
const click_result = (try page.click(cmd.arena, params.x, params.y)) orelse return;
const mouse_event = Page.MouseEvent{
.x = params.x,
.y = params.y,
.type = switch (params.type) {
.mousePressed => .pressed,
.mouseReleased => .released,
else => unreachable,
},
};
const click_result = (try page.mouseEvent(cmd.arena, mouse_event)) orelse return;
switch (click_result) {
.navigate => |uri| try clickNavigate(cmd, uri),

View File

@@ -24,6 +24,7 @@ const c = @cImport({
@cInclude("dom/bindings/hubbub/parser.h");
@cInclude("events/event_target.h");
@cInclude("events/event.h");
@cInclude("events/mouse_event.h");
});
const mimalloc = @import("mimalloc");
@@ -809,14 +810,10 @@ const DispatchOpts = struct {
pub fn elementDispatchEvent(element: *Element, opts: DispatchOpts) !bool {
const event = try eventCreate();
defer eventDestroy(event);
try eventInit(event, opts.type, .{ .bubbles = opts.bubbles, .cancelable = opts.cancelable });
var res: bool = undefined;
const et: *EventTarget = @ptrCast(element);
const err = eventTargetVtable(et).dispatch_event.?(et, event, &res);
try DOMErr(err);
return res;
return eventTargetDispatchEvent(et, event);
}
pub fn eventTargetTBaseFieldName(comptime T: type) ?[]const u8 {
@@ -878,6 +875,61 @@ pub const EventTargetTBase = extern struct {
}
};
// MouseEvent
pub const MouseEvent = c.dom_mouse_event;
pub fn mouseEventCreate() !*MouseEvent {
var evt: ?*MouseEvent = undefined;
const err = c._dom_mouse_event_create(&evt);
try DOMErr(err);
return evt.?;
}
pub fn mouseEventDestroy(evt: *MouseEvent) void {
c._dom_mouse_event_destroy(evt);
}
const MouseEventOpts = struct {
x: i32,
y: i32,
bubbles: bool = false,
cancelable: bool = false,
ctrl: bool = false,
alt: bool = false,
shift: bool = false,
meta: bool = false,
button: u16 = 0,
click_count: u16 = 1,
};
pub fn mouseEventInit(evt: *MouseEvent, typ: []const u8, opts: MouseEventOpts) !void {
const s = try strFromData(typ);
const err = c._dom_mouse_event_init(
evt,
s,
opts.bubbles,
opts.cancelable,
null, // dom_abstract_view* ?
opts.click_count, // details
opts.x, // screen_x
opts.y, // screen_y
opts.x, // client_x
opts.y, // client_y
opts.ctrl,
opts.alt,
opts.shift,
opts.meta,
opts.button,
null, // related target
);
try DOMErr(err);
}
pub fn mouseEventDefaultPrevented(evt: *MouseEvent) !bool {
return eventDefaultPrevented(@ptrCast(evt));
}
// NodeType
pub const NodeType = enum(u4) {