1
0
mirror of https://github.com/rkd77/elinks.git synced 2025-02-02 15:09:23 -05:00
elinks/src/scripting/smjs/keybinding.c
Witold Filipczyk 25dd2ecae9 Changed ecmascript engine to mozjs-17.0.
Was not tested, especially smjs is likely buggy.
2019-02-10 21:00:37 +01:00

261 lines
6.0 KiB
C

/* "elinks.keymaps" */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "elinks.h"
#include "config/kbdbind.h"
#include "ecmascript/spidermonkey-shared.h"
#include "main/event.h"
#include "scripting/smjs/core.h"
#include "scripting/smjs/elinks_object.h"
#include "util/memory.h"
static const JSClass keymap_class; /* defined below */
/* @keymap_class.getProperty */
static JSBool
keymap_get_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSMutableHandleValue hvp)
{
ELINKS_CAST_PROP_PARAMS
jsid id = *(hid._);
unsigned char *action_str;
const unsigned char *keystroke_str;
int *data;
jsval tmp;
/* This can be called if @obj if not itself an instance of the
* appropriate class but has one in its prototype chain. Fail
* such calls. */
if (!JS_InstanceOf(ctx, obj, (JSClass *) &keymap_class, NULL))
return JS_FALSE;
data = JS_GetInstancePrivate(ctx, obj,
(JSClass *) &keymap_class, NULL);
if (!JS_IdToValue(ctx, id, &tmp))
goto ret_null;
keystroke_str = JS_EncodeString(ctx, JS_ValueToString(ctx, tmp));
if (!keystroke_str) goto ret_null;
action_str = get_action_name_from_keystroke((enum keymap_id) *data,
keystroke_str);
if (!action_str || !strcmp(action_str, "none")) goto ret_null;
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(ctx, action_str));
return JS_TRUE;
ret_null:
*vp = JSVAL_NULL;
return JS_TRUE;
}
static enum evhook_status
smjs_keybinding_action_callback(va_list ap, void *data)
{
jsval rval;
struct session *ses = va_arg(ap, struct session *);
JSObject *jsobj = data;
evhook_use_params(ses);
smjs_ses = ses;
JS_CallFunctionValue(smjs_ctx, NULL, OBJECT_TO_JSVAL(jsobj),
0, NULL, &rval);
smjs_ses = NULL;
return EVENT_HOOK_STATUS_LAST;
}
/* @keymap_class.setProperty */
static JSBool
keymap_set_property(JSContext *ctx, JSHandleObject hobj, JSHandleId hid, JSBool strict, JSMutableHandleValue hvp)
{
ELINKS_CAST_PROP_PARAMS
jsid id = *(hid._);
int *data;
unsigned char *keymap_str;
jsval val;
const unsigned char *keystroke_str;
/* This can be called if @obj if not itself an instance of the
* appropriate class but has one in its prototype chain. Fail
* such calls. */
if (!JS_InstanceOf(ctx, obj, (JSClass *) &keymap_class, NULL))
return JS_FALSE;
data = JS_GetInstancePrivate(ctx, obj,
(JSClass *) &keymap_class, NULL);
/* Ugly fact: we need to get the string from the id to give to bind_do,
* which will of course then convert the string back to an id... */
keymap_str = get_keymap_name((enum keymap_id) *data);
if (!keymap_str) return JS_FALSE;
JS_IdToValue(ctx, id, &val);
keystroke_str = JS_EncodeString(ctx, JS_ValueToString(ctx, val));
if (!keystroke_str) return JS_FALSE;
if (JSVAL_IS_STRING(*vp)) {
unsigned char *action_str;
action_str = JS_EncodeString(ctx, JS_ValueToString(ctx, *vp));
if (!action_str) return JS_FALSE;
if (bind_do(keymap_str, keystroke_str, action_str, 0))
return JS_FALSE;
return JS_TRUE;
} else if (JSVAL_IS_NULL(*vp)) { /* before JSVAL_IS_OBJECT */
if (bind_do(keymap_str, keystroke_str, "none", 0))
return JS_FALSE;
return JS_TRUE;
} else if (!JSVAL_IS_PRIMITIVE(*vp) || JSVAL_IS_NULL(*vp)) {
unsigned char *err = NULL;
int event_id;
struct string event_name = NULL_STRING;
JSObject *jsobj = JSVAL_TO_OBJECT(*vp);
if (JS_FALSE == JS_ObjectIsFunction(ctx, jsobj))
return JS_FALSE;
if (!init_string(&event_name)) return JS_FALSE;
add_format_to_string(&event_name, "smjs-run-func %p", jsobj);
event_id = bind_key_to_event_name(keymap_str,
keystroke_str,
event_name.source, &err);
done_string(&event_name);
if (err) {
alert_smjs_error(err);
return JS_FALSE;
}
event_id = register_event_hook(event_id,
smjs_keybinding_action_callback,
0, (void *) jsobj);
if (event_id == EVENT_NONE) {
alert_smjs_error("error registering event hook"
" for keybinding");
return JS_FALSE;
}
return JS_TRUE;
}
return JS_FALSE;
}
/* @keymap_class.finalize */
static void
keymap_finalize(JSFreeOp *op, JSObject *obj)
{
void *data;
#if 0
assert(JS_InstanceOf(ctx, obj, (JSClass *) &keymap_class, NULL));
if_assert_failed return;
#endif
data = JS_GetPrivate(obj);
mem_free(data);
}
static const JSClass keymap_class = {
"keymap",
JSCLASS_HAS_PRIVATE, /* int * */
JS_PropertyStub, JS_PropertyStub,
keymap_get_property, keymap_set_property,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, keymap_finalize,
};
static JSObject *
smjs_get_keymap_object(enum keymap_id keymap_id)
{
int *data;
JSObject *keymap_object;
assert(smjs_ctx);
keymap_object = JS_NewObject(smjs_ctx, (JSClass *) &keymap_class,
NULL, NULL);
if (!keymap_object) return NULL;
data = intdup(keymap_id);
if (!data) return NULL;
JS_SetPrivate(keymap_object, data); /* to @keymap_class */
return keymap_object;
}
static const JSClass keymaps_hash_class = {
"keymaps_hash",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
};
static JSObject *
smjs_get_keymap_hash_object(void)
{
jsval val;
enum keymap_id keymap_id;
JSObject *keymaps_hash;
keymaps_hash = JS_NewObject(smjs_ctx, (JSClass *) &keymaps_hash_class,
NULL, NULL);
if (!keymaps_hash) return NULL;
for (keymap_id = 0; keymap_id < KEYMAP_MAX; ++keymap_id) {
unsigned char *keymap_str = get_keymap_name(keymap_id);
JSObject *map = smjs_get_keymap_object(keymap_id);
assert(keymap_str);
if (!map) return NULL;
val = OBJECT_TO_JSVAL(map);
JS_SetProperty(smjs_ctx, keymaps_hash, keymap_str, &val);
}
return keymaps_hash;
}
void
smjs_init_keybinding_interface(void)
{
jsval val;
struct JSObject *keymaps_hash;
if (!smjs_ctx || !smjs_elinks_object)
return;
keymaps_hash = smjs_get_keymap_hash_object();
if (!keymaps_hash) return;
val = OBJECT_TO_JSVAL(keymaps_hash);
JS_SetProperty(smjs_ctx, smjs_elinks_object, "keymaps", &val);
}