implement KeyboardEvent properties and methods

This commit is contained in:
nikneym
2025-09-11 13:13:36 +03:00
parent 68e237eec5
commit f79f25bcf4
3 changed files with 148 additions and 57 deletions

View File

@@ -18,24 +18,12 @@
const std = @import("std");
const log = @import("../../log.zig");
const builtin = @import("builtin");
const netsurf = @import("../netsurf.zig");
const Event = @import("event.zig").Event;
const JsObject = @import("../env.zig").JsObject;
const c = @cImport({
@cInclude("dom/dom.h");
@cInclude("core/pi.h");
@cInclude("dom/bindings/hubbub/parser.h");
@cInclude("events/event_target.h");
@cInclude("events/event.h");
@cInclude("events/mouse_event.h");
@cInclude("events/keyboard_event.h");
@cInclude("utils/validate.h");
@cInclude("html/html_element.h");
@cInclude("html/html_document.h");
});
// TODO: We currently don't have a UIEvent interface so we skip it in the prototype chain.
// https://developer.mozilla.org/en-US/docs/Web/API/UIEvent
const UIEvent = Event;
@@ -45,51 +33,125 @@ pub const KeyboardEvent = struct {
pub const Self = netsurf.KeyboardEvent;
pub const prototype = *UIEvent;
pub const KeyLocationCode = enum(u16) {
standard = 0x00,
left = 0x01,
right = 0x02,
numpad = 0x03,
mobile = 0x04, // Non-standard, deprecated.
joystick = 0x05, // Non-standard, deprecated.
};
pub const ConstructorOptions = struct {
key: []const u8 = "",
code: []const u8 = "",
location: KeyLocationCode = .standard,
char_code: u32 = 0,
key_code: u32 = 0,
which: u32 = 0,
location: netsurf.KeyboardEventOpts.LocationCode = .standard,
repeat: bool = false,
ctrl_key: bool = false,
shift_key: bool = false,
alt_key: bool = false,
meta_key: bool = false,
is_composing: bool = false,
isComposing: bool = false,
// Currently not supported but we take as argument.
charCode: u32 = 0,
// Currently not supported but we take as argument.
keyCode: u32 = 0,
// Currently not supported but we take as argument.
which: u32 = 0,
ctrlKey: bool = false,
shiftKey: bool = false,
altKey: bool = false,
metaKey: bool = false,
};
pub fn constructor(event_type: []const u8, maybe_options: ?ConstructorOptions) !*netsurf.KeyboardEvent {
const options = maybe_options orelse ConstructorOptions{};
const options: ConstructorOptions = maybe_options orelse .{};
var event = try netsurf.keyboardEventCreate();
try netsurf.eventSetInternalType(@ptrCast(&event), .keyboard_event);
const event = try netsurf.keyboardEventCreate();
try netsurf.keyboardEventInit(
event,
event_type,
.{
.bubbles = false,
.cancelable = false,
.key = options.key,
.code = options.code,
.alt = options.alt_key,
.ctrl = options.ctrl_key,
.meta = options.meta_key,
.shift = options.shift_key,
.location = options.location,
.repeat = options.repeat,
.is_composing = options.isComposing,
.ctrl_key = options.ctrlKey,
.shift_key = options.shiftKey,
.alt_key = options.altKey,
.meta_key = options.metaKey,
},
);
return event;
}
// Returns the modifier state for given modifier key.
pub fn _getModifierState(self: *Self, key: []const u8) bool {
// Chrome and Firefox do case-sensitive match, here we prefer the same.
if (std.mem.eql(u8, key, "Alt")) {
return get_altKey(self);
}
if (std.mem.eql(u8, key, "AltGraph")) {
return (get_altKey(self) and get_ctrlKey(self));
}
if (std.mem.eql(u8, key, "Control")) {
return get_ctrlKey(self);
}
if (std.mem.eql(u8, key, "Shift")) {
return get_shiftKey(self);
}
if (std.mem.eql(u8, key, "Meta") or std.mem.eql(u8, key, "OS")) {
return get_metaKey(self);
}
// Special case for IE.
if (comptime builtin.os.tag == .windows) {
if (std.mem.eql(u8, key, "Win")) {
return get_metaKey(self);
}
}
// getModifierState() also accepts a deprecated virtual modifier named "Accel".
// event.getModifierState("Accel") returns true when at least one of
// KeyboardEvent.ctrlKey or KeyboardEvent.metaKey is true.
//
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState#accel_virtual_modifier
if (std.mem.eql(u8, key, "Accel")) {
return (get_ctrlKey(self) or get_metaKey(self));
}
// TODO: Add support for "CapsLock", "ScrollLock".
return false;
}
// Getters.
pub fn get_altKey(self: *Self) bool {
return netsurf.keyboardEventKeyIsSet(self, .alt);
}
pub fn get_ctrlKey(self: *Self) bool {
return netsurf.keyboardEventKeyIsSet(self, .ctrl);
}
pub fn get_metaKey(self: *Self) bool {
return netsurf.keyboardEventKeyIsSet(self, .meta);
}
pub fn get_shiftKey(self: *Self) bool {
return netsurf.keyboardEventKeyIsSet(self, .shift);
}
pub fn get_isComposing(self: *Self) bool {
return self.is_composing;
}
pub fn get_location(self: *Self) u32 {
return self.location;
}
pub fn get_key(self: *Self) ![]const u8 {
return netsurf.keyboardEventGetKey(self);
}
pub fn get_repeat(self: *Self) bool {
return self.repeat;
}
};
const testing = @import("../../testing.zig");

