1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. 5 * 6 * The contents of this file are subject to the terms of either the GNU Lesser 7 * General Public License Version 2.1 only ("LGPL") or the Common Development and 8 * Distribution License ("CDDL")(collectively, the "License"). You may not use this 9 * file except in compliance with the License. You can obtain a copy of the CDDL at 10 * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at 11 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 12 * specific language governing permissions and limitations under the License. When 13 * distributing the software, include this License Header Notice in each file and 14 * include the full text of the License in the License file as well as the 15 * following notice: 16 * 17 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 18 * (CDDL) 19 * For Covered Software in this distribution, this License shall be governed by the 20 * laws of the State of California (excluding conflict-of-law provisions). 21 * Any litigation relating to this License shall be subject to the jurisdiction of 22 * the Federal Courts of the Northern District of California and the state courts 23 * of the State of California, with venue lying in Santa Clara County, California. 24 * 25 * Contributor(s): 26 * 27 * If you wish your version of this file to be governed by only the CDDL or only 28 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to 29 * include this software in this distribution under the [CDDL or LGPL Version 2.1] 30 * license." If you don't indicate a single choice of license, a recipient has the 31 * option to distribute your version of this file under either the CDDL or the LGPL 32 * Version 2.1, or to extend the choice of license to its licensees as provided 33 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL 34 * Version 2 license, then the option applies only if the new code is made subject 35 * to such option by the copyright holder. 36 */ 37 38 #ifdef HAVE_CONFIG_H 39 #include <config.h> 40 #endif 41 42 #include <locale.h> 43 #include <ctype.h> 44 45 #include "imi_view_modern.h" 46 #include "imi_uiobjects.h" 47 48 #include "imi_keys.h" 49 50 CIMIModernView::CIMIModernView() 51 : CIMIView(), m_SyllableStr(), m_bNewSyll(false), m_SyllBone(), 52 m_CandiList(), m_CandiFirst(0), m_CursorIdx(-1) 53 { 54 } 55 56 CIMIModernView::~CIMIModernView() 57 { 58 } 59 60 int 61 CIMIModernView::getViewType(void) 62 { return CIMIViewFactory::SVT_MODERN; } 63 64 65 void 66 CIMIModernView::attachIC(CIMIContext* pIC) 67 { 68 CIMIView::attachIC(pIC); 69 70 CSunpinyinOptions *ppref = dynamic_cast<CSunpinyinOptions*>(m_pPref); 71 72 m_pIC->setLeft2RightSelection(false); 73 if (ppref) { 74 m_pIC->enableGBK(ppref->m_GBK); 75 m_pIC->setHistoryPower(ppref->m_MemoryPower); 76 m_pIC->enableContextRanking(ppref->m_ContextRanking); 77 } 78 79 m_SyllableStr.clear(); 80 m_SyllBone = m_pIC->getLastBone(); 81 m_CandiList.clear(); 82 m_CandiFirst = 0; 83 m_bNewSyll = true; 84 m_CursorIdx = -1; 85 } 86 87 unsigned 88 CIMIModernView::clearIC(void) 89 { 90 if (!m_pIC->isEmpty()) { 91 m_pIC->clear(); 92 m_SyllableStr.clear(); 93 m_bNewSyll = true; 94 m_SyllBone = m_pIC->getLastBone(); 95 m_CandiFirst = 0; 96 m_pIC->getCandidates(m_SyllBone, m_CandiList); 97 m_CursorIdx = -1; 98 return (PREEDIT_MASK | CANDIDATE_MASK); 99 } 100 101 m_SyllableStr.clear(); 102 return 0; 103 } 104 105 void 106 CIMIModernView::setStatusAttrValue(int key, int value) 107 { 108 if (key == CIMIWinHandler::STATUS_ID_CN) { 109 if (m_CN != (value != 0)) { 110 unsigned int changeMasks = 0; 111 112 if (m_SyllableStr.size() != 0) { 113 if (m_pIC->isValidSyllable(m_SyllableStr)) { 114 convertSyllable(CBone::USER_BOUNDARY, m_SyllableStr.size(), changeMasks); 115 } else { 116 cancelSyllable(changeMasks); 117 } 118 } 119 updateWindows(changeMasks); 120 121 m_CN = (value != 0); 122 if (mp_winHandler) 123 mp_winHandler->updateStatus(key, value); 124 } 125 return; 126 } 127 CIMIView::setStatusAttrValue(key, value); 128 } 129 130 /** 131 * NOTE: We can not use keyrelease information because IIIM do not give 132 * such type event. 133 * - If KEY_PRESS type event then 134 * -# m_nKeysWithShift = 1 135 * -# If LShift pressed, m_nKeysWithShift <-- 0, return 136 * -# Process Key Press event according whether or not in syllable editing mode 137 * . 138 * - If LShift released and (m_nKeysWithShift == 0), SwitchCNState() 139 */ 140 int 141 CIMIModernView::onKeyEvent(unsigned keycode, unsigned keyvalue, unsigned modifier) 142 { 143 unsigned int changeMasks = 0; 144 145 #ifdef DEBUG 146 printf("ModernView got a key (0x%x-0x%x-0x%x)...", keycode, keyvalue, modifier); 147 fflush(stdout); 148 #endif 149 150 //Clear other mask bit we do not care 151 modifier &= (IM_SHIFT_MASK | IM_CTRL_MASK | IM_ALT_MASK); 152 153 // On ALT+SHIFT, switch CN/EN status, but return the key event back as we do not use it 154 if ((keycode == IM_VK_SHIFT) && (modifier == IM_ALT_MASK)) { 155 setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, (!m_CN)?1:0); 156 return 0; 157 } 158 159 if (keycode == IM_VK_SHIFT || keycode == IM_VK_CONTROL || keycode == IM_VK_ALT) 160 return 0; 161 162 if ((keyvalue == IM_VK_PERIOD) && (modifier == IM_CTRL_MASK)) { 163 changeMasks |= KEYEVENT_USED; 164 setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, (!m_FullPunc)?1:0); 165 166 } else if ((keyvalue == IM_VK_SPACE) && (modifier == IM_SHIFT_MASK)) { 167 changeMasks |= KEYEVENT_USED; 168 setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSIMBOL, (!m_FullSimbol)?1:0); 169 170 } else if ((modifier & (IM_CTRL_MASK | IM_ALT_MASK)) == 0) { 171 if (m_SyllableStr.size() > 0) 172 pressKeyOnSyllable(keycode, keyvalue, modifier, changeMasks); 173 else 174 pressKeyOnSentence(keycode, keyvalue, modifier, changeMasks); 175 } 176 177 #ifdef DEBUG 178 printf(" |-->(Mask=0x%x)\n", changeMasks); 179 fflush(stdout); 180 #endif 181 182 updateWindows(changeMasks); 183 184 return ((changeMasks & KEYEVENT_USED) != 0)?1:0; 185 } 186 187 void 188 CIMIModernView::getPreeditString(IPreeditString& ps) 189 { 190 int i, SyllPos, SyllSize, caret; 191 192 ps.clear(); 193 caret = getSentence(ps.getString(), &SyllPos, &SyllSize); 194 if (m_CursorIdx >= 0 && m_CursorIdx < m_SyllableStr.size()) 195 caret -= m_SyllableStr.size()-m_CursorIdx; 196 ps.setCaret(caret); 197 198 IPreeditString::CCharTypeVec& ctv = ps.getCharTypeVec(); 199 for (i = 0; i < SyllPos; ++i) 200 ctv.push_back(IPreeditString::HANZI_CHAR); 201 for (SyllPos += SyllSize; i < SyllPos; ++i) 202 ctv.push_back(IPreeditString::PINYIN_CHAR); 203 for (; i < ps.size(); ++i) 204 ctv.push_back(IPreeditString::HANZI_CHAR); 205 } 206 207 void 208 CIMIModernView::getCandidateList(ICandidateList& cl, int start, int size) 209 { 210 cl.clear(); 211 ICandidateList::CCandiStrings& css = cl.getCandiStrings(); 212 ICandidateList::CCandiTypeVec& cts = cl.getCandiTypeVec(); 213 214 cl.setFirst(start); 215 cl.setTotal(m_CandiList.size()); 216 217 size = start+size; 218 if (size > m_CandiList.size()) 219 size = m_CandiList.size(); 220 for (; start < size; ++start) { 221 css.push_back(m_CandiList[start].m_String); 222 cts.push_back( (start == 0)?(ICandidateList::BEST_WORD):(ICandidateList::NORMAL_WORD) ); 223 } 224 } 225 226 void 227 CIMIModernView::updateWindows(unsigned int mask) 228 { 229 if (mp_winHandler) { 230 if ((mask & PREEDIT_MASK) != 0) { 231 CPreEditString ps; 232 getPreeditString(ps); 233 mp_winHandler->updatePreedit(&ps); 234 } 235 236 if ((mask & CANDIDATE_MASK) != 0) { 237 CCandidateList cl; 238 if (m_SyllableStr.size() == 0) 239 getCandidateList(cl, m_CandiFirst, s_CandiWindowSize); 240 else 241 m_CandiFirst = 0; 242 mp_winHandler->updateCandidates(&cl); 243 } 244 } 245 } 246 247 void 248 CIMIModernView::cancelSyllable(unsigned int& mask) 249 { 250 mask |= PREEDIT_MASK | CANDIDATE_MASK; 251 m_CandiFirst = 0; 252 m_SyllableStr.clear(); 253 m_CursorIdx = -1; 254 } 255 256 void 257 CIMIModernView::convertSyllable(int boundaryType, int len, unsigned int& mask) 258 { 259 tryCommitLeftSentence(mask); 260 261 std::list<CBone> newBones; 262 newBones.push_front(CBone(m_SyllableStr.c_str(), len, boundaryType, CBone::NODE_PINYIN)); 263 264 CSkeletonIter it2 = m_SyllBone; 265 if (!m_bNewSyll) 266 ++it2; 267 268 if (m_pIC->modify(m_SyllBone, it2, newBones)) { 269 m_CandiFirst = 0; 270 m_SyllBone = it2; 271 m_pIC->getCandidates(m_SyllBone, m_CandiList); 272 } 273 m_bNewSyll = true; 274 275 if (len < m_SyllableStr.size()) { 276 wstring tmpstr(m_SyllableStr.c_str()+len); 277 if (m_CursorIdx > 0) 278 m_CursorIdx -= len; 279 m_SyllableStr = tmpstr; 280 } else { 281 m_SyllableStr.clear(); 282 m_CursorIdx = -1; 283 } 284 mask |= PREEDIT_MASK | CANDIDATE_MASK; 285 } 286 287 void 288 CIMIModernView::makeSelection(int idx, unsigned int& mask) 289 { 290 CCandidate& cand = m_CandiList[m_CandiFirst + idx]; 291 m_pIC->makeSelection(cand); 292 m_SyllBone = cand.m_BoneEnd; 293 while (m_SyllBone->m_BoneType != CBone::NODE_PINYIN && 294 m_SyllBone->m_BoneType != CBone::NODE_TAIL) 295 ++m_SyllBone; 296 m_CandiFirst = 0; 297 m_pIC->getCandidates(m_SyllBone, m_CandiList); 298 mask |= PREEDIT_MASK | CANDIDATE_MASK; 299 } 300 301 void 302 CIMIModernView::eraseBone(CSkeletonIter boneIt, unsigned int& mask) 303 { 304 std::list<CBone> dummyBoneList; 305 CSkeletonIter it = ++CSkeletonIter(boneIt); 306 m_pIC->modify(boneIt, it, dummyBoneList); 307 308 m_SyllBone = it; 309 m_pIC->getCandidates(m_SyllBone, m_CandiList); 310 m_CandiFirst = 0; 311 312 mask |= PREEDIT_MASK | CANDIDATE_MASK; 313 } 314 315 void 316 CIMIModernView::insertNonPinyinBone(CBone& bone, unsigned int& mask) 317 { 318 tryCommitLeftSentence(mask); 319 320 mask |= PREEDIT_MASK | CANDIDATE_MASK; 321 std::list<CBone> newBones; 322 newBones.push_back(bone); 323 if (m_pIC->modify(m_SyllBone, m_SyllBone, newBones)) { 324 m_CandiFirst = 0; 325 m_pIC->getCandidates(m_SyllBone, m_CandiList); 326 } 327 } 328 329 unsigned 330 CIMIModernView::doCommit(bool bConvert) 331 { 332 wstring bs; 333 334 if (bConvert) { 335 getIC()->memorize(); 336 getSentence(bs); 337 mp_winHandler->commit(bs.c_str()); 338 } else { 339 CSkeletonIter ite = m_pIC->getLastBone(); 340 for (CSkeletonIter it = m_pIC->getFirstBone(); it != ite; ++it) 341 bs += it->m_String; 342 bs += m_SyllableStr; 343 mp_winHandler->commit(bs.c_str()); 344 } 345 346 return PREEDIT_MASK | CANDIDATE_MASK; 347 } 348 349 void 350 CIMIModernView::tryCommitLeftSentence(unsigned int& mask) 351 { 352 CSkeletonIter firstBone = m_pIC->getSkeleton().begin(); 353 CSkeletonIter sntnceEnd = m_SyllBone; 354 355 bool needCommit = false; 356 while (sntnceEnd != firstBone) { 357 --sntnceEnd; 358 if (sntnceEnd->m_BoneType == CBone::NODE_PUNC && 359 isTermPuncWide(sntnceEnd->m_String[0])) { 360 needCommit = true; 361 break; 362 } 363 } 364 365 if (needCommit) { 366 wstring bs; 367 ++sntnceEnd; 368 m_pIC->getBestSentence(bs, firstBone, sntnceEnd); 369 370 mp_winHandler->commit(bs.c_str()); 371 372 std::list<CBone> dummyBoneList; 373 m_pIC->modify(firstBone, sntnceEnd, dummyBoneList, false); 374 375 mask |= PREEDIT_MASK | CANDIDATE_MASK; 376 } 377 } 378 379 void 380 CIMIModernView::commitChar(TWCHAR ch) 381 { 382 TWCHAR wa[2] = {ch, 0}; 383 384 mp_winHandler->commit(wa); 385 } 386 387 int 388 CIMIModernView::getSentence(wstring& wstr, int* pSyllPos, int* pSyllSize) 389 { 390 wstr.clear(); 391 CSkeletonIter it = m_SyllBone; 392 m_pIC->getBestSentence(wstr, m_pIC->getSkeleton().begin(), it); 393 if (pSyllSize) 394 *pSyllSize = m_SyllableStr.size(); 395 if (pSyllPos) 396 *pSyllPos = wstr.size(); 397 if (m_SyllableStr.size() > 0) 398 wstr += m_SyllableStr; 399 int caret = wstr.size(); 400 if (m_SyllableStr.size() > 0 && !m_bNewSyll) 401 ++it; 402 wstring tmp; 403 m_pIC->getBestSentence(tmp, it, m_pIC->getLastBone()); 404 wstr += tmp; 405 return caret; 406 } 407 408 /** 409 * -# ESC --> cancel current syllable 410 * -# SPACE ' RETURN --> try to commit current syllable (untouch if can not commit) 411 * -# BACKSPACE --> try to erase the previouse PINYIN char in the syllable. If 412 * all PINYIN are erased, then: 413 * - if modifying syllable, erase the bone. 414 * - if inserting syllable, back to non-syllable editing mode. 415 * - return 416 * . 417 * -# a-z --> try to seg pinyin, if could be seged, the new PINYIN char are 418 * appended and if have some syllable to commit, commit it. if the 419 * newly input PINYIN char can not be accepted, just skip it. NOTE: 420 * after commit, even if previous is modifying state, the new syllable 421 * editing mode should be inserting. return. 422 * -# printable char 423 * - If current syllable is not commitable, skip it 424 * - else 425 * -# commit current syllable 426 * -# call pressNormalKey() 427 * . 428 * . 429 */ 430 void 431 CIMIModernView::pressKeyOnSyllable(unsigned keycode, unsigned keyvalue, unsigned modifier, unsigned int& mask) 432 { 433 mask |= KEYEVENT_USED; 434 if (keycode == IM_VK_ESCAPE) { 435 m_bNewSyll = true; 436 cancelSyllable(mask); 437 } else if (keycode == IM_VK_ENTER) { 438 mask |= KEYEVENT_USED | doCommit(modifier != IM_SHIFT_MASK); 439 mask |= clearIC(); 440 } else if (keyvalue == IM_VK_SPACE || keyvalue == '\'') { 441 if (m_CursorIdx != 0 || keyvalue == IM_VK_SPACE) { 442 wstring syllable = m_SyllableStr; 443 if (m_CursorIdx > 0 && m_CursorIdx < m_SyllableStr.size() && keyvalue == '\'') 444 syllable.resize(m_CursorIdx); 445 if (m_pIC->isValidSyllable(syllable)) { 446 convertSyllable(CBone::USER_BOUNDARY, syllable.size(), mask); 447 } 448 } 449 } else if (keycode == IM_VK_LEFT) { 450 if (m_CursorIdx != 0) { 451 mask |= PREEDIT_MASK; 452 m_CursorIdx = (m_CursorIdx < 0 ? m_SyllableStr.size() : m_CursorIdx) - 1; 453 } 454 } else if (keycode == IM_VK_RIGHT) { 455 if (m_CursorIdx >= 0 && m_CursorIdx < m_SyllableStr.size()) { 456 mask |= PREEDIT_MASK; 457 if (++m_CursorIdx == m_SyllableStr.size()) 458 m_CursorIdx = -1; 459 } 460 } else if (keycode == IM_VK_HOME) { 461 if (m_CursorIdx != 0) { 462 mask |= PREEDIT_MASK; 463 m_CursorIdx = 0; 464 } 465 } else if (keycode == IM_VK_END) { 466 if ( !(m_CursorIdx < 0 || m_CursorIdx == m_SyllableStr.size()) ) { 467 mask |= PREEDIT_MASK; 468 m_CursorIdx = -1; 469 } 470 } else if (keycode == IM_VK_BACK_SPACE) { 471 if (m_CursorIdx != 0) { 472 mask |= PREEDIT_MASK; 473 m_SyllableStr.erase(m_CursorIdx < 0 ? m_SyllableStr.size() - 1 : --m_CursorIdx, 1); 474 if (m_SyllableStr.size() == 0) { 475 if (!m_bNewSyll) 476 eraseBone(m_SyllBone, mask); 477 m_bNewSyll = true; 478 } else if (!m_bNewSyll) { 479 m_SyllBone->m_String = m_SyllableStr; 480 } 481 } 482 } else if (keycode == IM_VK_DELETE) { 483 if ( !(m_CursorIdx < 0 || m_CursorIdx == m_SyllableStr.size()) ) { 484 mask |= PREEDIT_MASK; 485 m_SyllableStr.erase(m_CursorIdx, 1); 486 if (m_CursorIdx >= m_SyllableStr.size()) 487 m_CursorIdx = -1; 488 if (m_SyllableStr.size() == 0) { 489 if (!m_bNewSyll) 490 eraseBone(m_SyllBone, mask); 491 m_bNewSyll = true; 492 } else if (!m_bNewSyll) { 493 m_SyllBone->m_String = m_SyllableStr; 494 } 495 } 496 } else if (keyvalue >= 'a' && keyvalue <= 'z') { 497 std::list<CBone> newBones; 498 TWCHAR wa[2] = {keyvalue, 0}; 499 m_SyllableStr.insert( m_CursorIdx < 0 ? m_SyllableStr.size() : m_CursorIdx++, wa ); 500 bool valid_py_char = m_pIC->segPinyinSimplest(m_SyllableStr, newBones); 501 502 if (!valid_py_char) //invalid pinyin character 503 m_SyllableStr.erase( m_CursorIdx < 0 ? m_SyllableStr.size() - 1 : --m_CursorIdx, 1); 504 505 if (newBones.size() > 1) { 506 if (!m_bNewSyll) 507 m_SyllBone->m_String = m_SyllableStr; 508 convertSyllable(CBone::AUTO_BOUNDARY, newBones.front().m_String.size(), mask); 509 if (!valid_py_char) { 510 pressNormalKey(keycode, keyvalue, modifier, mask); 511 } 512 } else { 513 mask |= PREEDIT_MASK; 514 } 515 } else if (keyvalue < 0x7f && keyvalue > 0x20) { 516 if (m_pIC->isValidSyllable(m_SyllableStr)) { 517 convertSyllable(CBone::AUTO_BOUNDARY, m_SyllableStr.size(), mask); 518 pressNormalKey(keycode, keyvalue, modifier, mask); 519 } 520 } 521 } 522 523 /** 524 * -# if (IC's skeleton is empty) and (the keyValue is not printable) 525 * --> give it back to IM framework 526 * -# ESACPE --> cancel all sentence (clear IC, update UI) 527 * -# RETURN --> commit the sentence 528 * -# LEFT_ARROW RIGHT_ARROW HOME END --> move caret 529 * -# DEL BACKSPACE --> erase properiate bone 530 * -# ENState --> call pressNormalKey 531 * -# ` (KEY left to key 1) and CN State and current bone contains only one HANZI --> 532 * - Entering current's characters syllable modifying mode 533 * - else ignore it (CNState) 534 * . 535 * -# SPACE: 536 * - if candidates displayed, select the candi, and seek new candidate-list position 537 * - (now, it's CNState) commit the sentence 538 * . 539 * -# 1-8: 540 * - if candidates displayed, select the candi, seek new position 541 * - (CNState), Processing normal key 542 * . 543 * -# =/- 544 * - If candidates displayed, move its display window 545 * - (CNState), Processing normal key 546 * . 547 * -# a-z --> entering syllable editing inserting mode, return 548 * -# call pressNormalKey 549 */ 550 void 551 CIMIModernView::pressKeyOnSentence(unsigned keycode, unsigned keyvalue, unsigned modifier, unsigned int& mask) 552 { 553 //unsigned int key = event->keyval; 554 CSunpinyinOptions *ppref = dynamic_cast<CSunpinyinOptions*>(m_pPref); 555 556 if (m_pIC->isEmpty() && !(keyvalue >= 'a' && keyvalue <= 'z')) 557 return pressNormalKey(keycode, keyvalue, modifier, mask); 558 559 if (keycode == IM_VK_ESCAPE) { 560 mask |= KEYEVENT_USED | clearIC(); 561 562 } else if (keycode == IM_VK_ENTER) { 563 mask |= KEYEVENT_USED | doCommit(modifier != IM_SHIFT_MASK); 564 mask |= clearIC(); 565 566 } else if (keycode == IM_VK_HOME || keycode == IM_VK_LEFT) { 567 mask |= KEYEVENT_USED; 568 if (m_SyllBone != m_pIC->getSkeleton().begin()){ 569 if (keycode != IM_VK_HOME) 570 --m_SyllBone; 571 else 572 m_SyllBone = m_pIC->getSkeleton().begin(); 573 m_CandiFirst = 0; 574 m_pIC->getCandidates(m_SyllBone, m_CandiList); 575 mask |= PREEDIT_MASK | CANDIDATE_MASK; 576 } 577 } else if (keycode == IM_VK_END || keycode == IM_VK_RIGHT) { 578 mask |= KEYEVENT_USED; 579 if (m_SyllBone != m_pIC->getLastBone()){ 580 if (keycode != IM_VK_END) 581 ++m_SyllBone; 582 else 583 m_SyllBone = m_pIC->getLastBone(); 584 m_CandiFirst = 0; 585 m_pIC->getCandidates(m_SyllBone, m_CandiList); 586 mask |= KEYEVENT_USED | PREEDIT_MASK | CANDIDATE_MASK; 587 } 588 } else if (keycode == IM_VK_DELETE) { 589 mask |= KEYEVENT_USED; 590 if (m_SyllBone != m_pIC->getLastBone()){ 591 eraseBone(m_SyllBone, mask); 592 } 593 } else if (keycode == IM_VK_BACK_SPACE) { 594 mask |= KEYEVENT_USED; 595 if (m_SyllBone != m_pIC->getSkeleton().begin()){ 596 eraseBone(--CSkeletonIter(m_SyllBone), mask); 597 } 598 } else if (!m_CN) { 599 pressNormalKey(keycode, keyvalue, modifier, mask); 600 } else if (keycode == IM_VK_BACK_QUOTE) { 601 mask |= KEYEVENT_USED; 602 if (m_SyllBone->m_BoneType == CBone::NODE_PINYIN) { 603 m_bNewSyll = false; 604 m_SyllableStr = m_SyllBone->m_String; 605 mask |= PREEDIT_MASK | CANDIDATE_MASK; 606 } 607 } else if (keyvalue == IM_VK_SPACE) { 608 mask |= KEYEVENT_USED; 609 if (m_CandiList.size() > 0) { 610 makeSelection(0, mask); 611 } else { // (m_CN is true) 612 mask |= doCommit(); 613 mask |= clearIC(); 614 } 615 } else if ((keyvalue >= '1' && keyvalue < '1'+s_CandiWindowSize) || 616 (keyvalue == '0' && s_CandiWindowSize == 10)) { 617 mask |= KEYEVENT_USED; 618 if (m_CandiList.size() > m_CandiFirst + (keyvalue == '0' ? 9 : keyvalue-'1')) { 619 makeSelection(keyvalue == '0' ? 9 : keyvalue-'1', mask); 620 } else { 621 pressNormalKey(keycode, keyvalue, modifier, mask); 622 } 623 } else if ((ppref != NULL) && (ppref->isPageUpKey(keycode, keyvalue, modifier))) { 624 mask |= KEYEVENT_USED; 625 if (m_CandiList.size() && m_CandiFirst > 0) { 626 m_CandiFirst -= s_CandiWindowSize; 627 if (m_CandiFirst < 0) m_CandiFirst = 0; 628 mask |= CANDIDATE_MASK; 629 } 630 } else if ((ppref != NULL) && (ppref->isPageDnKey(keycode, keyvalue, modifier))) { 631 mask |= KEYEVENT_USED; 632 if (m_CandiFirst + s_CandiWindowSize < m_CandiList.size()) { 633 m_CandiFirst += s_CandiWindowSize; 634 mask |= CANDIDATE_MASK; 635 } 636 } else if (keyvalue >= 'a' && keyvalue <= 'z') { 637 mask |= KEYEVENT_USED; 638 m_bNewSyll = true; 639 m_SyllableStr += TWCHAR(keyvalue); 640 641 std::list<CBone> newBones; 642 if (m_pIC->segPinyinSimplest(m_SyllableStr, newBones)) { 643 mask |= PREEDIT_MASK | CANDIDATE_MASK; //hide the candi-window 644 } else { //invalid Pinyin character, like u, i 645 m_SyllableStr.clear(); 646 pressNormalKey(keycode, keyvalue, modifier, mask); 647 } 648 } else { 649 pressNormalKey(keycode, keyvalue, modifier, mask); 650 } 651 } 652 653 int 654 CIMIModernView::onCandidatePageRequest(int pgno, bool relative) 655 { 656 unsigned changeMasks = 0; 657 int ncandi, lastpgidx; 658 659 if (!m_pIC->isEmpty()) { 660 changeMasks |= KEYEVENT_USED; 661 int sz = m_CandiList.size(); 662 if (sz > 0) { 663 lastpgidx = (sz-1)/s_CandiWindowSize * s_CandiWindowSize; 664 if (relative == true) { 665 ncandi = m_CandiFirst + pgno*s_CandiWindowSize; 666 if (ncandi >= sz) 667 ncandi = lastpgidx; 668 if (ncandi < 0) 669 ncandi = 0; 670 if (ncandi != m_CandiFirst) { 671 m_CandiFirst = ncandi; 672 changeMasks |= CANDIDATE_MASK; 673 } 674 } else { 675 if (pgno < 0) { //last page 676 ncandi = lastpgidx; 677 } else { 678 ncandi = pgno * s_CandiWindowSize; 679 if (ncandi > lastpgidx) 680 ncandi = lastpgidx; 681 } 682 if (ncandi != m_CandiFirst) { 683 m_CandiFirst = ncandi; 684 changeMasks |= CANDIDATE_MASK; 685 } 686 } 687 } 688 } 689 690 updateWindows(changeMasks); 691 return 0; 692 } 693 694 int 695 CIMIModernView::onCandidateSelectRequest(int index) 696 { 697 unsigned changeMasks = 0; 698 699 if (!m_pIC->isEmpty()) { 700 makeSelection(index, changeMasks); 701 } 702 updateWindows(changeMasks); 703 return 0; 704 } 705 706 /** 707 * I will change the core to make that every punc/simbol/Eng char be a single 708 * bone soon. this could make this function much simpler. 709 * -# ch <-- the char of the key press 710 * -# not printable, return (nothing changed, the event key is not processed by IMI) 711 * -# word id <-- 0 712 * -# if is PuncChar and FullPuncState, 713 * - convert ch into Chinese Punc, 714 * - get its word id 715 * -# if is Simbol char, convert ch into Chinese Simbol 716 * -# insert the char or commit the char 717 * - if (IC's Skeleton is not empty) 718 * - create a bone and insert it into IC's skeleton 719 * - if ch in (A-Z) and in CN state, change the state into EN automatically 720 * . 721 * - else commit the char directly 722 */ 723 void 724 CIMIModernView::pressNormalKey(unsigned keycode, unsigned keyvalue, unsigned modifier, unsigned int& mask) 725 { 726 //unsigned int key = event->keyval; 727 unsigned int bone_type = CBone::NODE_ASCII; 728 729 if (keyvalue <= 0x20 || keyvalue >= 0x7F ) 730 return; 731 if (m_FullSimbol) 732 keyvalue = (unsigned int)(getFullSimbol(TWCHAR(keyvalue))); 733 if (m_FullPunc) { 734 keyvalue = (unsigned int)(getFullPunc(TWCHAR(keyvalue))); 735 bone_type = CBone::NODE_PUNC; 736 } 737 if (m_pIC->isEmpty()) { 738 mask |= KEYEVENT_USED; 739 commitChar(TWCHAR(keyvalue)); 740 } else { 741 mask |= KEYEVENT_USED; 742 CBone bone(CBone::AUTO_BOUNDARY, bone_type); 743 bone.m_String.clear(); 744 bone.m_String += TWCHAR(keyvalue); 745 insertNonPinyinBone(bone, mask); 746 } 747 } 748