enlightenment/src/modules/vkbd/e_kbd_send.c

458 lines
12 KiB
C

#include "e.h"
#include "e_kbd_send.h"
#ifdef HAVE_WAYLAND
#include "input-method-unstable-v1-client-protocol.h"
#include "text-input-unstable-v1-client-protocol.h"
/*
struct weekeyboard
{
E_Module *module;
Ecore_Evas *ee;
Ecore_Wl2_Window *win;
Evas_Object *edje_obj;
const char *ee_engine;
char **ignore_keys;
struct wl_surface *surface;
struct zwp_input_panel_v1 *ip;
struct zwp_input_method_v1 *im;
struct wl_output *output;
struct zwp_input_method_context_v1 *im_ctx;
char *surrounding_text;
char *preedit_str;
char *language;
char *theme;
uint32_t text_direction;
uint32_t preedit_style;
uint32_t content_hint;
uint32_t content_purpose;
uint32_t serial;
uint32_t surrounding_cursor;
Eina_Bool context_changed;
};
static char *
_wkb_insert_text(const char *text, uint32_t offset, const char *insert)
{
char *new_text = malloc(strlen(text) + strlen(insert) + 1);
uint32_t text_len = 0;
if (!new_text) return NULL;
if ((!text) || (!insert))
{
free(new_text);
return NULL;
}
text_len = strlen(text);
if (offset > text_len) offset = text_len;
new_text = malloc(text_len + strlen(insert) + 1);
if (!new_text) return NULL;
strncpy(new_text, text, offset);
new_text[offset] = '\0';
strcat(new_text, insert);
strcat(new_text, text + offset);
return new_text;
}
static void
_wkb_commit_preedit_str(struct weekeyboard *wkb)
{
char *surrounding_text;
if ((!wkb->preedit_str) || (strlen(wkb->preedit_str) == 0)) return;
zwp_input_method_context_v1_cursor_position(wkb->im_ctx, 0, 0);
zwp_input_method_context_v1_commit_string(wkb->im_ctx, wkb->serial,
wkb->preedit_str);
if (wkb->surrounding_text)
{
surrounding_text =
_wkb_insert_text(wkb->surrounding_text, wkb->surrounding_cursor,
wkb->preedit_str);
free(wkb->surrounding_text);
wkb->surrounding_text = surrounding_text;
wkb->surrounding_cursor += strlen(wkb->preedit_str);
}
else
{
wkb->surrounding_text = strdup(wkb->preedit_str);
wkb->surrounding_cursor = strlen(wkb->preedit_str);
}
free(wkb->preedit_str);
wkb->preedit_str = strdup("");
}
static void
_wkb_send_preedit_str(struct weekeyboard *wkb, int cursor)
{
unsigned int index = strlen(wkb->preedit_str);
if (wkb->preedit_style)
zwp_input_method_context_v1_preedit_styling(wkb->im_ctx, 0,
strlen(wkb->preedit_str),
wkb->preedit_style);
if (cursor > 0) index = cursor;
zwp_input_method_context_v1_preedit_cursor(wkb->im_ctx, index);
zwp_input_method_context_v1_preedit_string(wkb->im_ctx, wkb->serial,
wkb->preedit_str,
wkb->preedit_str);
}
static void
_wkb_update_preedit_str(struct weekeyboard *wkb, const char *key)
{
char *tmp;
if (!wkb->preedit_str) wkb->preedit_str = strdup("");
tmp = _wkb_insert_text(wkb->preedit_str, strlen(wkb->preedit_str), key);
free(wkb->preedit_str);
wkb->preedit_str = tmp;
if (eina_streq(key, " ")) _wkb_commit_preedit_str(wkb);
else _wkb_send_preedit_str(wkb, -1);
}
static Eina_Bool
_wkb_ignore_key(struct weekeyboard *wkb, const char *key)
{
int i;
if (!wkb->ignore_keys) return EINA_FALSE;
for (i = 0; wkb->ignore_keys[i] != NULL; i++)
{
if (eina_streq(key, wkb->ignore_keys[i])) return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_cb_wkb_on_key_down(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source)
{
struct weekeyboard *wkb = data;
char *src;
const char *key;
EINA_SAFETY_ON_FALSE_RETURN(wkb);
EINA_SAFETY_ON_FALSE_RETURN(source);
src = strdup(source);
if (!src) return NULL;
key = strtok(src, ":");
key = strtok(NULL, ":");
if (key == NULL) key = ":";
if (_wkb_ignore_key(wkb, key)) goto end;
else if (eina_streq(key, "backspace"))
{
if (strlen(wkb->preedit_str) == 0)
{
zwp_input_method_context_v1_delete_surrounding_text(wkb->im_ctx,
-1, 1);
zwp_input_method_context_v1_commit_string(wkb->im_ctx,
wkb->serial, "");
}
else
{
wkb->preedit_str[strlen(wkb->preedit_str) -1] = '\0';
_wkb_send_preedit_str(wkb, -1);
}
goto end;
}
else if (eina_streq(key, "enter"))
{
_wkb_commit_preedit_str(wkb);
zwp_input_method_context_v1_keysym(wkb->im_ctx, wkb->serial, 0,
XKB_KEY_Return,
WL_KEYBOARD_KEY_STATE_PRESSED, 0);
goto end;
}
else if (eina_streq(key, "space")) key = " ";
_wkb_update_preedit_str(wkb, key);
end:
free(src);
}
static void
_wkb_im_ctx_surrounding_text(void *data, struct zwp_input_method_context_v1 *im_ctx, const char *text, uint32_t cursor, uint32_t anchor)
{
struct weekeyboard *wkb = data;
EINA_SAFETY_ON_NULL_RETURN(text);
free(wkb->surrounding_text);
wkb->surrounding_text = strdup(text);
if (!wkb->surrounding_text) return;
wkb->surrounding_cursor = cursor;
}
static void
_wkb_im_ctx_reset(void *data, struct zwp_input_method_context_v1 *im_ctx)
{
struct weekeyboard *wkb = data;
if (strlen(wkb->preedit_str))
{
free(wkb->preedit_str);
wkb->preedit_str = strdup("");
}
}
static void
_wkb_im_ctx_content_type(void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t hint, uint32_t purpose)
{
struct weekeyboard *wkb = data;
if (!wkb->context_changed) return;
switch (purpose)
{
case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DIGITS:
case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER:
{
if (wkb->edje_obj)
edje_object_signal_emit(wkb->edje_obj, "show,numeric", "");
break;
}
default:
{
if (wkb->edje_obj)
edje_object_signal_emit(wkb->edje_obj, "show,alphanumeric", "");
break;
}
}
wkb->content_hint = hint;
wkb->content_purpose = purpose;
wkb->context_changed = EINA_FALSE;
}
static void
_wkb_im_ctx_invoke_action(void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t button, uint32_t index)
{
struct weekeyboard *wkb = data;
if (button != BTN_LEFT) return;
_wkb_send_preedit_str(wkb, index);
}
static void
_wkb_im_ctx_commit_state(void *data, struct zwp_input_method_context_v1 *im_ctx, uint32_t serial)
{
struct weekeyboard *wkb = data;
wkb->serial = serial;
zwp_input_method_context_v1_language(im_ctx, wkb->serial, "en");
zwp_input_method_context_v1_text_direction(im_ctx, wkb->serial,
ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR);
}
static void
_wkb_im_ctx_preferred_language(void *data, struct zwp_input_method_context_v1 *im_ctx, const char *language)
{
struct weekeyboard *wkb = data;
if ((language) && (wkb->language) && (eina_streq(language, wkb->language))) return;
E_FREE_FUNC(wkb->language, free);
if (language) wkb->language = strdup(language);
}
static const struct zwp_input_method_context_v1_listener
wkb_im_context_listener =
{
_wkb_im_ctx_surrounding_text,
_wkb_im_ctx_reset,
_wkb_im_ctx_content_type,
_wkb_im_ctx_invoke_action,
_wkb_im_ctx_commit_state,
_wkb_im_ctx_preferred_language,
};
*/
#endif
#ifndef HAVE_WAYLAND_ONLY
static const char *
_string_to_keysym(const char *str)
{
if (e_comp_util_has_x())
{
int glyph;
/* utf8 -> glyph id (unicode - ucs4) */
glyph = 0;
evas_string_char_next_get(str, 0, &glyph);
if (glyph <= 0) return NULL;
/* glyph id -> keysym */
if (glyph > 0xff) glyph |= 0x1000000;
return ecore_x_keysym_string_get(glyph);
}
else
{
return NULL;
}
}
#endif
EAPI void
e_kbd_send_string_press(const char *str EINA_UNUSED, Kbd_Mod mod EINA_UNUSED)
{
#ifndef HAVE_WAYLAND_ONLY
if (e_comp_util_has_x())
{
const char *key = NULL;
key = _string_to_keysym(str);
if (!key) return;
e_kbd_send_keysym_press(key, mod);
}
#endif
}
EAPI void
e_kbd_send_keysym_press(const char *key EINA_UNUSED, Kbd_Mod mod EINA_UNUSED)
{
#ifndef HAVE_WAYLAND_ONLY
if (e_comp_util_has_x())
{
if (mod & KBD_MOD_CTRL) ecore_x_test_fake_key_down("Control_L");
if (mod & KBD_MOD_ALT) ecore_x_test_fake_key_down("Alt_L");
if (mod & KBD_MOD_WIN) ecore_x_test_fake_key_down("Super_L");
ecore_x_test_fake_key_press(key);
if (mod & KBD_MOD_WIN) ecore_x_test_fake_key_up("Super_L");
if (mod & KBD_MOD_ALT) ecore_x_test_fake_key_up("Alt_L");
if (mod & KBD_MOD_CTRL) ecore_x_test_fake_key_up("Control_L");
}
else
{
/*
struct wl_resource *res;
uint32_t serial, *end, *k, keycode, timestamp;
xkb_keysym_t keysym;
Eina_List *l;
timestamp = ecore_loop_time_get() * 1000.0;
keysym = xkb_keysym_from_name(key, XKB_KEYSYM_NO_FLAGS);
keycode = xkb_keymap_key_by_name(keymap, key);
serial = wl_display_next_serial(e_comp_wl->wl.disp);
EINA_LIST_FOREACH(e_comp_wl->kbd.focused, l, res)
{
//keycode = KEYCOADE_ctrl
//e_comp_wl_input_keyboard_state_update(keycode, EINA_TRUE);
//if (mod & KBD_MOD_CTRL) ecore_x_test_fake_key_down("Control_L");
//if (mod & KBD_MOD_ALT) ecore_x_test_fake_key_down("Alt_L");
//if (mod & KBD_MOD_WIN) ecore_x_test_fake_key_down("Super_L");
wl_keyboard_send_key(res, serial, timestamp,
keycode, WL_KEYBOARD_KEY_STATE_PRESSED);
}
serial = wl_display_next_serial(e_comp_wl->wl.disp);
EINA_LIST_FOREACH(e_comp_wl->kbd.focused, l, res)
{
wl_keyboard_send_key(res, serial, timestamp,
keycode, WL_KEYBOARD_KEY_STATE_RELEASED);
//if (mod & KBD_MOD_WIN) ecore_x_test_fake_key_up("Super_L");
//if (mod & KBD_MOD_ALT) ecore_x_test_fake_key_up("Alt_L");
//if (mod & KBD_MOD_CTRL) ecore_x_test_fake_key_up("Control_L");
}
*/
}
#endif
}
EAPI void
e_kbd_send_init(void)
{
#ifndef HAVE_WAYLAND_ONLY
if (e_comp_util_has_x())
{
return;
}
#endif
#ifdef HAVE_WAYLAND
if (!e_comp_util_has_x())
{
/*
void *data;
struct wl_registry *registry =
e_comp_wl->wl.registry ? :
ecore_wl2_display_registry_get(e_comp_wl->ewd);
itr = ecore_wl2_display_globals_get(e_comp_wl->ewd);
EINA_ITERATOR_FOREACH(itr, data)
{
Ecore_Wl2_Global *global = data;
if (eina_streq(global->interface, "zwp_input_panel_v1"))
{
wkb->ip =
wl_registry_bind(registry, global->id,
&zwp_input_panel_v1_interface, 1);
}
else if (eina_streq(global->interface, "zwp_input_method_v1"))
{
wkb->im =
wl_registry_bind(registry, global->id,
&zwp_input_method_v1_interface, 1);
}
else if (eina_streq(global->interface, "wl_output"))
{
wkb->output =
wl_registry_bind(registry, global->id,
&wl_output_interface, 1);
}
}
eina_iterator_free(itr);
if ((!wkb->ip) || (!wkb->im) || (!wkb->output)) return;
zwp_input_method_v1_add_listener(wkb->im, &wkb_im_listener, wkb);
*/
}
#endif
}
EAPI void
e_kbd_send_shutdown(void)
{
#ifndef HAVE_WAYLAND_ONLY
if (e_comp_util_has_x())
{
return;
}
#endif
#ifdef HAVE_WAYLAND
if (!e_comp_util_has_x())
{
/*
E_FREE_FUNC(wkb->im_ctx, zwp_input_method_context_v1_destroy);
E_FREE_FUNC(wkb->edje_obj, evas_object_del);
if (wkb->ignore_keys)
{
free(*wkb->ignore_keys);
free(wkb->ignore_keys);
}
free(wkb->preedit_str);
free(wkb->surrounding_text);
free(wkb->theme);
free(wkb);
*/
}
#endif
}