1
// Copyright 2010, Google Inc.
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
8
// * Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// * Redistributions in binary form must reproduce the above
11
// copyright notice, this list of conditions and the following disclaimer
12
// in the documentation and/or other materials provided with the
14
// * Neither the name of Google Inc. nor the names of its
15
// contributors may be used to endorse or promote products derived from
16
// this software without specific prior written permission.
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
#include "unix/scim/scim_mozc.h"
34
#include "base/const.h"
35
#include "base/logging.h"
36
#include "base/process.h"
37
#include "base/util.h"
38
#include "unix/scim/mozc_connection.h"
39
#include "unix/scim/mozc_lookup_table.h"
40
#include "unix/scim/mozc_response_parser.h"
41
#include "unix/scim/scim_key_translator.h"
45
const char kConfigName[] = "/Panel/Gtk/LookupTableVertical";
47
const char kPropTool[] = "/Mozc/Tool";
48
const char kPropToolIcon[] = SCIM_ICONDIR "/scim-mozc-tool.png";
49
const char kPropToolDictionary[] = "/Mozc/Tool/dictionary";
50
const char kPropToolDictionaryIcon[] = SCIM_ICONDIR "/scim-mozc-dictionary.png";
51
const char kPropToolProperty[] = "/Mozc/Tool/property";
52
const char kPropToolPropertyIcon[] = SCIM_ICONDIR "/scim-mozc-property.png";
54
const char kPropCompositionModeIcon[] = "/Mozc/CompositionMode";
56
const struct CompositionMode {
59
const char *config_path;
60
const char *description;
61
mozc::commands::CompositionMode mode;
62
} kPropCompositionModes[] = {
64
"", // TODO(yusukes): use icons.
66
"/Mozc/CompositionMode/direct",
68
mozc::commands::DIRECT,
71
"\xe3\x81\x82", // Hiragana letter A in UTF-8.
72
"/Mozc/CompositionMode/hiragana",
74
mozc::commands::HIRAGANA,
77
"\xe3\x82\xa2", // Katakana letter A.
78
"/Mozc/CompositionMode/full_katakana",
80
mozc::commands::FULL_KATAKANA,
84
"/Mozc/CompositionMode/half_ascii",
86
mozc::commands::HALF_ASCII,
89
"\xef\xbc\xa1", // Full width ASCII letter A.
90
"/Mozc/CompositionMode/full_ascii",
92
mozc::commands::FULL_ASCII,
95
"_\xef\xbd\xb1", // Half width Katakana letter A.
96
"/Mozc/CompositionMode/half_katakana",
98
mozc::commands::HALF_KATAKANA,
101
const size_t kNumCompositionModes = arraysize(kPropCompositionModes);
103
// This array must correspond with the CompositionMode enum in the
104
// mozc/session/command.proto file.
106
mozc::commands::NUM_OF_COMPOSITIONS == arraysize(kPropCompositionModes),
107
bad_number_of_modes);
111
namespace mozc_unix_scim {
114
ScimMozc *ScimMozc::CreateScimMozc(scim::IMEngineFactoryBase *factory,
115
const scim::String &encoding, int id,
116
const scim::ConfigPointer *config) {
117
return new ScimMozc(factory, encoding, id,
119
MozcConnection::CreateMozcConnection(),
120
new MozcResponseParser);
124
ScimMozc::ScimMozc(scim::IMEngineFactoryBase *factory,
125
const scim::String &encoding, int id,
126
const scim::ConfigPointer *config,
127
MozcConnectionInterface *connection,
128
MozcResponseParser *parser)
129
: scim::IMEngineInstanceBase(factory, encoding, id),
130
connection_(connection),
132
composition_mode_(mozc::commands::HIRAGANA) {
133
VLOG(1) << "ScimMozc created.";
134
const bool is_vertical
135
= config ? (*config)->read(kConfigName, false) : false;
136
parser_->set_use_annotation(is_vertical);
140
ScimMozc::~ScimMozc() {
141
VLOG(1) << "ScimMozc destroyed.";
144
// This function is called from SCIM framework when users press or release a
146
bool ScimMozc::process_key_event(const scim::KeyEvent &key) {
147
VLOG(1) << "process_key_event, key.code=" << key.code;
149
if (!connection_->CanSend(key)) {
150
VLOG(1) << "Mozc doesn't handle the key. Not consumed.";
151
return false; // not consumed.
155
mozc::commands::Output raw_response;
156
if (!connection_->TrySendKeyEvent(
157
key, composition_mode_, &raw_response, &error)) {
158
// TODO(yusukes): Show |error|.
159
return false; // not consumed.
162
return ParseResponse(raw_response);
165
// This function is called from SCIM framework when users click the candidate
167
void ScimMozc::select_candidate(unsigned int index) {
168
VLOG(1) << "select_candidate, index=" << index;
170
if (!candidates_.get()) {
171
LOG(ERROR) << "Candidate window clicked, but we don't have the instance.";
175
const int32 id = candidates_->GetId(index);
176
if (id == kBadCandidateId) {
177
LOG(ERROR) << "The clicked candidate doesn't have unique ID.";
180
VLOG(1) << "select_candidate, id=" << id;
183
mozc::commands::Output raw_response;
184
if (!connection_->TrySendClick(id, &raw_response, &error)) {
185
LOG(ERROR) << "IPC failed. error=" << error;
189
ParseResponse(raw_response);
193
// This function is called from SCIM framework.
194
void ScimMozc::reset() {
197
mozc::commands::Output raw_response;
198
if (connection_->TrySendCommand(
199
mozc::commands::SessionCommand::REVERT, &raw_response, &error)) {
200
parser_->ParseResponse(raw_response, this);
202
ClearAll(); // just in case.
206
// This function is called from SCIM framework when the ic gets focus.
207
void ScimMozc::focus_in() {
208
VLOG(1) << "focus_in";
213
// This function is called when the ic loses focus.
214
void ScimMozc::focus_out() {
215
VLOG(1) << "focus_out";
217
mozc::commands::Output raw_response;
218
if (connection_->TrySendCommand(
219
mozc::commands::SessionCommand::REVERT, &raw_response, &error)) {
220
parser_->ParseResponse(raw_response, this);
222
ClearAll(); // just in case.
224
// TODO(yusukes): Call session::SyncData() like ibus-mozc.
227
// This function is called from SCIM framework when Mozc related icon in the
228
// SCIM toolbar is pressed.
229
void ScimMozc::trigger_property(const scim::String &property) {
230
VLOG(1) << "trigger_property: " << property;
232
for (size_t i = 0; i < kNumCompositionModes; ++i) {
233
if (property == kPropCompositionModes[i].config_path) {
234
if (kPropCompositionModes[i].mode == mozc::commands::DIRECT) {
235
// Commit a preedit string.
237
mozc::commands::Output raw_response;
238
if (connection_->TrySendCommand(mozc::commands::SessionCommand::SUBMIT,
239
&raw_response, &error)) {
240
parser_->ParseResponse(raw_response, this);
243
// Switch to the DIRECT mode.
244
SetCompositionMode(mozc::commands::DIRECT);
246
// Send the SWITCH_INPUT_MODE command.
248
mozc::commands::Output raw_response;
249
if (connection_->TrySendCompositionMode(
250
kPropCompositionModes[i].mode, &raw_response, &error)) {
251
parser_->ParseResponse(raw_response, this);
259
if (property == kPropToolDictionary) {
260
args = "--mode=dictionary_tool";
261
} else if (property == kPropToolProperty) {
262
args = "--mode=config_dialog";
269
// TODO(yusukes): Use session::LaunchTool().
270
mozc::Process::SpawnMozcProcess("mozc_tool", args);
273
bool ScimMozc::ParseResponse(const mozc::commands::Output &raw_response) {
275
const bool consumed = parser_->ParseResponse(raw_response, this);
277
VLOG(1) << "The input was not consumed by Mozc.";
284
void ScimMozc::SetResultString(const scim::WideString &result_string) {
285
commit_string(result_string);
288
void ScimMozc::SetCandidateWindow(const MozcLookupTable *new_candidates) {
289
candidates_.reset(new_candidates);
292
void ScimMozc::SetPreeditInfo(const PreeditInfo *preedit_info) {
293
preedit_info_.reset(preedit_info);
296
void ScimMozc::SetAuxString(const scim::String &str) {
300
void ScimMozc::SetCompositionMode(mozc::commands::CompositionMode mode) {
301
composition_mode_ = mode;
303
const char *icon = GetCurrentCompositionModeIcon();
304
const char *label = GetCurrentCompositionModeLabel();
305
scim::Property p = scim::Property(
306
kPropCompositionModeIcon, label, icon, "Composition mode");
310
void ScimMozc::SetUrl(const string &url) {
314
void ScimMozc::ClearAll() {
315
SetCandidateWindow(NULL);
316
SetPreeditInfo(NULL);
321
void ScimMozc::DrawCandidateWindow() {
322
if (!candidates_.get()) {
323
VLOG(1) << "HideCandidateWindow";
326
VLOG(1) << "DrawCandidateWindow";
327
update_lookup_table(*candidates_.get());
332
void ScimMozc::DrawPreeditInfo() {
333
if (!preedit_info_.get()) {
334
hide_preedit_string();
336
VLOG(1) << "DrawPreeditInfo: cursor=" << preedit_info_->cursor_pos;
337
update_preedit_string(preedit_info_->str,
338
preedit_info_->attribute_list);
339
update_preedit_caret(preedit_info_->cursor_pos);
340
show_preedit_string();
344
void ScimMozc::DrawAux() {
348
update_aux_string(scim::utf8_mbstowcs(aux_));
353
void ScimMozc::DrawAll() {
356
DrawCandidateWindow();
359
void ScimMozc::OpenUrl() {
363
mozc::Process::OpenBrowser(url_);
367
void ScimMozc::InitializeBar() {
368
VLOG(1) << "Registering properties";
369
// TODO(yusukes): L10N needed for "Tool", "Dictionary", and "Property".
370
scim::PropertyList prop_list;
372
const char *icon = GetCurrentCompositionModeIcon();
373
const char *label = GetCurrentCompositionModeLabel();
374
scim::Property p = scim::Property(
375
kPropCompositionModeIcon, label, icon, "Composition mode");
376
prop_list.push_back(p);
377
for (size_t i = 0; i < kNumCompositionModes; ++i) {
378
p = scim::Property(kPropCompositionModes[i].config_path,
379
kPropCompositionModes[i].description,
380
kPropCompositionModes[i].icon,
381
kPropCompositionModes[i].description);
382
prop_list.push_back(p);
385
if (mozc::Util::FileExists(mozc::Util::JoinPath(
386
mozc::Util::GetServerDirectory(), mozc::kMozcTool))) {
387
// Construct "tool" icon and its menu.
388
p = scim::Property(kPropTool, "", kPropToolIcon, "Tool");
389
prop_list.push_back(p);
391
kPropToolDictionary, "Dictionary", kPropToolDictionaryIcon);
392
prop_list.push_back(p);
393
p = scim::Property(kPropToolProperty, "Property", kPropToolPropertyIcon);
394
prop_list.push_back(p);
397
register_properties(prop_list);
400
const char *ScimMozc::GetCurrentCompositionModeIcon() const {
401
DCHECK(composition_mode_ < kNumCompositionModes);
402
if (composition_mode_ < kNumCompositionModes) {
403
return kPropCompositionModes[composition_mode_].icon;
408
const char *ScimMozc::GetCurrentCompositionModeLabel() const {
409
DCHECK(composition_mode_ < kNumCompositionModes);
410
if (composition_mode_ < kNumCompositionModes) {
411
return kPropCompositionModes[composition_mode_].label;
416
} // namespace mozc_unix_scim