forked from enlightenment/enlightenment
parent
09a8888f76
commit
074b3fe1eb
37 changed files with 107822 additions and 0 deletions
@ -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
Binary file not shown.
@ -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); |
||||