View File

@@ -952,15 +952,44 @@ pub fn keyboardEventDestroy(evt: *KeyboardEvent) void {
c._dom_keyboard_event_destroy(evt);
}
const KeyboardEventOpts = struct {
key: []const u8,
code: []const u8,
pub inline fn keyboardEventKeyIsSet(
evt: *KeyboardEvent,
comptime key: enum { ctrl, alt, shift, meta },
) bool {
var is_set: bool = false;
const err = switch (key) {
.ctrl => c._dom_keyboard_event_get_ctrl_key(evt, &is_set),
.alt => c._dom_keyboard_event_get_alt_key(evt, &is_set),
.shift => c._dom_keyboard_event_get_shift_key(evt, &is_set),
.meta => c._dom_keyboard_event_get_meta_key(evt, &is_set),
};
// None of the earlier can fail.
std.debug.assert(err == c.DOM_NO_ERR);
return is_set;
}
pub const KeyboardEventOpts = struct {
key: []const u8 = "",
code: []const u8 = "",
location: LocationCode = .standard,
repeat: bool = false,
bubbles: bool = false,
cancelable: bool = false,
ctrl: bool = false,
alt: bool = false,
shift: bool = false,
meta: bool = false,
is_composing: bool = false,
ctrl_key: bool = false,
alt_key: bool = false,
shift_key: bool = false,
meta_key: bool = false,
pub const LocationCode = enum(u32) {
standard = c.DOM_KEY_LOCATION_STANDARD,
left = c.DOM_KEY_LOCATION_LEFT,
right = c.DOM_KEY_LOCATION_RIGHT,
numpad = c.DOM_KEY_LOCATION_NUMPAD,
mobile = 0x04, // Non-standard, deprecated.
joystick = 0x05, // Non-standard, deprecated.
};
};
pub fn keyboardEventInit(evt: *KeyboardEvent, typ: []const u8, opts: KeyboardEventOpts) !void {
@@ -973,13 +1002,13 @@ pub fn keyboardEventInit(evt: *KeyboardEvent, typ: []const u8, opts: KeyboardEve
null, // dom_abstract_view* ?
try strFromData(opts.key),
try strFromData(opts.code),
0, // location 0 == standard
opts.ctrl,
opts.shift,
opts.alt,
opts.meta,
false, // repease
false, // is_composiom
@intFromEnum(opts.location),
opts.ctrl_key,
opts.shift_key,
opts.alt_key,
opts.meta_key,
opts.repeat, // repease
opts.is_composing, // is_composiom
);
try DOMErr(err);
}

View File

@@ -942,10 +942,10 @@ pub const Page = struct {
.cancelable = true,
.key = kbe.key,
.code = kbe.code,
.alt = kbe.alt,
.ctrl = kbe.ctrl,
.meta = kbe.meta,
.shift = kbe.shift,
.alt_key = kbe.alt,
.ctrl_key = kbe.ctrl,
.meta_key = kbe.meta,
.shift_key = kbe.shift,
});
_ = try parser.elementDispatchEvent(element, @ptrCast(event));
}