e - add vkbd for convertibles (tablets, laptops ... phones)

devs/bu5hm4n/sandbox_fix
Carsten Haitzler 6 years ago
parent 09a8888f76
commit 074b3fe1eb
  1. 7
      meson.build
  2. 8
      meson_options.txt
  3. 1
      src/modules/meson.build
  4. 1
      src/modules/vkbd/.gitignore
  5. 98342
      src/modules/vkbd/dicts/English_US.dic
  6. 5001
      src/modules/vkbd/dicts/English_US_Small.dic
  7. BIN
      src/modules/vkbd/e-module-vkbd.edj
  8. 567
      src/modules/vkbd/e_kbd_buf.c
  9. 73
      src/modules/vkbd/e_kbd_buf.h
  10. 205
      src/modules/vkbd/e_kbd_cfg.c
  11. 9
      src/modules/vkbd/e_kbd_cfg.h
  12. 880
      src/modules/vkbd/e_kbd_dict.c
  13. 62
      src/modules/vkbd/e_kbd_dict.h
  14. 1427
      src/modules/vkbd/e_kbd_int.c
  15. 127
      src/modules/vkbd/e_kbd_int.h
  16. 57
      src/modules/vkbd/e_kbd_send.c
  17. 15
      src/modules/vkbd/e_kbd_send.h
  18. 158
      src/modules/vkbd/e_mod_main.c
  19. 26
      src/modules/vkbd/e_mod_main.h
  20. 145
      src/modules/vkbd/keyboards/Default.kbd
  21. 120
      src/modules/vkbd/keyboards/Numbers.kbd
  22. 275
      src/modules/vkbd/keyboards/Terminal.kbd
  23. BIN
      src/modules/vkbd/keyboards/alpha.png
  24. BIN
      src/modules/vkbd/keyboards/backspace.png
  25. BIN
      src/modules/vkbd/keyboards/down.png
  26. BIN
      src/modules/vkbd/keyboards/enter.png
  27. BIN
      src/modules/vkbd/keyboards/left.png
  28. BIN
      src/modules/vkbd/keyboards/numeric.png
  29. BIN
      src/modules/vkbd/keyboards/qwerty.png
  30. BIN
      src/modules/vkbd/keyboards/right.png
  31. BIN
      src/modules/vkbd/keyboards/shift.png
  32. BIN
      src/modules/vkbd/keyboards/spanner.png
  33. BIN
      src/modules/vkbd/keyboards/tab.png
  34. BIN
      src/modules/vkbd/keyboards/up.png
  35. 52
      src/modules/vkbd/meson.build
  36. 6
      src/modules/vkbd/module.desktop
  37. 258
      src/modules/vkbd/theme.edc

@ -327,6 +327,13 @@ if freebsd == true
dir_pkgconfig = join_paths(dir_lib, 'data/pkgconfig')
endif
##### edje_cc binary compiler tool
edje_cmd = get_option('edje-cc')
if edje_cmd == ''
edje_cmd = join_paths(dep_edje.get_pkgconfig_variable('prefix'),
'bin', 'edje_cc')
endif
subdir('src/bin')
subdir('src/modules')

