Skip to content

Commit bb84e3e

Browse files
committed
ibus-zinnia - Japanese handwriting recognition engine.
ibus-zinnia is a very thin wrapper of libzinnia, a open source handwriting recognition engine written in C++. The code of ibus-zinnia is based on suzhe's work at https://github.com/suzhe/ibus-xkb-layouts (thus Apache-2.0 license). Review URL: http://codereview.appspot.com/4428051
1 parent 85195ab commit bb84e3e

11 files changed

+245
-337
lines changed

configure.ac

+5-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
AC_INIT([ibus-xkb-layouts],
2-
[0.0.0],
3-
[https://github.com/suzhe/ibus-xkb-layouts])
1+
AC_INIT([ibus-zinnia],
2+
[0.0.1],
3+
[https://github.com/yusukes/ibus-zinnia])
44

55
AC_PREREQ([2.50])
66
AC_CONFIG_SRCDIR([src/main.c])
@@ -18,26 +18,15 @@ AC_HEADER_STDC
1818

1919
PKG_PROG_PKG_CONFIG([0.20])
2020

21-
AC_ARG_WITH([xkb-rules-xml],
22-
AC_HELP_STRING([--with-xkb-rules-xml=${datadir}/X11/xkb/rules/evdev.xml],
23-
[Specify the XKB rules xml file to be used.]),
24-
[XKB_RULES_XML_FILE=$withval],
25-
[XKB_RULES_XML_FILE="/usr/share/X11/xkb/rules/evdev.xml"])
26-
27-
AC_CHECK_FILE([$XKB_RULES_XML_FILE],[],[AC_MSG_ERROR([$XKB_RULES_XML_FILE is not available.])])
28-
29-
PREDEFINED_MACROS="-DXKB_RULES_XML_FILE=\\\"$XKB_RULES_XML_FILE\\\""
30-
AC_SUBST([PREDEFINED_MACROS])
31-
AC_SUBST([XKB_RULES_XML_FILE])
3221
AC_SUBST([datarootdir])
3322

3423
# check ibus
35-
PKG_CHECK_MODULES(IBUS, [ibus-1.0 >= 1.3.0])
24+
PKG_CHECK_MODULES(IBUS, [ibus-1.0 >= 1.3.99])
3625

3726
# OUTPUT files
3827
AC_CONFIG_FILES([Makefile
3928
src/Makefile
40-
src/xkb-layouts.xml.in
29+
src/zinnia.xml.in
4130
])
4231

4332
AC_OUTPUT

src/Makefile.am

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
1-
libexec_PROGRAMS = ibus-engine-xkb-layouts
1+
libexec_PROGRAMS = ibus-engine-zinnia
22

3-
ibus_engine_xkb_layouts_SOURCES = \
3+
ibus_engine_zinnia_SOURCES = \
44
main.c \
55
engine.c \
66
engine.h \
7-
xkbutil.c \
8-
xkbutil.h \
7+
zinnia_component.c \
8+
zinnia_component.h \
99
$(NULL)
10-
ibus_engine_xkb_layouts_CPPFLAGS = \
10+
ibus_engine_zinnia_CPPFLAGS = \
1111
$(PREDEFINED_MACROS) \
1212
$(NULL)
13-
ibus_engine_xkb_layouts_CFLAGS = \
13+
ibus_engine_zinnia_CFLAGS = \
1414
@IBUS_CFLAGS@ \
1515
$(NULL)
16-
ibus_engine_xkb_layouts_LDFLAGS = \
16+
ibus_engine_zinnia_LDFLAGS = \
1717
@IBUS_LIBS@ \
18+
-lzinnia \
1819
$(NULL)
1920

2021
component_DATA = \
21-
xkb-layouts.xml \
22+
zinnia.xml \
2223
$(NULL)
2324
componentdir = @datadir@/ibus/component
2425

2526
EXTRA_DIST = \
26-
xkb-layouts.xml.in \
27+
zinnia.xml.in \
2728
$(NULL)
2829

2930
CLEANFILES = \
30-
xkb-layouts.xml \
31+
zinnia.xml \
3132
$(NULL)
3233

33-
xkb-layouts.xml: xkb-layouts.xml.in
34+
zinnia.xml: zinnia.xml.in
3435
$(AM_V_GEN) \
3536
( \
3637
libexecdir=${libexecdir}; \

src/engine.c

+131-25
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,161 @@
1+
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2+
13
#include "engine.h"
4+
#include "zinnia.h"
25

3-
typedef struct _IBusXkbLayoutEngine IBusXkbLayoutEngine;
4-
typedef struct _IBusXkbLayoutEngineClass IBusXkbLayoutEngineClass;
6+
typedef struct _IBusZinniaEngine IBusZinniaEngine;
7+
typedef struct _IBusZinniaEngineClass IBusZinniaEngineClass;
58

6-
struct _IBusXkbLayoutEngine {
9+
struct _IBusZinniaEngine {
710
IBusEngine parent;
11+
zinnia_recognizer_t *recognizer;
12+
zinnia_character_t *character;
13+
zinnia_result_t *result;
14+
size_t stroke_count;
815
};
916

10-
struct _IBusXkbLayoutEngineClass {
17+
struct _IBusZinniaEngineClass {
1118
IBusEngineClass parent;
1219
};
1320

1421
/* functions prototype */
15-
static void ibus_xkb_layout_engine_class_init (IBusXkbLayoutEngineClass *klass);
16-
static void ibus_xkb_layout_engine_init (IBusXkbLayoutEngine *engine);
17-
static void ibus_xkb_layout_engine_destroy (IBusXkbLayoutEngine *engine);
18-
static gboolean ibus_xkb_layout_engine_process_key_event(IBusEngine *engine,
19-
guint keyval,
20-
guint keycode,
21-
guint modifiers);
22+
static void ibus_zinnia_engine_class_init (IBusZinniaEngineClass *klass);
23+
static void ibus_zinnia_engine_init (IBusZinniaEngine *engine);
24+
static void ibus_zinnia_engine_destroy (IBusZinniaEngine *engine);
25+
static void ibus_zinnia_engine_candidate_clicked (IBusEngine *engine,
26+
guint index,
27+
guint button,
28+
guint state);
29+
static void ibus_zinnia_engine_process_hand_writing_event
30+
(IBusEngine *engine,
31+
const gdouble *coordinates,
32+
guint coordinates_len);
33+
static void ibus_zinnia_engine_cancel_hand_writing
34+
(IBusEngine *engine,
35+
guint n_strokes);
36+
37+
G_DEFINE_TYPE (IBusZinniaEngine, ibus_zinnia_engine, IBUS_TYPE_ENGINE)
38+
39+
static const gint zinnia_xy = 1000;
40+
static const gchar model_path[] = "/usr/share/tegaki/models/zinnia/handwriting-ja.model";
41+
/* FIXME support Chinese and other languages */
2242

23-
G_DEFINE_TYPE (IBusXkbLayoutEngine, ibus_xkb_layout_engine, IBUS_TYPE_ENGINE)
43+
static gint
44+
normalize(gdouble x_or_y)
45+
{
46+
gint result = (gint)(x_or_y * zinnia_xy);
47+
if (result < 0)
48+
return 0;
49+
if (result > zinnia_xy)
50+
return zinnia_xy;
51+
return result;
52+
}
2453

2554
static void
26-
ibus_xkb_layout_engine_class_init (IBusXkbLayoutEngineClass *klass)
55+
ibus_zinnia_engine_class_init (IBusZinniaEngineClass *klass)
2756
{
2857
IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
2958
IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
3059

31-
ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_layout_engine_destroy;
60+
ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_zinnia_engine_destroy;
3261

33-
engine_class->process_key_event = ibus_xkb_layout_engine_process_key_event;
62+
engine_class->candidate_clicked = ibus_zinnia_engine_candidate_clicked;
63+
engine_class->process_hand_writing_event = ibus_zinnia_engine_process_hand_writing_event;
64+
engine_class->cancel_hand_writing = ibus_zinnia_engine_cancel_hand_writing;
3465
}
3566

3667
static void
37-
ibus_xkb_layout_engine_init (IBusXkbLayoutEngine *xkb_layout)
68+
ibus_zinnia_engine_init (IBusZinniaEngine *zinnia)
3869
{
70+
zinnia->recognizer = zinnia_recognizer_new ();
71+
zinnia->character = zinnia_character_new ();
72+
73+
g_return_if_fail (zinnia_recognizer_open (zinnia->recognizer, model_path));
74+
zinnia_character_clear (zinnia->character);
75+
zinnia_character_set_width (zinnia->character, zinnia_xy);
76+
zinnia_character_set_height (zinnia->character, zinnia_xy);
77+
zinnia->result = NULL;
78+
zinnia->stroke_count = 0;
3979
}
4080

4181
static void
42-
ibus_xkb_layout_engine_destroy (IBusXkbLayoutEngine *xkb_layout)
82+
ibus_zinnia_engine_destroy (IBusZinniaEngine *zinnia)
4383
{
44-
((IBusObjectClass *) ibus_xkb_layout_engine_parent_class)->destroy ((IBusObject *)xkb_layout);
84+
zinnia_character_destroy (zinnia->character);
85+
zinnia_recognizer_destroy (zinnia->recognizer);
86+
if (zinnia->result != NULL) {
87+
zinnia_result_destroy (zinnia->result);
88+
}
89+
((IBusObjectClass *) ibus_zinnia_engine_parent_class)->destroy ((IBusObject *) zinnia);
4590
}
4691

47-
static gboolean
48-
ibus_xkb_layout_engine_process_key_event (IBusEngine *engine,
49-
guint keyval,
50-
guint keycode,
51-
guint modifiers)
92+
static void
93+
ibus_zinnia_engine_candidate_clicked (IBusEngine *engine,
94+
guint index,
95+
guint button,
96+
guint state)
97+
{
98+
IBusZinniaEngine *zinnia = (IBusZinniaEngine *) engine;
99+
if (zinnia->result == NULL || index >= zinnia_result_size (zinnia->result)) {
100+
return;
101+
}
102+
IBusText *text = ibus_text_new_from_string (zinnia_result_value (zinnia->result, index));
103+
ibus_engine_commit_text (engine, text);
104+
ibus_engine_hide_lookup_table (engine);
105+
}
106+
107+
static void
108+
ibus_zinnia_engine_process_hand_writing_event (IBusEngine *engine,
109+
const gdouble *coordinates,
110+
guint coordinates_len)
52111
{
53-
/* TODO: Support Compose/Dead keys */
54-
return FALSE;
112+
static const gint max_candidates = 10;
113+
IBusZinniaEngine *zinnia = (IBusZinniaEngine *) engine;
114+
guint i;
115+
116+
g_return_if_fail (coordinates_len >= 4);
117+
g_return_if_fail ((coordinates_len & 1) == 0);
118+
119+
for (i = 1; i < coordinates_len; i += 2) {
120+
zinnia_character_add (zinnia->character,
121+
zinnia->stroke_count,
122+
normalize(coordinates[i - 1]),
123+
normalize(coordinates[i]));
124+
}
125+
zinnia->stroke_count++;
126+
127+
if (zinnia->result != NULL) {
128+
zinnia_result_destroy (zinnia->result);
129+
}
130+
zinnia->result = zinnia_recognizer_classify (zinnia->recognizer,
131+
zinnia->character,
132+
max_candidates);
133+
if (zinnia->result == NULL || zinnia_result_size (zinnia->result) == 0) {
134+
ibus_engine_hide_lookup_table (engine);
135+
} else {
136+
IBusLookupTable *table = ibus_lookup_table_new (max_candidates, /* page size */
137+
0, /* cursur pos */
138+
FALSE, /* cursor visible */
139+
TRUE); /* round */
140+
ibus_lookup_table_set_orientation (table, IBUS_ORIENTATION_VERTICAL);
141+
142+
for (i = 0; i < zinnia_result_size (zinnia->result); i++) {
143+
IBusText *text = ibus_text_new_from_string (zinnia_result_value (zinnia->result, i));
144+
ibus_lookup_table_append_candidate (table, text);
145+
}
146+
ibus_engine_update_lookup_table (engine, table, TRUE);
147+
}
148+
}
149+
150+
static void
151+
ibus_zinnia_engine_cancel_hand_writing (IBusEngine *engine,
152+
guint n_strokes)
153+
{
154+
IBusZinniaEngine *zinnia = (IBusZinniaEngine *) engine;
155+
156+
zinnia_character_clear (zinnia->character);
157+
zinnia->stroke_count = 0;
158+
ibus_engine_hide_lookup_table (engine);
159+
160+
/* FIXME support n_strokes != 0 cases */
55161
}

src/engine.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
#include <ibus.h>
55

6-
#define IBUS_TYPE_XKB_LAYOUT_ENGINE (ibus_xkb_layout_engine_get_type ())
6+
#define IBUS_TYPE_ZINNIA_ENGINE (ibus_zinnia_engine_get_type ())
77

8-
GType ibus_xkb_layout_engine_get_type (void);
8+
GType ibus_zinnia_engine_get_type (void);
99

1010
#endif

src/main.c

+8-32
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@
33
#include <stdio.h>
44
#include <stdlib.h>
55
#include "engine.h"
6-
#include "xkbutil.h"
6+
#include "zinnia_component.h"
77

88
static IBusBus *bus = NULL;
99
static IBusFactory *factory = NULL;
1010

1111
/* options */
12-
static gboolean xml = FALSE;
1312
static gboolean ibus = FALSE;
1413
static gboolean verbose = FALSE;
1514

1615
static const GOptionEntry entries[] =
1716
{
18-
{ "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "generate xml for engines", NULL },
1917
{ "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
2018
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "verbose", NULL },
2119
{ NULL },
@@ -41,18 +39,20 @@ start_component (void)
4139
bus = ibus_bus_new ();
4240
g_signal_connect (bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
4341

44-
component = ibus_xkb_get_component ();
42+
component = ibus_zinnia_get_component ();
4543

4644
factory = ibus_factory_new (ibus_bus_get_connection (bus));
4745

4846
engines = ibus_component_get_engines (component);
4947
for (p = engines; p != NULL; p = p->next) {
5048
IBusEngineDesc *engine = (IBusEngineDesc *)p->data;
51-
ibus_factory_add_engine (factory, engine->name, IBUS_TYPE_XKB_LAYOUT_ENGINE);
49+
ibus_factory_add_engine (factory,
50+
ibus_engine_desc_get_name(engine),
51+
IBUS_TYPE_ZINNIA_ENGINE);
5252
}
5353

5454
if (ibus) {
55-
ibus_bus_request_name (bus, "org.freedesktop.IBus.XKBLayouts", 0);
55+
ibus_bus_request_name (bus, "com.google.IBus.Zinnia", 0);
5656
}
5757
else {
5858
ibus_bus_register_component (bus, component);
@@ -63,25 +63,6 @@ start_component (void)
6363
ibus_main ();
6464
}
6565

66-
static void
67-
print_engines_xml (void)
68-
{
69-
IBusComponent *component;
70-
GString *output;
71-
72-
ibus_init ();
73-
74-
component = ibus_xkb_get_component ();
75-
output = g_string_new ("");
76-
77-
ibus_component_output_engines (component, output, 0);
78-
79-
fprintf (stdout, "%s", output->str);
80-
81-
g_string_free (output, TRUE);
82-
83-
}
84-
8566
int
8667
main (gint argc, gchar **argv)
8768
{
@@ -90,20 +71,15 @@ main (gint argc, gchar **argv)
9071

9172
setlocale (LC_ALL, "");
9273

93-
context = g_option_context_new ("- ibus XKB Layouts engine component");
74+
context = g_option_context_new ("- ibus zinnia engine component");
9475

95-
g_option_context_add_main_entries (context, entries, "ibus-xkb-layouts");
76+
g_option_context_add_main_entries (context, entries, "ibus-zinnia");
9677

9778
if (!g_option_context_parse (context, &argc, &argv, &error)) {
9879
g_print ("Option parsing failed: %s\n", error->message);
9980
exit (-1);
10081
}
10182

102-
if (xml) {
103-
print_engines_xml ();
104-
exit (0);
105-
}
106-
10783
start_component ();
10884
return 0;
10985
}

src/xkb-layouts.xml.in.in

-15
This file was deleted.

0 commit comments

Comments
 (0)