16a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard/* 26a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * Copyright (C) 2013 The Android Open Source Project 36a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * 46a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * Licensed under the Apache License, Version 2.0 (the "License"); 56a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * you may not use this file except in compliance with the License. 66a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * You may obtain a copy of the License at 76a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * 86a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * http://www.apache.org/licenses/LICENSE-2.0 96a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * 106a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * Unless required by applicable law or agreed to in writing, software 116a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * distributed under the License is distributed on an "AS IS" BASIS, 126a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * See the License for the specific language governing permissions and 146a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * limitations under the License. 156a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard */ 166a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard 176a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalardpackage com.android.inputmethod.event; 186a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard 196a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalardimport android.text.TextUtils; 206a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalardimport android.view.KeyCharacterMap; 216a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard 226a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalardimport com.android.inputmethod.latin.Constants; 236a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard 246a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard/** 256a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard * A combiner that handles dead keys. 266a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard */ 276a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalardpublic class DeadKeyCombiner implements Combiner { 286a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard final StringBuilder mDeadSequence = new StringBuilder(); 296a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard 306a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard @Override 316a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard public Event combine(final Event event) { 326a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard if (null == event) return null; // Just in case some combiner is broken 336a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard if (TextUtils.isEmpty(mDeadSequence)) { 346a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard if (event.isDead()) { 356a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard mDeadSequence.appendCodePoint(event.mCodePoint); 366a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard } 376a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard return event; 386a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard } else { 396a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // TODO: Allow combining for several dead chars rather than only the first one. 406a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // The framework doesn't know how to do this now. 416a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard final int deadCodePoint = mDeadSequence.codePointAt(0); 426a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard mDeadSequence.setLength(0); 436a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard final int resultingCodePoint = 446a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard KeyCharacterMap.getDeadChar(deadCodePoint, event.mCodePoint); 456a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard if (0 == resultingCodePoint) { 466a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // We can't combine both characters. We need to commit the dead key as a committable 476a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // character, and the next char too unless it's a space (because as a special case, 486a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // dead key + space should result in only the dead key being committed - that's 496a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // how dead keys work). 506a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // If the event is a space, we should commit the dead char alone, but if it's 516a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // not, we need to commit both. 526a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard return Event.createCommittableEvent(deadCodePoint, 536a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */); 546a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard } else { 556a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard // We could combine the characters. 566a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard return Event.createCommittableEvent(resultingCodePoint, null /* next */); 576a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard } 586a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard } 596a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard } 606a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard 616a26de1d7e3bb3b277c0af6d678023b862c22a86Jean Chalard} 62