diff --git a/src/ecmascript/spidermonkey/Makefile b/src/ecmascript/spidermonkey/Makefile index 58c9fad7..08670e7f 100644 --- a/src/ecmascript/spidermonkey/Makefile +++ b/src/ecmascript/spidermonkey/Makefile @@ -3,6 +3,6 @@ include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) OBJS = attr.obj attributes.obj collection.obj console.obj document.obj element.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \ - location.obj localstorage.obj navigator.obj nodelist.obj screen.obj unibar.obj window.obj xhr.obj + keyboard.obj location.obj localstorage.obj navigator.obj nodelist.obj screen.obj unibar.obj window.obj xhr.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/spidermonkey/element.cpp b/src/ecmascript/spidermonkey/element.cpp index c8492f36..e8efb71f 100644 --- a/src/ecmascript/spidermonkey/element.cpp +++ b/src/ecmascript/spidermonkey/element.cpp @@ -29,6 +29,7 @@ #include "ecmascript/spidermonkey/collection.h" #include "ecmascript/spidermonkey/element.h" #include "ecmascript/spidermonkey/heartbeat.h" +#include "ecmascript/spidermonkey/keyboard.h" #include "ecmascript/spidermonkey/nodelist.h" #include "ecmascript/spidermonkey/window.h" #include "intl/libintl.h" @@ -3508,8 +3509,9 @@ getElement(JSContext *ctx, void *node) } void -check_element_event(void *elem, const char *event_name) +check_element_event(void *elem, const char *event_name, struct term_event *ev) { + JSObject *obj; auto el = map_privates.find(elem); if (el == map_privates.end()) { @@ -3528,7 +3530,17 @@ check_element_event(void *elem, const char *event_name) if (strcmp(l->typ, event_name)) { continue; } - JS_CallFunctionValue(ctx, el_private->thisval, l->fun, JS::HandleValueArray::empty(), &r_val); + if (ev && ev->ev == EVENT_KBD && (!strcmp(event_name, "keydown") || !strcmp(event_name, "keyup"))) { + JS::RootedValueVector argv(ctx); + if (!argv.resize(1)) { + return; + } + obj = get_keyboardEvent(ctx, ev); + argv[0].setObject(*obj); + JS_CallFunctionValue(ctx, el_private->thisval, l->fun, argv, &r_val); + } else { + JS_CallFunctionValue(ctx, el_private->thisval, l->fun, JS::HandleValueArray::empty(), &r_val); + } } done_heartbeat(interpreter->heartbeat); JS::LeaveRealm(ctx, comp); diff --git a/src/ecmascript/spidermonkey/element.h b/src/ecmascript/spidermonkey/element.h index b50fdebc..67c06fca 100644 --- a/src/ecmascript/spidermonkey/element.h +++ b/src/ecmascript/spidermonkey/element.h @@ -3,6 +3,7 @@ #include "ecmascript/spidermonkey/util.h" +struct term_event; extern JSClass element_class; extern JSPropertySpec element_props[]; @@ -10,6 +11,6 @@ JSObject *getElement(JSContext *ctx, void *node); void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false); -void check_element_event(void *elem, const char *event_name); +void check_element_event(void *elem, const char *event_name, struct term_event *ev); #endif diff --git a/src/ecmascript/spidermonkey/keyboard.cpp b/src/ecmascript/spidermonkey/keyboard.cpp new file mode 100644 index 00000000..ff179908 --- /dev/null +++ b/src/ecmascript/spidermonkey/keyboard.cpp @@ -0,0 +1,216 @@ +/* The SpiderMonkey KeyboardEvent object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/spidermonkey/util.h" +#include +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/spidermonkey.h" +#include "ecmascript/spidermonkey/heartbeat.h" +#include "ecmascript/spidermonkey/keyboard.h" +#include "ecmascript/timer.h" +#include "intl/libintl.h" +#include "main/select.h" +#include "main/timer.h" +#include "network/connection.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/download.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +#include +#include +#include +#include +#include +#include + + +static bool keyboardEvent_get_property_key(JSContext *cx, unsigned int argc, JS::Value *vp); +static bool keyboardEvent_get_property_keyCode(JSContext *cx, unsigned int argc, JS::Value *vp); + +static unicode_val_T keyCode; + +struct keyboard { + unicode_val_T keyCode; +}; + +static void +keyboardEvent_finalize(JS::GCContext *op, JSObject *xhr_obj) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif +} + +JSClassOps keyboardEvent_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + keyboardEvent_finalize, // finalize + nullptr, // call + nullptr, // construct + JS_GlobalObjectTraceHook // trace +}; + +JSClass keyboardEvent_class = { + "KeyboardEvent", + JSCLASS_HAS_RESERVED_SLOTS(1), + &keyboardEvent_ops +}; + +bool +keyboardEvent_constructor(JSContext* ctx, unsigned argc, JS::Value* vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject newObj(ctx, JS_NewObjectForConstructor(ctx, &keyboardEvent_class, args)); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + if (!newObj) { + return false; + } + struct keyboard *keyb = (struct keyboard *)mem_calloc(1, sizeof(*keyb)); + + if (!keyb) { + return false; + } + JS::SetReservedSlot(newObj, 0, JS::PrivateValue(keyb)); + keyb->keyCode = keyCode; + args.rval().setObject(*newObj); + + return true; +} + +JSPropertySpec keyboardEvent_props[] = { + JS_PSG("key", keyboardEvent_get_property_key, JSPROP_ENUMERATE), + JS_PSG("keyCode", keyboardEvent_get_property_keyCode, JSPROP_ENUMERATE), + JS_PS_END +}; + +static bool +keyboardEvent_get_property_key(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct keyboard *keyb = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!keyb) { + return false; + } + char text[8] = {0}; + + *text = keyb->keyCode; + args.rval().setString(JS_NewStringCopyZ(ctx, text)); + + return true; +} + +static bool +keyboardEvent_get_property_keyCode(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct keyboard *keyb = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!keyb) { + return false; + } + args.rval().setInt32(keyb->keyCode); + + return true; +} + + +JSObject * +get_keyboardEvent(JSContext *ctx, struct term_event *ev) +{ + JSObject *k = JS_NewObject(ctx, &keyboardEvent_class); + + if (!k) { + return NULL; + } + + JS::RootedObject r_keyb(ctx, k); + JS_DefineProperties(ctx, r_keyb, (JSPropertySpec *) keyboardEvent_props); + + struct keyboard *keyb = (struct keyboard *)mem_calloc(1, sizeof(*keyb)); + + if (!keyb) { + return NULL; + } + keyCode = keyb->keyCode = get_kbd_key(ev); + JS::SetReservedSlot(k, 0, JS::PrivateValue(keyb)); + + return k; +} diff --git a/src/ecmascript/spidermonkey/keyboard.h b/src/ecmascript/spidermonkey/keyboard.h new file mode 100644 index 00000000..c59733eb --- /dev/null +++ b/src/ecmascript/spidermonkey/keyboard.h @@ -0,0 +1,14 @@ +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_KEYBOARD_H +#define EL__ECMASCRIPT_SPIDERMONKEY_KEYBOARD_H + +#include "ecmascript/spidermonkey/util.h" + +struct term_event; + +extern JSClass keyboardEvent_class; +extern JSPropertySpec keyboardEvent_props[]; +bool keyboardEvent_constructor(JSContext* ctx, unsigned argc, JS::Value* vp); + +JSObject *get_keyboardEvent(JSContext *ctx, struct term_event *ev); + +#endif diff --git a/src/ecmascript/spidermonkey/meson.build b/src/ecmascript/spidermonkey/meson.build index 6ea90eb4..2725fc2a 100644 --- a/src/ecmascript/spidermonkey/meson.build +++ b/src/ecmascript/spidermonkey/meson.build @@ -1,4 +1,4 @@ #INCLUDES += $(SPIDERMONKEY_CFLAGS) srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'document.cpp', 'element.cpp', 'form.cpp', 'forms.cpp', 'heartbeat.cpp', 'history.cpp', 'implementation.cpp', 'input.cpp', -'location.cpp', 'localstorage.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp') +'keyboard.cpp', 'location.cpp', 'localstorage.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp') diff --git a/src/viewer/text/link.cpp b/src/viewer/text/link.cpp index 84edceb6..369eb25d 100644 --- a/src/viewer/text/link.cpp +++ b/src/viewer/text/link.cpp @@ -75,7 +75,7 @@ current_link_evhook(struct document_view *doc_view, enum script_event_hook_type if (element != (*mapa).end()) { const char *event_name = script_event_hook_name[(int)type]; - check_element_event(element->second, event_name); + check_element_event(element->second, event_name, NULL); } } diff --git a/src/viewer/text/view.cpp b/src/viewer/text/view.cpp index a86c399f..0dd071b9 100644 --- a/src/viewer/text/view.cpp +++ b/src/viewer/text/view.cpp @@ -1298,9 +1298,9 @@ try_form_action(struct session *ses, struct document_view *doc_view, if (element != (*mapa).end()) { const char *event_name = script_event_hook_name[SEVHOOK_ONKEYDOWN]; - check_element_event(element->second, event_name); + check_element_event(element->second, event_name, ev); event_name = script_event_hook_name[SEVHOOK_ONKEYUP]; - check_element_event(element->second, event_name); + check_element_event(element->second, event_name, ev); } } diff --git a/test/ecmascript/keyListener.html b/test/ecmascript/keyListener.html index 9fdb2282..858a6209 100644 --- a/test/ecmascript/keyListener.html +++ b/test/ecmascript/keyListener.html @@ -11,7 +11,7 @@