@ -15,6 +15,10 @@ option('nls',
default: true,
description: 'enable localization: (default=true)')
option('edje-cc',
type : 'string',
description: 'A path to a edje_cc. Defaults to system edje_cc')
option('pam',
type: 'boolean',
default: true,
@ -236,6 +240,10 @@ option('xkbswitch',
type: 'boolean',
default: true,
description: 'enable xkbswitch module: (default=true)')
option('vkbd',
type: 'boolean',
default: true,
description: 'enable vkbd module: (default=true)')
option('conf',

@ -49,6 +49,7 @@ mods = [
'time',
'luncher',
'teamwork',
'vkbd',
# modules have a custom binary as well
'battery',
'cpufreq',

@ -0,0 +1 @@
e-module-illume-keyboard.edj

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,567 @@
#include "e.h"
#include "e_kbd_buf.h"
#include "e_kbd_dict.h"
static E_Kbd_Buf_Layout *
_e_kbd_buf_new(void)
{
E_Kbd_Buf_Layout *kbl;
kbl = E_NEW(E_Kbd_Buf_Layout, 1);
kbl->ref =1;
return kbl;
}
static void
_e_kbd_buf_layout_ref(E_Kbd_Buf_Layout *kbl)
{
kbl->ref++;
}
static void
_e_kbd_buf_layout_unref(E_Kbd_Buf_Layout *kbl)
{
kbl->ref--;
if (kbl->ref > 0) return;
while (kbl->keys)
{
E_Kbd_Buf_Key *ky;
ky = kbl->keys->data;
if (ky->key) eina_stringshare_del(ky->key);
if (ky->key_shift) eina_stringshare_del(ky->key_shift);
if (ky->key_capslock) eina_stringshare_del(ky->key_capslock);
if (ky->key_altgr) eina_stringshare_del(ky->key_altgr);
free(ky);
kbl->keys = eina_list_remove_list(kbl->keys, kbl->keys);
}
free(kbl);
}
static void
_e_kbd_buf_string_matches_clear(E_Kbd_Buf *kb)
{
while (kb->string_matches)
{
if (kb->string_matches->data)
eina_stringshare_del(kb->string_matches->data);
kb->string_matches = eina_list_remove_list(kb->string_matches, kb->string_matches);
}
}
static void
_e_kbd_buf_actual_string_clear(E_Kbd_Buf *kb)
{
if (kb->actual_string) eina_stringshare_del(kb->actual_string);
kb->actual_string = NULL;
}
static E_Kbd_Buf_Key *
_e_kbd_buf_at_coord_get(E_Kbd_Buf *kb EINA_UNUSED, E_Kbd_Buf_Layout *kbl, int x, int y)
{
Eina_List *l;
for (l = kbl->keys; l; l = l->next)
{
E_Kbd_Buf_Key *ky;
ky = l->data;
if (ky->key)
{
if ((x >= ky->x) && (y >= ky->y) &&
(x < (ky->x + ky->w)) && (y < (ky->y + ky->h)))
return ky;
}
}
return NULL;
}
static E_Kbd_Buf_Key *
_e_kbd_buf_closest_get(E_Kbd_Buf *kb EINA_UNUSED, E_Kbd_Buf_Layout *kbl, int x, int y)
{
Eina_List *l;
E_Kbd_Buf_Key *ky_closest = NULL;
int dist_closest = 0x7fffffff;
for (l = kbl->keys; l; l = l->next)
{
E_Kbd_Buf_Key *ky;
int dist, dx, dy;
ky = l->data;
if (ky->key)
{
dx = x - (ky->x + (ky->w / 2));
dy = y - (ky->y + (ky->h / 2));
dist = (dx * dx) + (dy * dy);
if (dist < dist_closest)
{
ky_closest = ky;
dist_closest = dist;
}
}
}
return ky_closest;
}
static const char *
_e_kbd_buf_keystroke_key_string_get(E_Kbd_Buf *kb EINA_UNUSED, E_Kbd_Buf_Keystroke *ks, E_Kbd_Buf_Key *ky)
{
const char *str = NULL;
if ((ky) && (ky->key))
{
if (ks->shift)
{
if (ky->key_shift) str = ky->key_shift;
else str = ky->key;
}
else if (ks->capslock)
{
if (ky->key_capslock) str = ky->key_capslock;
else str = ky->key;
}
else str = ky->key;
}
return str;
}
static const char *
_e_kbd_buf_keystroke_string_get(E_Kbd_Buf *kb, E_Kbd_Buf_Keystroke *ks)
{
const char *str = NULL;
if (ks->key) str = ks->key;
else
{
E_Kbd_Buf_Key *ky;
ky = _e_kbd_buf_at_coord_get(kb, ks->layout, ks->x, ks->y);
if (!ky) ky = _e_kbd_buf_closest_get(kb, ks->layout, ks->x, ks->y);
str = _e_kbd_buf_keystroke_key_string_get(kb, ks, ky);
}
return str;
}
static void
_e_kbd_buf_actual_string_update(E_Kbd_Buf *kb)
{
Eina_List *l;
char *actual = NULL;
int actual_len = 0;
unsigned int actual_size = 0;
E_Kbd_Buf_Keystroke *ks;
_e_kbd_buf_actual_string_clear(kb);
EINA_LIST_FOREACH(kb->keystrokes, l, ks)
{
const char *str;
str = _e_kbd_buf_keystroke_string_get(kb, ks);
if (!str) continue;
if (!actual) actual_size += 64, actual = malloc(actual_size);
else if ((actual_len + strlen(str) + 1) > actual_size)
{
actual_size += 64;
actual = realloc(actual, actual_size);
}
strcpy(actual + actual_len, str);
actual_len += strlen(str);
}
kb->actual_string = eina_stringshare_add(actual);
free(actual);
}
static const char *
_e_kbd_buf_matches_find(Eina_List *matches, const char *s)
{
Eina_List *l;
for (l = matches; l; l = l->next)
{
if (!strcmp(l->data, s)) return s;
}
return NULL;
}
static void
_e_kbd_buf_matches_update(E_Kbd_Buf *kb)
{
const char *word;
int pri, i;
E_Kbd_Dict *dicts[3];
_e_kbd_buf_string_matches_clear(kb);
dicts[0] = kb->dict.personal;
dicts[1] = kb->dict.sys;
dicts[2] = kb->dict.data;
for (i = 0; i < 3; i++)
{
if (!dicts[i]) continue;
e_kbd_dict_matches_lookup(dicts[i]);
e_kbd_dict_matches_first(dicts[i]);
for (;;)
{
word = e_kbd_dict_matches_match_get(dicts[i], &pri);
if (!word) break;
if (!_e_kbd_buf_matches_find(kb->string_matches, word))
kb->string_matches = eina_list_append(kb->string_matches,
eina_stringshare_add(word));
e_kbd_dict_matches_next(dicts[i]);
}
}
}
static Eina_Bool
_e_kbd_buf_cb_data_dict_reload(void *data)
{
E_Kbd_Buf *kb;
char buf[PATH_MAX];
kb = data;
kb->dict.data_reload_delay = NULL;
e_kbd_buf_clear(kb);
if (kb->dict.data) e_kbd_dict_free(kb->dict.data);
e_user_dir_concat_static(buf, "dicts-dynamic/data.dic");
kb->dict.data = e_kbd_dict_new(buf);
return ECORE_CALLBACK_CANCEL;
}
static void
_e_kbd_buf_cb_data_dict_change(void *data, Ecore_File_Monitor *em EINA_UNUSED, Ecore_File_Event event EINA_UNUSED, const char *path EINA_UNUSED)
{
E_Kbd_Buf *kb;
kb = data;
if (kb->dict.data_reload_delay) ecore_timer_del(kb->dict.data_reload_delay);
kb->dict.data_reload_delay = ecore_timer_add(2.0, _e_kbd_buf_cb_data_dict_reload, kb);
}
EAPI E_Kbd_Buf *
e_kbd_buf_new(const char *sysdicts, const char *dict)
{
E_Kbd_Buf *kb;
char buf[PATH_MAX];
kb = E_NEW(E_Kbd_Buf, 1);
if (!kb) return NULL;
kb->sysdicts = eina_stringshare_add(sysdicts);
e_user_dir_concat_static(buf, "dicts");
if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
e_user_dir_snprintf(buf, sizeof(buf), "dicts/%s", dict);
kb->dict.sys = e_kbd_dict_new(buf);
if (!kb->dict.sys)
{
snprintf(buf, sizeof(buf), "%s/dicts/%s", kb->sysdicts, dict);
kb->dict.sys = e_kbd_dict_new(buf);
}
e_user_dir_concat_static(buf, "dicts-dynamic");
if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
e_user_dir_concat_static(buf, "dicts-dynamic/personal.dic");
kb->dict.personal = e_kbd_dict_new(buf);
if (!kb->dict.personal)
{
FILE *f;
f = fopen(buf, "w");
if (f)
{
fprintf(f, "\n");
fclose(f);
}
kb->dict.personal = e_kbd_dict_new(buf);
}
e_user_dir_concat_static(buf, "dicts-dynamic/data.dic");
kb->dict.data = e_kbd_dict_new(buf);
kb->dict.data_monitor =
ecore_file_monitor_add(buf, _e_kbd_buf_cb_data_dict_change, kb);
return kb;
}
EAPI void
e_kbd_buf_free(E_Kbd_Buf *kb)
{
e_kbd_buf_clear(kb);
e_kbd_buf_layout_clear(kb);
e_kbd_buf_lookup_cancel(kb);
eina_stringshare_del(kb->sysdicts);
if (kb->dict.sys) e_kbd_dict_free(kb->dict.sys);
if (kb->dict.personal) e_kbd_dict_free(kb->dict.personal);
if (kb->dict.data) e_kbd_dict_free(kb->dict.data);
if (kb->dict.data_monitor) ecore_file_monitor_del(kb->dict.data_monitor);
if (kb->dict.data_reload_delay) ecore_timer_del(kb->dict.data_reload_delay);
free(kb);
}
EAPI void
e_kbd_buf_dict_set(E_Kbd_Buf *kb, const char *dict)
{
char buf[PATH_MAX];
e_kbd_buf_clear(kb);
if (kb->dict.sys) e_kbd_dict_free(kb->dict.sys);
e_user_dir_concat_static(buf, "dicts");
if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
e_user_dir_snprintf(buf, sizeof(buf), "dicts/%s", dict);
kb->dict.sys = e_kbd_dict_new(buf);
if (!kb->dict.sys)
{
snprintf(buf, sizeof(buf), "%s/dicts/%s", kb->sysdicts, dict);
kb->dict.sys = e_kbd_dict_new(buf);
}
}
EAPI void
e_kbd_buf_clear(E_Kbd_Buf *kb)
{
e_kbd_buf_lookup_cancel(kb);
while (kb->keystrokes)
{
E_Kbd_Buf_Keystroke *ks;
ks = kb->keystrokes->data;
if (ks->key) eina_stringshare_del(ks->key);
_e_kbd_buf_layout_unref(ks->layout);
free(ks);
kb->keystrokes = eina_list_remove_list(kb->keystrokes, kb->keystrokes);
}
_e_kbd_buf_string_matches_clear(kb);
if (kb->dict.sys) e_kbd_dict_word_letter_clear(kb->dict.sys);
if (kb->dict.personal) e_kbd_dict_word_letter_clear(kb->dict.personal);
if (kb->dict.data) e_kbd_dict_word_letter_clear(kb->dict.data);
_e_kbd_buf_actual_string_clear(kb);
}
EAPI void
e_kbd_buf_layout_clear(E_Kbd_Buf *kb)
{
if (kb->layout)
{
_e_kbd_buf_layout_unref(kb->layout);
kb->layout = NULL;
}
}
EAPI void
e_kbd_buf_layout_size_set(E_Kbd_Buf *kb, int w, int h)
{
if (!kb->layout) kb->layout = _e_kbd_buf_new();
if (!kb->layout) return;
kb->layout->w = w;
kb->layout->h = h;
}
EAPI void
e_kbd_buf_layout_fuzz_set(E_Kbd_Buf *kb, int fuzz)
{
if (!kb->layout) kb->layout = _e_kbd_buf_new();
if (!kb->layout) return;
kb->layout->fuzz = fuzz;
}
EAPI void
e_kbd_buf_layout_key_add(E_Kbd_Buf *kb, const char *key, const char *key_shift, const char *key_capslock, const char *key_altgr, int x, int y, int w, int h)
{
E_Kbd_Buf_Key *ky;
if (!key) return;
if (!kb->layout) kb->layout = _e_kbd_buf_new();
if (!kb->layout) return;
ky = E_NEW(E_Kbd_Buf_Key, 1);
if (!ky) return;
ky->key = eina_stringshare_add(key);
if (key_shift) ky->key_shift = eina_stringshare_add(key_shift);
if (key_capslock) ky->key_capslock = eina_stringshare_add(key_capslock);
if (key_altgr) ky->key_altgr = eina_stringshare_add(key_altgr);
ky->x = x;
ky->y = y;
ky->w = w;
ky->h = h;
kb->layout->keys = eina_list_append(kb->layout->keys, ky);
}
static void
_e_kbd_buf_keystroke_add(E_Kbd_Buf *kb, E_Kbd_Buf_Keystroke *ks)
{
const char *str;
str = _e_kbd_buf_keystroke_string_get(kb, ks);
if (str)
{
if (kb->dict.sys) e_kbd_dict_word_letter_add(kb->dict.sys, str, 0);
if (kb->dict.personal) e_kbd_dict_word_letter_add(kb->dict.personal, str, 0);
if (kb->dict.data) e_kbd_dict_word_letter_add(kb->dict.data, str, 0);
}
}
EAPI void
e_kbd_buf_pressed_key_add(E_Kbd_Buf *kb, const char *key, int shift, int capslock)
{
E_Kbd_Buf_Keystroke *ks;
e_kbd_buf_lookup_cancel(kb);
if (!key) return;
if (!kb->layout) kb->layout = _e_kbd_buf_new();
if (!kb->layout) return;
ks = E_NEW(E_Kbd_Buf_Keystroke, 1);
if (!ks) return;
ks->key = eina_stringshare_add(key);
if (shift) ks->shift = 1;
if (capslock) ks->capslock = 1;
ks->layout = kb->layout;
_e_kbd_buf_layout_ref(ks->layout);
kb->keystrokes = eina_list_append(kb->keystrokes, ks);
if (kb->dict.sys) e_kbd_dict_word_letter_advance(kb->dict.sys);
if (kb->dict.personal) e_kbd_dict_word_letter_advance(kb->dict.personal);
if (kb->dict.data) e_kbd_dict_word_letter_advance(kb->dict.data);
_e_kbd_buf_keystroke_add(kb, ks);
_e_kbd_buf_actual_string_update(kb);
_e_kbd_buf_matches_update(kb);
}
static void
_e_kbd_buf_keystroke_point_add(E_Kbd_Buf *kb, E_Kbd_Buf_Keystroke *ks)
{
Eina_List *l;
for (l = ks->layout->keys; l; l = l->next)
{
E_Kbd_Buf_Key *ky;
const char *str;
int px, py, dx, dy, d;
ky = l->data;
px = ky->x + (ky->w / 2);
py = ky->y + (ky->h / 2);
dx = ks->x - px;
dy = ks->y - py;
d = sqrt((dx * dx) + (dy * dy));
if (d <= ks->layout->fuzz)
{
str = _e_kbd_buf_keystroke_key_string_get(kb, ks, ky);
if (str)
{
if (kb->dict.sys) e_kbd_dict_word_letter_add(kb->dict.sys, str, d);
if (kb->dict.personal) e_kbd_dict_word_letter_add(kb->dict.personal, str, d);
if (kb->dict.data) e_kbd_dict_word_letter_add(kb->dict.data, str, d);
}
}
}
}
EAPI void
e_kbd_buf_pressed_point_add(E_Kbd_Buf *kb, int x, int y, int shift, int capslock)
{
E_Kbd_Buf_Keystroke *ks;
e_kbd_buf_lookup_cancel(kb);
if (!kb->layout) kb->layout = _e_kbd_buf_new();
if (!kb->layout) return;
ks = E_NEW(E_Kbd_Buf_Keystroke, 1);
if (!ks) return;
ks->x = x;
ks->y = y;
if (shift) ks->shift = 1;
if (capslock) ks->capslock = 1;
ks->layout = kb->layout;
_e_kbd_buf_layout_ref(ks->layout);
kb->keystrokes = eina_list_append(kb->keystrokes, ks);
if (kb->dict.sys) e_kbd_dict_word_letter_advance(kb->dict.sys);
if (kb->dict.personal) e_kbd_dict_word_letter_advance(kb->dict.personal);
if (kb->dict.data) e_kbd_dict_word_letter_advance(kb->dict.data);
_e_kbd_buf_keystroke_point_add(kb, ks);
_e_kbd_buf_actual_string_update(kb);
_e_kbd_buf_matches_update(kb);
}
EAPI const char *
e_kbd_buf_actual_string_get(E_Kbd_Buf *kb)
{
return kb->actual_string;
}
EAPI const Eina_List *
e_kbd_buf_string_matches_get(E_Kbd_Buf *kb)
{
return kb->string_matches;
}
EAPI void
e_kbd_buf_backspace(E_Kbd_Buf *kb)
{
Eina_List *l;
l = eina_list_last(kb->keystrokes);
if (l)
{
E_Kbd_Buf_Keystroke *ks;
ks = l->data;
if (ks->key) eina_stringshare_del(ks->key);
_e_kbd_buf_layout_unref(ks->layout);
free(ks);
kb->keystrokes = eina_list_remove_list(kb->keystrokes, l);
if (kb->dict.sys) e_kbd_dict_word_letter_delete(kb->dict.sys);
if (kb->dict.personal) e_kbd_dict_word_letter_delete(kb->dict.personal);
if (kb->dict.data) e_kbd_dict_word_letter_delete(kb->dict.data);
_e_kbd_buf_actual_string_update(kb);
_e_kbd_buf_matches_update(kb);
}
}
EAPI void
e_kbd_buf_word_use(E_Kbd_Buf *kb, const char *word)
{
if (kb->dict.personal)
e_kbd_dict_word_usage_adjust(kb->dict.personal, word, 1);
}
// FIXME: just faking delayed lookup with timer
static Eina_Bool
_e_kbd_buf_cb_faket(void *data)
{
E_Kbd_Buf *kb;
kb = data;
kb->lookup.faket = NULL;
kb->lookup.func((void *)kb->lookup.data);
kb->lookup.func = NULL;
kb->lookup.data = NULL;
return ECORE_CALLBACK_CANCEL;
}
EAPI void
e_kbd_buf_lookup(E_Kbd_Buf *kb, void (*func) (void *data), const void *data)
{
e_kbd_buf_lookup_cancel(kb);
kb->lookup.func = func;
kb->lookup.data = data;
// FIXME: just faking delayed lookup with timer
kb->lookup.faket = ecore_timer_add(0.1, _e_kbd_buf_cb_faket, kb);
}
EAPI void
e_kbd_buf_lookup_cancel(E_Kbd_Buf *kb)
{
// FIXME: just faking delayed lookup with timer
if (!kb->lookup.faket) return;
ecore_timer_del(kb->lookup.faket);
kb->lookup.faket = NULL;
kb->lookup.func = NULL;
kb->lookup.data = NULL;
}

@ -0,0 +1,73 @@
#ifndef E_KBD_BUF_H
#define E_KBD_BUF_H
#include "e_kbd_dict.h"
typedef struct _E_Kbd_Buf E_Kbd_Buf;
typedef struct _E_Kbd_Buf_Key E_Kbd_Buf_Key;
typedef struct _E_Kbd_Buf_Keystroke E_Kbd_Buf_Keystroke;
typedef struct _E_Kbd_Buf_Layout E_Kbd_Buf_Layout;
struct _E_Kbd_Buf
{
const char *sysdicts;
Eina_List *keystrokes;
Eina_List *string_matches;
const char *actual_string;
E_Kbd_Buf_Layout *layout;
struct {
void (*func) (void *data);
const void *data;
// FIXME: just faking delayed lookup with timer
Ecore_Timer *faket;
} lookup;
struct {
E_Kbd_Dict *sys;
E_Kbd_Dict *personal;
E_Kbd_Dict *data;
Ecore_File_Monitor *data_monitor;
Ecore_Timer *data_reload_delay;
} dict;
};
struct _E_Kbd_Buf_Key
{
int x, y, w, h;
const char *key, *key_shift, *key_capslock, *key_altgr;
};
struct _E_Kbd_Buf_Keystroke
{
const char *key;
int x, y;
E_Kbd_Buf_Layout *layout;
unsigned char shift : 1;
unsigned char capslock : 1;
};
struct _E_Kbd_Buf_Layout
{
int ref;
int w, h;
int fuzz;
Eina_List *keys;
};
EAPI E_Kbd_Buf *e_kbd_buf_new(const char *sysdicts, const char *dicts);
EAPI void e_kbd_buf_free(E_Kbd_Buf *kb);
EAPI void e_kbd_buf_dict_set(E_Kbd_Buf *kb, const char *dict);
EAPI void e_kbd_buf_clear(E_Kbd_Buf *kb);
EAPI void e_kbd_buf_layout_clear(E_Kbd_Buf *kb);
EAPI void e_kbd_buf_layout_size_set(E_Kbd_Buf *kb, int w, int h);
EAPI void e_kbd_buf_layout_fuzz_set(E_Kbd_Buf *kb, int fuzz);
EAPI void e_kbd_buf_layout_key_add(E_Kbd_Buf *kb, const char *key, const char *key_shift, const char *key_capslock, const char *key_altgr, int x, int y, int w, int h);
EAPI void e_kbd_buf_pressed_key_add(E_Kbd_Buf *kb, const char *key, int shift, int capslock);
EAPI void e_kbd_buf_pressed_point_add(E_Kbd_Buf *kb, int x, int y, int shift, int capslock);
EAPI const char *e_kbd_buf_actual_string_get(E_Kbd_Buf *kb);
EAPI const Eina_List *e_kbd_buf_string_matches_get(E_Kbd_Buf *kb);
EAPI void e_kbd_buf_backspace(E_Kbd_Buf *kb);
EAPI void e_kbd_buf_lookup(E_Kbd_Buf *kb, void (*func) (void *data), const void *data);
EAPI void e_kbd_buf_lookup_cancel(E_Kbd_Buf *kb);
EAPI void e_kbd_buf_word_use(E_Kbd_Buf *kb, const char *word);
#endif

@ -0,0 +1,205 @@
#include "e.h"
#include "e_mod_main.h"
#include "e_kbd_cfg.h"
#include "e_kbd_buf.h"
static E_Kbd_Int *cfg_kbd = NULL;
static Eina_List *dicts = NULL;
static Evas_Object *win = NULL;
static void
_cb_close(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
e_kbd_cfg_hide(cfg_kbd);
}
static void
_cb_del(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
char *s;
EINA_LIST_FREE(dicts, s) eina_stringshare_del(s);
win = NULL;
cfg_kbd = NULL;
}
static void
_cb_size(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
double v = elm_slider_value_get(obj);
il_kbd_cfg->size = v;
e_kbd_int_update(cfg_kbd);
e_config_save_queue();
}
static void
_cb_fill_mode(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
il_kbd_cfg->fill_mode = (int)(uintptr_t)data;
if (il_kbd_cfg->fill_mode == 0) elm_object_text_set(obj, _("Shrink"));
else if (il_kbd_cfg->fill_mode == 1) elm_object_text_set(obj, _("Stretch"));
else if (il_kbd_cfg->fill_mode == 2) elm_object_text_set(obj, _("Fill"));
else if (il_kbd_cfg->fill_mode == 3) elm_object_text_set(obj, _("Float"));
e_kbd_int_update(cfg_kbd);
e_config_save_queue();
}
static void
_cb_dict(void *data, Evas_Object *li EINA_UNUSED, void *event_info EINA_UNUSED)
{
char *s = data;
eina_stringshare_replace(&il_kbd_cfg->dict, s);
e_kbd_buf_dict_set(cfg_kbd->kbuf, il_kbd_cfg->dict);
e_kbd_buf_clear(cfg_kbd->kbuf);
e_config_save_queue();
}
EAPI void
e_kbd_cfg_show(E_Kbd_Int *ki)
{
Evas_Object *o, *box, *fr, *li, *tb;
Elm_Object_Item *it;
Eina_List *files;
char buf[PATH_MAX], *p, *f;
const char *p2;
if (cfg_kbd) return;
cfg_kbd = ki;
win = e_elm_win_util_dialog_add(NULL, "vkbd_config",
_("Virtual Keyboard Settings"));
evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _cb_del, NULL);
elm_win_autodel_set(win, EINA_TRUE);
o = fr = elm_frame_add(win);
E_EXPAND(o);
E_FILL(o);
elm_object_style_set(o, "pad_large");
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_win_resize_object_add(win, o);
evas_object_show(o);
box = o = elm_box_add(win);
E_EXPAND(o);
E_FILL(o);
elm_object_content_set(fr, o);
evas_object_show(o);
o = fr = elm_frame_add(win);
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_layout_text_set(o, NULL, _("Layout Mode"));
elm_box_pack_end(box, o);
evas_object_show(o);
o = elm_hoversel_add(win);
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_hoversel_auto_update_set(o, EINA_TRUE);
elm_hoversel_hover_parent_set(o, win);
if (il_kbd_cfg->fill_mode == 0) elm_object_text_set(o, _("Shrink"));
else if (il_kbd_cfg->fill_mode == 1) elm_object_text_set(o, _("Stretch"));
else if (il_kbd_cfg->fill_mode == 2) elm_object_text_set(o, _("Fill"));
else if (il_kbd_cfg->fill_mode == 3) elm_object_text_set(o, _("Float"));
elm_hoversel_item_add(o, _("Shrink"), NULL, ELM_ICON_NONE, _cb_fill_mode, (void *)(uintptr_t)0);
elm_hoversel_item_add(o, _("Stretch"), NULL, ELM_ICON_NONE, _cb_fill_mode, (void *)(uintptr_t)1);
elm_hoversel_item_add(o, _("Fill"), NULL, ELM_ICON_NONE, _cb_fill_mode, (void *)(uintptr_t)2);
elm_hoversel_item_add(o, _("Float"), NULL, ELM_ICON_NONE, _cb_fill_mode, (void *)(uintptr_t)3);
elm_object_content_set(fr, o);
evas_object_show(o);
o = fr = elm_frame_add(win);
E_EXPAND(o);
E_FILL(o);
elm_layout_text_set(o, NULL, _("Dictionary"));
elm_box_pack_end(box, o);
evas_object_show(o);
o = tb = elm_table_add(win);
E_EXPAND(o);
E_FILL(o);
elm_object_content_set(fr, o);
evas_object_show(o);
o = evas_object_rectangle_add(evas_object_evas_get(win));
E_EXPAND(o);
E_FILL(o);
evas_object_color_set(o, 0, 0, 0, 0);
evas_object_size_hint_min_set(o,
elm_config_scale_get() * 80,
elm_config_scale_get() * 80);
elm_table_pack(tb, o, 0, 0, 1, 1);
o = li = elm_list_add(win);
E_EXPAND(o);
E_FILL(o);
snprintf(buf, sizeof(buf), "%s/dicts", ki->syskbds);
files = ecore_file_ls(buf);
EINA_LIST_FREE(files, f)
{
strncpy(buf, f, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
p = strrchr(buf, '.');
if ((p) && (!strcasecmp(p, ".dic")))
{
p2 = eina_stringshare_add(buf);
dicts = eina_list_append(dicts, p2);
*p = 0;
it = elm_list_item_append(li, buf, NULL, NULL, _cb_dict, p2);
if (!strcasecmp(p2, il_kbd_cfg->dict))
elm_list_item_selected_set(it, EINA_TRUE);
}
free(f);
}
elm_list_go(o);
elm_table_pack(tb, o, 0, 0, 1, 1);
evas_object_show(o);
o = fr = elm_frame_add(win);
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_layout_text_set(o, NULL, _("Sizing"));
elm_box_pack_end(box, o);
evas_object_show(o);
o = elm_slider_add(win);
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_slider_unit_format_set(o, "%1.1f");
elm_slider_step_set(o, 0.2);
elm_slider_span_size_set(o, 240);
elm_slider_min_max_set(o, 1.0, 9.0);
elm_slider_value_set(o, il_kbd_cfg->size);
evas_object_smart_callback_add(o, "changed", _cb_size, NULL);
elm_object_content_set(fr, o);
evas_object_show(o);
o = elm_separator_add(win);
elm_separator_horizontal_set(o, EINA_TRUE);
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(box, o);
evas_object_show(o);
o = elm_button_add(win);
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_object_text_set(o, _("Close"));
evas_object_smart_callback_add(o, "clicked", _cb_close, NULL);
elm_box_pack_end(box, o);
evas_object_show(o);
evas_object_show(win);
evas_smart_objects_calculate(evas_object_evas_get(win));
elm_win_center(win, 1, 1);
}
EAPI void
e_kbd_cfg_hide(E_Kbd_Int *ki)
{
if (!ki) return;
if (cfg_kbd != ki) return;
if (win) evas_object_del(win);
cfg_kbd = NULL;
}

@ -0,0 +1,9 @@
#ifndef E_KBD_CFG_H
#define E_KBD_CFG_H
#include "e_kbd_int.h"
EAPI void e_kbd_cfg_show(E_Kbd_Int *ki);
EAPI void e_kbd_cfg_hide(E_Kbd_Int *ki);
#endif

@ -0,0 +1,880 @@
#include "e.h"
#include "e_kbd_dict.h"
#include <fcntl.h>
#include <sys/mman.h>
#define MAXLATIN 0x100
static unsigned char _e_kbd_normalise_base[MAXLATIN];
static unsigned char _e_kbd_normalise_ready = 0;
static void
_e_kbd_normalise_init(void)
{
int i;
const char *table[][2] =
{
{"À", "a"},
{"Á", "a"},
{"Â", "a"},
{"Ã", "a"},
{"Ä", "a"},
{"Å", "a"},
{"Æ", "a"},
{"Ç", "c"},
{"È", "e"},
{"É", "e"},
{"Ê", "e"},
{"Ë", "e"},
{"Ì", "i"},
{"Í", "i"},
{"Î", "i"},
{"Ï", "i"},
{"Ð", "d"},
{"Ñ", "n"},
{"Ò", "o"},
{"Ó", "o"},
{"Ô", "o"},
{"Õ", "o"},
{"Ö", "o"},
{"×", "x"},
{"Ø", "o"},
{"Ù", "u"},
{"Ú", "u"},
{"Û", "u"},
{"Ü", "u"},
{"Ý", "y"},
{"Þ", "p"},
{"ß", "s"},
{"à", "a"},
{"á", "a"},
{"â", "a"},
{"ã", "a"},
{"ä", "a"},
{"å", "a"},
{"æ", "a"},
{"ç", "c"},
{"è", "e"},
{"é", "e"},
{"ê", "e"},
{"ë", "e"},
{"ì", "i"},
{"í", "i"},
{"î", "i"},
{"ï", "i"},
{"ð", "o"},
{"ñ", "n"},
{"ò", "o"},
{"ó", "o"},
{"ô", "o"},
{"õ", "o"},
{"ö", "o"},
{"ø", "o"},
{"ù", "u"},
{"ú", "u"},
{"û", "u"},
{"ü", "u"},
{"ý", "y"},
{"þ", "p"},
{"ÿ", "y"}
}; // 63 items
if (_e_kbd_normalise_ready) return;
_e_kbd_normalise_ready = 1;
for (i = 0; i < 128; i++)
_e_kbd_normalise_base[i] = tolower(i);
for (;i < MAXLATIN; i++)
{
int glyph, j;
for (j = 0; j < 63; j++)
{
evas_string_char_next_get(table[j][0], 0, &glyph);
if (glyph == i)
{
_e_kbd_normalise_base[i] = *table[j][1];
break;
}
}
}
}
static int
_e_kbd_dict_letter_normalise(int glyph)
{
// FIXME: ö -> o, ä -> a, Ó -> o etc. - ie normalise to latin-1
if (glyph < MAXLATIN) return _e_kbd_normalise_base[glyph];
return tolower(glyph) & 0x7f;
}
static int
_e_kbd_dict_normalized_strncmp(const char *a, const char *b, int len)
{
// FIXME: normalise 2 strings and then compare
if (len < 0) return strcasecmp(a, b);
return strncasecmp(a, b, len);
}
static int
_e_kbd_dict_normalized_strcmp(const char *a, const char *b)
{
return _e_kbd_dict_normalized_strncmp(a, b, -1);
}
static void
_e_kbd_dict_normalized_strcpy(char *dst, const char *src)
{
const char *p;
char *d;
for (p = src, d = dst; *p; p++, d++)
*d = _e_kbd_dict_letter_normalise(*p);
*d = 0;
}
static int
_e_kbd_dict_matches_lookup_cb_sort(const void *d1, const void *d2)
{
const E_Kbd_Dict_Word *kw1, *kw2;
kw1 = d1;
kw2 = d2;
if (kw1->usage < kw2->usage) return 1;
else if (kw1->usage > kw2->usage) return -1;
return 0;
}
static int
_e_kbd_dict_writes_cb_sort(const void *d1, const void *d2)
{
const E_Kbd_Dict_Word *kw1, *kw2;
kw1 = d1;
kw2 = d2;
return _e_kbd_dict_normalized_strcmp(kw1->word, kw2->word);
}
static const char *
_e_kbd_dict_line_next(E_Kbd_Dict *kd, const char *p)
{
const char *e, *pp;
e = kd->file.dict + kd->file.size;
for (pp = p; pp < e; pp++)
if (*pp == '\n') return pp + 1;
return NULL;
}
static char *
_e_kbd_dict_line_parse(E_Kbd_Dict *kd EINA_UNUSED, const char *p, int *usage)
{
const char *ps;
char *wd = NULL;
for (ps = p; !isspace(*ps); ps++);
wd = malloc(ps - p + 1);
if (!wd) return NULL;
strncpy(wd, p, ps - p);
wd[ps - p] = 0;
if (*ps == '\n') *usage = 0;
else
{
ps++;
*usage = atoi(ps);
}
return wd;
}
static void
_e_kbd_dict_lookup_build_line(E_Kbd_Dict *kd EINA_UNUSED, const char *p, const char *eol, int *glyphs)
{
char *s;
int p2;
s = alloca(eol - p + 1);
strncpy(s, p, eol - p);
s[eol - p] = 0;
p2 = evas_string_char_next_get(s, 0, &(glyphs[0]));
if ((p2 > 0) && (glyphs[0] > 0))
evas_string_char_next_get(s, p2, &(glyphs[1]));
}
static void
_e_kbd_dict_lookup_build(E_Kbd_Dict *kd)
{
const char *p, *e, *eol, *base;
int glyphs[2], pglyphs[2];
int i, j, line = 0;
p = base = kd->file.dict;
e = p + kd->file.size;
pglyphs[0] = pglyphs[1] = 0;
for (j = 0; j < 128; j++)
{
for (i = 0; i < 128; i++)
kd->lookup.tuples[j][i] = -1;
}
while (p < e)
{
eol = strchr(p, '\n');
if (!eol) break;
line++;
if ((p - base) >= 0x7fffffff)
{
ERR("DICT %s TOO BIG! must be < 2GB", kd->file.file);
return;
}
if (eol > p)
{
glyphs[0] = glyphs[1] = 0;
_e_kbd_dict_lookup_build_line(kd, p, eol, glyphs);
if ((glyphs[1] != pglyphs[1]) || (glyphs[0] != pglyphs[0]))
{
int v1, v2;
if (isspace(glyphs[0]))
{
glyphs[0] = 0;
glyphs[1] = 0;
}
else if (isspace(glyphs[1]))
glyphs[1] = 0;
if (glyphs[0] == 0)
{
pglyphs[0] = pglyphs[1] = 0;
p = eol + 1;
continue;
}
v1 = _e_kbd_dict_letter_normalise(glyphs[0]);
v2 = _e_kbd_dict_letter_normalise(glyphs[1]);
if (kd->lookup.tuples[v1][v2] == -1)
kd->lookup.tuples[v1][v2] = (unsigned int)(p - base);
pglyphs[0] = v1;
pglyphs[1] = v2;
}
}
p = eol + 1;
}
}
static int
_e_kbd_dict_open(E_Kbd_Dict *kd)
{
struct stat st;
kd->file.fd = open(kd->file.file, O_RDONLY);
if (kd->file.fd < 0) return 0;
if (fstat(kd->file.fd, &st) < 0)
{
close(kd->file.fd);
return 0;
}
kd->file.size = st.st_size;
eina_mmap_safety_enabled_set(EINA_TRUE);
kd->file.dict = mmap(NULL, kd->file.size, PROT_READ, MAP_SHARED,
kd->file.fd, 0);
if ((kd->file.dict== MAP_FAILED) || (!kd->file.dict))
{
close(kd->file.fd);
return 0;
}
return 1;
}
static void
_e_kbd_dict_close(E_Kbd_Dict *kd)
{
if (kd->file.fd < 0) return;
memset(kd->lookup.tuples, 0, sizeof(kd->lookup.tuples));
munmap((void *)kd->file.dict, kd->file.size);
close(kd->file.fd);
kd->file.fd = -1;
kd->file.dict = NULL;
kd->file.size = 0;
}
EAPI E_Kbd_Dict *
e_kbd_dict_new(const char *file)
{
// alloc and load new dict - build quick-lookup table. words MUST be sorted
E_Kbd_Dict *kd;
_e_kbd_normalise_init();
kd = E_NEW(E_Kbd_Dict, 1);
if (!kd) return NULL;
kd->file.file = eina_stringshare_add(file);
if (!kd->file.file)
{
free(kd);
return NULL;
}
kd->file.fd = -1;
if (!_e_kbd_dict_open(kd))
{
eina_stringshare_del(kd->file.file);
free(kd);
return NULL;
}
_e_kbd_dict_lookup_build(kd);
return kd;
}
EAPI void
e_kbd_dict_free(E_Kbd_Dict *kd)
{
// free dict and anything in it
e_kbd_dict_word_letter_clear(kd);
e_kbd_dict_save(kd);
_e_kbd_dict_close(kd);
free(kd);
}
static E_Kbd_Dict_Word *
_e_kbd_dict_changed_write_find(E_Kbd_Dict *kd, const char *word)
{
Eina_List *l;
for (l = kd->changed.writes; l; l = l->next)
{
E_Kbd_Dict_Word *kw;
kw = l->data;
if (!strcmp(kw->word, word)) return kw;
}
return NULL;
}
EAPI void
e_kbd_dict_save(E_Kbd_Dict *kd)
{
FILE *f;
// XXX: disable personal dict saving for now as we don't merge personal
// XXX: and system dict stats very well at all
return;
// save any changes (new words added, usage adjustments).
// all words MUST be sorted
if (!kd->changed.writes) return;
if (kd->changed.flush_timer)
{
ecore_timer_del(kd->changed.flush_timer);
kd->changed.flush_timer = NULL;
}
ecore_file_unlink(kd->file.file);
f = fopen(kd->file.file, "w");
kd->changed.writes = eina_list_sort(kd->changed.writes,
eina_list_count(kd->changed.writes),
_e_kbd_dict_writes_cb_sort);
if (f)
{
const char *p, *pn;
p = kd->file.dict;
while (p)
{
char *wd;
int usage = 0;
pn = _e_kbd_dict_line_next(kd, p);
if (!pn)
{
fclose(f);
return;
}
wd = _e_kbd_dict_line_parse(kd, p, &usage);
if ((wd) && (strlen(wd) > 0))
{
if (kd->changed.writes)
{
int writeline = 0;
while (kd->changed.writes)
{
E_Kbd_Dict_Word *kw;
int cmp;
kw = kd->changed.writes->data;
cmp = _e_kbd_dict_normalized_strcmp(kw->word, wd);
if (cmp < 0)
{
fprintf(f, "%s %i\n", kw->word, kw->usage);
writeline = 1;
eina_stringshare_del(kw->word);
free(kw);
kd->changed.writes = eina_list_remove_list(kd->changed.writes, kd->changed.writes);
}
else if (cmp == 0)
{
fprintf(f, "%s %i\n", wd, kw->usage);
if (!strcmp(kw->word, wd))
writeline = 0;
else
writeline = 1;
eina_stringshare_del(kw->word);
free(kw);