diff --git a/src/java/KP2ASoftKeyboard2/.gitignore b/src/java/KP2ASoftKeyboard2/.gitignore new file mode 100644 index 00000000..d45006d9 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/.gitignore @@ -0,0 +1,5 @@ +/native/obj +/native/libs + +/java/bin +/tests/bin diff --git a/src/java/KP2ASoftKeyboard2/java/.classpath b/src/java/KP2ASoftKeyboard2/java/.classpath new file mode 100644 index 00000000..51769745 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/.project b/src/java/KP2ASoftKeyboard2/java/.project new file mode 100644 index 00000000..2f557768 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/.project @@ -0,0 +1,33 @@ + + + KP2ASoftKeyboard2 + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/src/java/KP2ASoftKeyboard2/java/.settings/org.eclipse.jdt.core.prefs b/src/java/KP2ASoftKeyboard2/java/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..b080d2dd --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/src/java/KP2ASoftKeyboard2/java/Android.mk b/src/java/KP2ASoftKeyboard2/java/Android.mk new file mode 100644 index 00000000..03d48aaa --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := LatinIME + +LOCAL_CERTIFICATE := shared + +LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime + +LOCAL_STATIC_JAVA_LIBRARIES := android-common + +#LOCAL_AAPT_FLAGS := -0 .dict + +LOCAL_SDK_VERSION := current + +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +include $(BUILD_PACKAGE) diff --git a/src/java/KP2ASoftKeyboard2/java/AndroidManifest.xml b/src/java/KP2ASoftKeyboard2/java/AndroidManifest.xml new file mode 100644 index 00000000..242fcb53 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/MODULE_LICENSE_APACHE2 b/src/java/KP2ASoftKeyboard2/java/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b diff --git a/src/java/KP2ASoftKeyboard2/java/NOTICE b/src/java/KP2ASoftKeyboard2/java/NOTICE new file mode 100644 index 00000000..7340b9e3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/src/java/KP2ASoftKeyboard2/java/gen/keepass2android/softkeyboard/BuildConfig.java b/src/java/KP2ASoftKeyboard2/java/gen/keepass2android/softkeyboard/BuildConfig.java new file mode 100644 index 00000000..7048a099 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/gen/keepass2android/softkeyboard/BuildConfig.java @@ -0,0 +1,6 @@ +/** Automatically generated file. DO NOT MODIFY */ +package keepass2android.softkeyboard; + +public final class BuildConfig { + public final static boolean DEBUG = true; +} \ No newline at end of file diff --git a/src/java/KP2ASoftKeyboard2/java/gen/keepass2android/softkeyboard/R.java b/src/java/KP2ASoftKeyboard2/java/gen/keepass2android/softkeyboard/R.java new file mode 100644 index 00000000..f7ec5558 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/gen/keepass2android/softkeyboard/R.java @@ -0,0 +1,1311 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package keepass2android.softkeyboard; + +public final class R { + public static final class anim { + public static final int key_preview_fadein=0x7f040000; + public static final int key_preview_fadeout=0x7f040001; + public static final int mini_keyboard_fadein=0x7f040002; + public static final int mini_keyboard_fadeout=0x7f040003; + } + public static final class array { + public static final int keyboard_layout_modes=0x7f0d0007; + public static final int keyboard_layout_modes_values=0x7f0d0008; + /** Array of prediction modes + */ + public static final int prediction_modes=0x7f0d0002; + public static final int prediction_modes_values=0x7f0d0003; + /** Array of the settings key modes + */ + public static final int settings_key_modes=0x7f0d0001; + /** Array of the settings key mode values + */ + public static final int settings_key_modes_values=0x7f0d0000; + /** Array of Voice Input modes + */ + public static final int voice_input_modes=0x7f0d0004; + /** Array of Voice Input modes summary + */ + public static final int voice_input_modes_summary=0x7f0d0006; + public static final int voice_input_modes_values=0x7f0d0005; + } + public static final class attr { + /**

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int backgroundDimAmount=0x7f01000d; + /** Image for the key. This image needs to be a StateListDrawable, with the following + possible states: normal, pressed, checkable, checkable+pressed, checkable+checked, + checkable+checked+pressed. +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". + */ + public static final int keyBackground=0x7f010001; + /** Hysteresis distance for key debouncing +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int keyHysteresisDistance=0x7f010008; + /** Height of the key press feedback popup. +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int keyPreviewHeight=0x7f010007; + /** Layout resource for key press feedback. +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". + */ + public static final int keyPreviewLayout=0x7f010005; + /** Vertical offset of the key press feedback from the key. +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int keyPreviewOffset=0x7f010006; + /** Color to use for the label in a key. +

Must be a color value, in the form of "#rgb", "#argb", +"#rrggbb", or "#aarrggbb". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int keyTextColor=0x7f010004; + /** Size of the text for character keys. +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int keyTextSize=0x7f010002; + /**

Must be one or more (separated by '|') of the following constant values.

+ ++++ + + + +
ConstantValueDescription
normal0
bold1
italic2
+ */ + public static final int keyTextStyle=0x7f01000e; + /** Default KeyboardView style. +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". + */ + public static final int keyboardViewStyle=0x7f010000; + /** Size of the text for custom keys with some text and no icon. +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int labelTextSize=0x7f010003; + /** Layout resource for popup keyboards. +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". + */ + public static final int popupLayout=0x7f01000a; + /**

Must be a color value, in the form of "#rgb", "#argb", +"#rrggbb", or "#aarrggbb". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int shadowColor=0x7f01000b; + /**

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int shadowRadius=0x7f01000c; + /**

Must be one or more (separated by '|') of the following constant values.

+ ++++ + + +
ConstantValueDescription
white0
black1
+ */ + public static final int symbolColorScheme=0x7f01000f; + /** Amount to offset the touch Y coordinate by, for bias correction. +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int verticalCorrection=0x7f010009; + } + public static final class bool { + public static final int config_long_press_comma_for_settings_enabled=0x7f080006; + public static final int config_swipeDisambiguation=0x7f080003; + /** Whether or not Popup on key press is enabled by default + */ + public static final int default_popup_preview=0x7f080004; + public static final int default_recorrection_enabled=0x7f080005; + /** Whether or not auto-correction should be enabled by default + */ + public static final int enable_autocorrect=0x7f080000; + /** Whether this input method should be used as the default for a locale. Override it + for latin languages. + */ + public static final int im_is_default=0x7f080001; + /** Whether or not voice input is enabled by default. + */ + public static final int voice_input_default=0x7f080002; + } + public static final class color { + public static final int candidate_normal=0x7f090000; + public static final int candidate_other=0x7f090002; + public static final int candidate_recommended=0x7f090001; + public static final int latinkeyboard_bar_language_shadow_black=0x7f090005; + public static final int latinkeyboard_bar_language_shadow_white=0x7f090004; + public static final int latinkeyboard_bar_language_text=0x7f090006; + public static final int latinkeyboard_extension_background=0x7f090007; + public static final int latinkeyboard_feedback_language_text=0x7f090008; + public static final int latinkeyboard_key_color_black=0x7f09000a; + public static final int latinkeyboard_key_color_white=0x7f090009; + public static final int latinkeyboard_transparent=0x7f090003; + } + public static final class dimen { + public static final int bubble_pointer_offset=0x7f0b0004; + public static final int candidate_min_touchable_width=0x7f0b0012; + public static final int candidate_strip_fading_edge_length=0x7f0b0006; + public static final int candidate_strip_height=0x7f0b0005; + public static final int key_bottom_gap=0x7f0b0001; + /** key_height + key_bottom_gap = popup_key_height + key_height + key_bottom_gap = popup_key_height + */ + public static final int key_height=0x7f0b0000; + public static final int key_hysteresis_distance=0x7f0b0010; + public static final int key_label_text_size=0x7f0b000a; + /** key_preview_text_size_large x 2 + */ + public static final int key_preview_height=0x7f0b000d; + public static final int key_preview_offset=0x7f0b000c; + public static final int key_preview_text_size_large=0x7f0b000b; + public static final int key_text_size=0x7f0b0009; + public static final int keyboard_bottom_padding=0x7f0b0003; + /** We use "inch", not "dip" because this value tries dealing with physical distance related + to user's finger. + */ + public static final int keyboard_vertical_correction=0x7f0b0011; + /** If the screen height in landscape is larger than the below value, then the keyboard + will not go into extract (fullscreen) mode. + */ + public static final int max_height_for_fullscreen=0x7f0b0008; + /** Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. + popup_key_height x 1.7 + Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. + popup_key_height x 1.7 + */ + public static final int mini_keyboard_slide_allowance=0x7f0b000e; + /** popup_key_height x 1.0 + popup_key_height x 1.0 + */ + public static final int mini_keyboard_vertical_correction=0x7f0b000f; + public static final int popup_key_height=0x7f0b0002; + public static final int spacebar_vertical_correction=0x7f0b0007; + } + public static final class drawable { + public static final int btn_keyboard_key=0x7f020000; + public static final int btn_keyboard_key2=0x7f020001; + public static final int btn_keyboard_key3=0x7f020002; + public static final int btn_keyboard_key_dark_normal=0x7f020003; + public static final int btn_keyboard_key_dark_normal_off=0x7f020004; + public static final int btn_keyboard_key_dark_normal_on=0x7f020005; + public static final int btn_keyboard_key_dark_pressed=0x7f020006; + public static final int btn_keyboard_key_dark_pressed_off=0x7f020007; + public static final int btn_keyboard_key_dark_pressed_on=0x7f020008; + public static final int btn_keyboard_key_fulltrans=0x7f020009; + public static final int btn_keyboard_key_fulltrans_normal=0x7f02000a; + public static final int btn_keyboard_key_fulltrans_pressed=0x7f02000b; + public static final int btn_keyboard_key_gingerbread=0x7f02000c; + public static final int btn_keyboard_key_gingerbread_popup=0x7f02000d; + public static final int btn_keyboard_key_light_normal=0x7f02000e; + public static final int btn_keyboard_key_light_popup_normal=0x7f02000f; + public static final int btn_keyboard_key_light_popup_selected=0x7f020010; + public static final int btn_keyboard_key_light_pressed=0x7f020011; + public static final int btn_keyboard_key_normal=0x7f020012; + public static final int btn_keyboard_key_normal_off=0x7f020013; + public static final int btn_keyboard_key_normal_off_stone=0x7f020014; + public static final int btn_keyboard_key_normal_on=0x7f020015; + public static final int btn_keyboard_key_normal_on_stone=0x7f020016; + public static final int btn_keyboard_key_normal_stone=0x7f020017; + public static final int btn_keyboard_key_pressed=0x7f020018; + public static final int btn_keyboard_key_pressed_off=0x7f020019; + public static final int btn_keyboard_key_pressed_on=0x7f02001a; + public static final int btn_keyboard_key_stone=0x7f02001b; + public static final int cancel=0x7f02001c; + public static final int candidate_feedback_background=0x7f02001d; + public static final int caution=0x7f02001e; + public static final int dialog_bubble_step02=0x7f02001f; + public static final int dialog_bubble_step07=0x7f020020; + public static final int highlight_pressed=0x7f020021; + public static final int hint_popup=0x7f020022; + public static final int ic_dialog_keyboard=0x7f020023; + public static final int ic_mic_dialog=0x7f020024; + public static final int ic_subtype_keyboard=0x7f020025; + public static final int ic_subtype_mic=0x7f020026; + public static final int ic_suggest_scroll_background=0x7f020027; + public static final int ic_suggest_strip_microphone=0x7f020028; + public static final int ic_suggest_strip_microphone_swipe=0x7f020029; + public static final int keyboard_background=0x7f02002a; + public static final int keyboard_dark_background=0x7f02002b; + public static final int keyboard_hint_0=0x7f02002c; + public static final int keyboard_hint_1=0x7f02002d; + public static final int keyboard_hint_2=0x7f02002e; + public static final int keyboard_hint_3=0x7f02002f; + public static final int keyboard_hint_4=0x7f020030; + public static final int keyboard_hint_5=0x7f020031; + public static final int keyboard_hint_6=0x7f020032; + public static final int keyboard_hint_7=0x7f020033; + public static final int keyboard_hint_8=0x7f020034; + public static final int keyboard_hint_9=0x7f020035; + public static final int keyboard_key_feedback=0x7f020036; + public static final int keyboard_key_feedback_background=0x7f020037; + public static final int keyboard_key_feedback_more_background=0x7f020038; + public static final int keyboard_popup_panel_background=0x7f020039; + public static final int keyboard_suggest_strip=0x7f02003a; + public static final int keyboard_suggest_strip_divider=0x7f02003b; + public static final int list_selector_background_pressed=0x7f02003c; + public static final int mic_slash=0x7f02003d; + public static final int ok_cancel=0x7f02003e; + public static final int speak_now_level0=0x7f02003f; + public static final int speak_now_level1=0x7f020040; + public static final int speak_now_level2=0x7f020041; + public static final int speak_now_level3=0x7f020042; + public static final int speak_now_level4=0x7f020043; + public static final int speak_now_level5=0x7f020044; + public static final int speak_now_level6=0x7f020045; + public static final int sym_bkeyboard_123_mic=0x7f020046; + public static final int sym_bkeyboard_delete=0x7f020047; + public static final int sym_bkeyboard_done=0x7f020048; + public static final int sym_bkeyboard_kp2a=0x7f020049; + public static final int sym_bkeyboard_mic=0x7f02004a; + public static final int sym_bkeyboard_num0=0x7f02004b; + public static final int sym_bkeyboard_num1=0x7f02004c; + public static final int sym_bkeyboard_num2=0x7f02004d; + public static final int sym_bkeyboard_num3=0x7f02004e; + public static final int sym_bkeyboard_num4=0x7f02004f; + public static final int sym_bkeyboard_num5=0x7f020050; + public static final int sym_bkeyboard_num6=0x7f020051; + public static final int sym_bkeyboard_num7=0x7f020052; + public static final int sym_bkeyboard_num8=0x7f020053; + public static final int sym_bkeyboard_num9=0x7f020054; + public static final int sym_bkeyboard_numalt=0x7f020055; + public static final int sym_bkeyboard_numpound=0x7f020056; + public static final int sym_bkeyboard_numstar=0x7f020057; + public static final int sym_bkeyboard_return=0x7f020058; + public static final int sym_bkeyboard_search=0x7f020059; + public static final int sym_bkeyboard_settings=0x7f02005a; + public static final int sym_bkeyboard_shift=0x7f02005b; + public static final int sym_bkeyboard_shift_locked=0x7f02005c; + public static final int sym_bkeyboard_space=0x7f02005d; + public static final int sym_bkeyboard_tab=0x7f02005e; + public static final int sym_keyboard_123_mic=0x7f02005f; + public static final int sym_keyboard_delete=0x7f020060; + public static final int sym_keyboard_done=0x7f020061; + public static final int sym_keyboard_feedback_123_mic=0x7f020062; + public static final int sym_keyboard_feedback_delete=0x7f020063; + public static final int sym_keyboard_feedback_done=0x7f020064; + public static final int sym_keyboard_feedback_kp2a=0x7f020065; + public static final int sym_keyboard_feedback_language_arrows_left=0x7f020066; + public static final int sym_keyboard_feedback_language_arrows_right=0x7f020067; + public static final int sym_keyboard_feedback_mic=0x7f020068; + public static final int sym_keyboard_feedback_numalt=0x7f020069; + public static final int sym_keyboard_feedback_return=0x7f02006a; + public static final int sym_keyboard_feedback_search=0x7f02006b; + public static final int sym_keyboard_feedback_settings=0x7f02006c; + public static final int sym_keyboard_feedback_shift=0x7f02006d; + public static final int sym_keyboard_feedback_shift_locked=0x7f02006e; + public static final int sym_keyboard_feedback_space=0x7f02006f; + public static final int sym_keyboard_feedback_tab=0x7f020070; + public static final int sym_keyboard_kp2a=0x7f020071; + public static final int sym_keyboard_language_arrows_left=0x7f020072; + public static final int sym_keyboard_language_arrows_right=0x7f020073; + public static final int sym_keyboard_mic=0x7f020074; + public static final int sym_keyboard_num0=0x7f020075; + public static final int sym_keyboard_num1=0x7f020076; + public static final int sym_keyboard_num2=0x7f020077; + public static final int sym_keyboard_num3=0x7f020078; + public static final int sym_keyboard_num4=0x7f020079; + public static final int sym_keyboard_num5=0x7f02007a; + public static final int sym_keyboard_num6=0x7f02007b; + public static final int sym_keyboard_num7=0x7f02007c; + public static final int sym_keyboard_num8=0x7f02007d; + public static final int sym_keyboard_num9=0x7f02007e; + public static final int sym_keyboard_numalt=0x7f02007f; + public static final int sym_keyboard_numpound=0x7f020080; + public static final int sym_keyboard_numstar=0x7f020081; + public static final int sym_keyboard_return=0x7f020082; + public static final int sym_keyboard_search=0x7f020083; + public static final int sym_keyboard_settings=0x7f020084; + public static final int sym_keyboard_shift=0x7f020085; + public static final int sym_keyboard_shift_lock=0x7f020086; + public static final int sym_keyboard_shift_locked=0x7f020087; + public static final int sym_keyboard_space=0x7f020088; + public static final int sym_keyboard_space_led=0x7f020089; + public static final int sym_keyboard_tab=0x7f02008a; + public static final int voice_ime_background=0x7f02008b; + public static final int voice_swipe_hint=0x7f02008c; + public static final int working=0x7f02008d; + } + public static final class id { + public static final int LatinKeyboardBaseView=0x7f070007; + public static final int LatinkeyboardBaseView=0x7f070006; + public static final int black=0x7f070004; + public static final int bold=0x7f070001; + public static final int button=0x7f07000c; + public static final int button_text=0x7f07000d; + public static final int candidates=0x7f070005; + public static final int image=0x7f07000a; + public static final int italic=0x7f070002; + public static final int main_image=0x7f070008; + public static final int mode_email=0x7f070010; + public static final int mode_email_with_settings_key=0x7f070015; + public static final int mode_im=0x7f070011; + public static final int mode_im_with_settings_key=0x7f070016; + public static final int mode_normal=0x7f07000e; + public static final int mode_normal_with_settings_key=0x7f070013; + public static final int mode_symbols=0x7f070018; + public static final int mode_symbols_with_settings_key=0x7f070019; + public static final int mode_url=0x7f07000f; + public static final int mode_url_with_settings_key=0x7f070014; + public static final int mode_webentry=0x7f070012; + public static final int mode_webentry_with_settings_key=0x7f070017; + public static final int normal=0x7f070000; + public static final int progress=0x7f07000b; + public static final int text=0x7f070009; + public static final int white=0x7f070003; + } + public static final class integer { + public static final int config_delay_after_preview=0x7f0a0001; + public static final int config_delay_before_key_repeat_start=0x7f0a0006; + public static final int config_delay_before_preview=0x7f0a0000; + public static final int config_key_repeat_interval=0x7f0a0007; + public static final int config_long_press_key_timeout=0x7f0a0008; + public static final int config_mini_keyboard_fadein_anim_time=0x7f0a0004; + public static final int config_mini_keyboard_fadeout_anim_time=0x7f0a0005; + public static final int config_multi_tap_key_timeout=0x7f0a0009; + public static final int config_preview_fadein_anim_time=0x7f0a0002; + public static final int config_preview_fadeout_anim_time=0x7f0a0003; + public static final int key_delete=0x7f0a0010; + public static final int key_f1=0x7f0a0013; + public static final int key_kp2a=0x7f0a0014; + public static final int key_return=0x7f0a000c; + /** Keycode for F1 (function) key. This one switches between language switch & comma/.com + */ + public static final int key_settings=0x7f0a0011; + public static final int key_shift=0x7f0a000e; + public static final int key_space=0x7f0a000d; + public static final int key_symbol=0x7f0a000f; + public static final int key_tab=0x7f0a000b; + public static final int key_voice=0x7f0a0012; + /** Vibration duration in milliseconds, for key presses in the IME. This can be hardware + dependent and may require overriding with a device specific overlay. + */ + public static final int vibrate_duration_ms=0x7f0a000a; + } + public static final class layout { + public static final int bubble_text=0x7f030000; + public static final int candidate_preview=0x7f030001; + public static final int candidates=0x7f030002; + public static final int input_basic=0x7f030003; + public static final int input_basic_highcontrast=0x7f030004; + public static final int input_gingerbread=0x7f030005; + public static final int input_stone_bold=0x7f030006; + public static final int input_stone_normal=0x7f030007; + public static final int input_stone_popup=0x7f030008; + public static final int key_preview=0x7f030009; + public static final int keyboard_popup=0x7f03000a; + public static final int recognition_status=0x7f03000b; + public static final int voice_punctuation_hint=0x7f03000c; + public static final int voice_swipe_hint=0x7f03000d; + } + public static final class raw { + public static final int main=0x7f060000; + public static final int type3=0x7f060001; + } + public static final class string { + /** Indicates that a word has been added to the dictionary + */ + public static final int added_word=0x7f0c0044; + public static final int alternates_for_a=0x7f0c0000; + public static final int alternates_for_a_umlaut=0x7f0c0017; + public static final int alternates_for_ae=0x7f0c0013; + public static final int alternates_for_c=0x7f0c0007; + public static final int alternates_for_cyrillic_e=0x7f0c0015; + public static final int alternates_for_cyrillic_soft_sign=0x7f0c0016; + public static final int alternates_for_d=0x7f0c000b; + public static final int alternates_for_e=0x7f0c0001; + public static final int alternates_for_g=0x7f0c0010; + public static final int alternates_for_i=0x7f0c0002; + public static final int alternates_for_l=0x7f0c000f; + public static final int alternates_for_n=0x7f0c0006; + public static final int alternates_for_o=0x7f0c0003; + public static final int alternates_for_o_umlaut=0x7f0c0018; + public static final int alternates_for_oe=0x7f0c0014; + public static final int alternates_for_p=0x7f0c0011; + public static final int alternates_for_q=0x7f0c0009; + public static final int alternates_for_r=0x7f0c000c; + public static final int alternates_for_s=0x7f0c0005; + public static final int alternates_for_t=0x7f0c000d; + public static final int alternates_for_u=0x7f0c0004; + public static final int alternates_for_v=0x7f0c0012; + public static final int alternates_for_w=0x7f0c000a; + public static final int alternates_for_y=0x7f0c0008; + public static final int alternates_for_z=0x7f0c000e; + /** Option to enable auto capitalization of sentences + */ + public static final int auto_cap=0x7f0c0031; + /** Description for auto cap + */ + public static final int auto_cap_summary=0x7f0c0032; + /** Option to enable auto completion + */ + public static final int auto_complete=0x7f0c0039; + /** Dialog title for auto complete choices + */ + public static final int auto_complete_dialog_title=0x7f0c002e; + /** Description for auto completion + */ + public static final int auto_complete_summary=0x7f0c003a; + /** Option to automatically correct word on hitting space + */ + public static final int auto_correction=0x7f0c0029; + /** Description for auto_correction + */ + public static final int auto_correction_summary=0x7f0c002a; + /** Option to enable auto punctuate + */ + public static final int auto_punctuate=0x7f0c0033; + /** Description for auto punctuate + */ + public static final int auto_punctuate_summary=0x7f0c0034; + /** Press the "enter" key after the user speaks. Option on settings. + */ + public static final int auto_submit=0x7f0c0071; + /** Press the "enter" key after the user speaks. Summary of option in settings. + */ + public static final int auto_submit_summary=0x7f0c0072; + /** Option to enable bigram completion + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + no translation found for settings_key_modes:0 (8549888726962891527) + no translation found for settings_key_modes:1 (881280041213210923) + no translation found for settings_key_modes:2 (7317310620171067848) + */ + public static final int bigram_suggestion=0x7f0c003f; + /** Description for auto completion + */ + public static final int bigram_suggestion_summary=0x7f0c0040; + /** Label on button to stop recognition. Must be short to fit on button. + */ + public static final int cancel=0x7f0c006b; + /** appears above the image showing the back button used to close the keyboard + */ + public static final int close_the_keyboard=0x7f0c0074; + /** Title for Latin keyboard debug settings activity / dialog + */ + public static final int english_ime_debug_settings=0x7f0c008d; + /** Title for Latin keyboard input options dialog + */ + public static final int english_ime_input_options=0x7f0c0021; + /** Title for Latin keyboard + */ + public static final int english_ime_name=0x7f0c001f; + /** Title for Latin keyboard settings activity / dialog + */ + public static final int english_ime_settings=0x7f0c0020; + /** Inform the user that a particular language has an available dictionary + */ + public static final int has_dictionary=0x7f0c0080; + /** Add to dictionary hint + outdated translation 8058519710062071085 + */ + public static final int hint_add_to_dictionary=0x7f0c007f; + /** Option to enable using nearby keys when correcting/predicting + */ + public static final int hit_correction=0x7f0c0025; + /** Option to enable using nearby keys when correcting/predicting in landscape + */ + public static final int hit_correction_land=0x7f0c0027; + /** Description for hit_correction in landscape + */ + public static final int hit_correction_land_summary=0x7f0c0028; + /** Description for hit_correction + */ + public static final int hit_correction_summary=0x7f0c0026; + /** Description for keyboard theme switcher + */ + public static final int keyboard_layout=0x7f0c0085; + /** appears above image showing how to access keyboard settings + */ + public static final int keyboard_settings=0x7f0c0076; + /** Label for "switch to alphabetic" key. Must be short to fit on key! + */ + public static final int label_alpha_key=0x7f0c0057; + /** Label for ALT modifier key. Must be short to fit on key! + */ + public static final int label_alt_key=0x7f0c0058; + /** Label for soft enter key when it performs DONE action. Must be short to fit on key! + */ + public static final int label_done_key=0x7f0c0053; + /** Label for soft enter key when it performs GO action. Must be short to fit on key! + */ + public static final int label_go_key=0x7f0c0051; + /** Label for soft enter key when it performs NEXT action. Must be short to fit on key! + */ + public static final int label_next_key=0x7f0c0052; + /** Label for "switch to numeric" key. Must be short to fit on key! + */ + public static final int label_phone_key=0x7f0c0056; + /** Label for soft enter key when it performs SEND action. Must be short to fit on key! + */ + public static final int label_send_key=0x7f0c0054; + /** Label for "switch to symbols" key. Must be short to fit on key! + */ + public static final int label_symbol_key=0x7f0c0055; + /** Title summary for input language selection screen + */ + public static final int language_selection_summary=0x7f0c007e; + /** Title for input language selection screen + */ + public static final int language_selection_title=0x7f0c007d; + public static final int layout_basic=0x7f0c0086; + public static final int layout_gingerbread=0x7f0c008a; + public static final int layout_high_contrast=0x7f0c0087; + public static final int layout_stone_bold=0x7f0c0088; + public static final int layout_stone_normal=0x7f0c0089; + /** Label on button when an error occurs + */ + public static final int ok=0x7f0c006c; + /** appears above image showing the user to click on a TextView to show the IME + */ + public static final int open_the_keyboard=0x7f0c0073; + /** popular web domains for the locale - most popular, displayed on the keyboard + */ + public static final int popular_domain_0=0x7f0c0077; + /** popular web domains for the locale - item 1, displayed in the popup + */ + public static final int popular_domain_1=0x7f0c0078; + /** popular web domains for the locale - item 2, displayed in the popup + */ + public static final int popular_domain_2=0x7f0c0079; + /** popular web domains for the locale - item 3, displayed in the popup + */ + public static final int popular_domain_3=0x7f0c007a; + /** popular web domains for the locale - item 4, displayed in the popup + */ + public static final int popular_domain_4=0x7f0c007b; + /** Option to pop up the character with a larger font above soft keyboard + */ + public static final int popup_on_keypress=0x7f0c0024; + /** Option to enable text prediction + */ + public static final int prediction=0x7f0c002b; + /** Don't translate + */ + public static final int prediction_basic=0x7f0c0042; + /** Category title for text prediction + */ + public static final int prediction_category=0x7f0c002c; + /** Don't translate + */ + public static final int prediction_full=0x7f0c0043; + /** Option to enable text prediction in landscape + */ + public static final int prediction_landscape=0x7f0c002f; + /** Description for text prediction + */ + public static final int prediction_landscape_summary=0x7f0c0030; + /** Don't translate + */ + public static final int prediction_none=0x7f0c0041; + /** Description for text prediction + */ + public static final int prediction_summary=0x7f0c002d; + public static final int prefs_debug_mode=0x7f0c008e; + /** Description for enabling to send user statistics to Google + */ + public static final int prefs_description_log=0x7f0c0082; + /** Preferences item for enabling to send user statistics to Google + */ + public static final int prefs_enable_log=0x7f0c0081; + /** Preferences item for enabling to correct suggestions by touching words you have typed + */ + public static final int prefs_enable_recorrection=0x7f0c0083; + /** The summary for the preferences item for enabling to correct suggestions by touching words you have typed + */ + public static final int prefs_enable_recorrection_summary=0x7f0c0084; + /** Option to show/hide the settings key + */ + public static final int prefs_settings_key=0x7f0c003b; + /** Option to enable quick fixes + */ + public static final int quick_fixes=0x7f0c0035; + /** Description for quick fixes + */ + public static final int quick_fixes_summary=0x7f0c0036; + /** Menu item for launching Input method picker + */ + public static final int selectInputMethod=0x7f0c007c; + /** Symbols that are sentence separators, for purposes of making it hug the last sentence. + Symbols that are sentence separators, for purposes of making it hug the last sentence. + */ + public static final int sentence_separators=0x7f0c001a; + /** Always hide the settings key + */ + public static final int settings_key_mode_always_hide=0x7f0c001e; + /** Option to always hide the settings key + */ + public static final int settings_key_mode_always_hide_name=0x7f0c003e; + /** Always show the settings key + */ + public static final int settings_key_mode_always_show=0x7f0c001d; + /** Option to always show the settings key + */ + public static final int settings_key_mode_always_show_name=0x7f0c003d; + /** Option values to show/hide the settings key in onscreen keyboard + Automatically decide to show or hide the settings key + */ + public static final int settings_key_mode_auto=0x7f0c001c; + /** Option to automatically decide to show/hide the settings key + */ + public static final int settings_key_mode_auto_name=0x7f0c003c; + /** Option to enable showing suggestions + */ + public static final int show_suggestions=0x7f0c0037; + /** Description for show suggestions + */ + public static final int show_suggestions_summary=0x7f0c0038; + /** Option to play back sound on keypress in soft keyboard + */ + public static final int sound_on_keypress=0x7f0c0023; + public static final int subtype_mode_keyboard=0x7f0c008b; + public static final int subtype_mode_voice=0x7f0c008c; + /** Symbols that are suggested between words + */ + public static final int suggested_punctuations=0x7f0c001b; + /** Tip to press ?123 to access numbers and symbols + */ + public static final int tip_access_symbols=0x7f0c0047; + /** Tip to long press on typed word to add to dictionary + */ + public static final int tip_add_to_dictionary=0x7f0c0048; + /** Tip to dismiss keyboard + */ + public static final int tip_dismiss=0x7f0c0046; + /** Tip to long press on keys + */ + public static final int tip_long_press=0x7f0c0045; + /** Tutorial tip 4 - How to switch back to alphabet keyboard + */ + public static final int tip_to_close_symbols=0x7f0c004e; + /** Tutorial tip 5 - How to launch keyboard settings + */ + public static final int tip_to_launch_settings=0x7f0c004f; + /** Tutorial tip 1 - The keyboard opens any time you touch a text field + */ + public static final int tip_to_open_keyboard=0x7f0c004b; + /** Tutorial tip 3 - How to switch to number/symbol keyboard + */ + public static final int tip_to_open_symbols=0x7f0c004d; + /** Tutorial tip 6 - Done with the tutorial + */ + public static final int tip_to_start_typing=0x7f0c0050; + /** Tutorial tip 2 - Touch and hold a key to view accents (examples) + */ + public static final int tip_to_view_accents=0x7f0c004c; + /** appears above image showing how to use touch and hold + */ + public static final int touch_and_hold=0x7f0c0075; + /** Instruction to touch the bubble to continue + */ + public static final int touch_to_continue=0x7f0c0049; + /** Instruction to touch the bubble to start typing + */ + public static final int touch_to_finish=0x7f0c004a; + /** Option to provide vibrate/haptic feedback on keypress + */ + public static final int vibrate_on_keypress=0x7f0c0022; + /** Short message shown for an audio error. + */ + public static final int voice_audio_error=0x7f0c0064; + /** Short message shown when a generic error occurs. + */ + public static final int voice_error=0x7f0c0061; + /** Message to show when user clicks the swiping hint (which says + "Swipe across keyboard to speak"). Also shown when enabling settings. + */ + public static final int voice_hint_dialog_message=0x7f0c005d; + /** Short message shown before the user should speak. + */ + public static final int voice_initializing=0x7f0c0060; + /** Preferences item for enabling speech input + */ + public static final int voice_input=0x7f0c006d; + /** Short message to tell the user the system is ready for them to speak. + */ + public static final int voice_listening=0x7f0c005e; + /** Don't translate + */ + public static final int voice_mode_main=0x7f0c006e; + /** Don't translate + */ + public static final int voice_mode_off=0x7f0c0070; + /** Don't translate + */ + public static final int voice_mode_symbols=0x7f0c006f; + /** Short message shown for a network error. + */ + public static final int voice_network_error=0x7f0c0062; + /** Short message shown when the server couldn't parse any speech. + */ + public static final int voice_no_match=0x7f0c0067; + /** Short message shown when the user initiates voice and voice + search is not installed. + */ + public static final int voice_not_installed=0x7f0c0068; + /** Short hint shown in candidate view to explain that user can speak punctuation. + */ + public static final int voice_punctuation_hint=0x7f0c006a; + /** Short message shown for an error with the voice server. + */ + public static final int voice_server_error=0x7f0c0065; + /** Short message shown when no speech is heard. + */ + public static final int voice_speech_timeout=0x7f0c0066; + /** Short hint shown in candidate view to explain voice input. + */ + public static final int voice_swipe_hint=0x7f0c0069; + /** Short message shown for a network error where the utterance was really long, + in which case we should suggest that the user speak less. + */ + public static final int voice_too_much_speech=0x7f0c0063; + /** An additional part of the warning dialog for voice input that only shows when the user + actually initiates voice input, rather than just turning it on in settings. + */ + public static final int voice_warning_how_to_turn_off=0x7f0c005c; + /** Message that gets put at the top of the warning dialog if the user is attempting to use + voice input in a currently unsupported locale. Voice input will work for such a user, + but it will only recognize them in English. + */ + public static final int voice_warning_locale_not_supported=0x7f0c005a; + /** Message of the warning dialog that shows when a user initiates voice input for + the first time, or turns it on in settings. + */ + public static final int voice_warning_may_not_understand=0x7f0c005b; + /** Voice related labels + Title of the warning dialog that shows when a user initiates voice input for + the first time. + */ + public static final int voice_warning_title=0x7f0c0059; + /** Short message shown after the user finishes speaking. + */ + public static final int voice_working=0x7f0c005f; + /** Symbols that are commonly considered word separators in this language + Symbols that are commonly considered word separators in this language + Symbols that are commonly considered word separators in this language + */ + public static final int word_separators=0x7f0c0019; + } + public static final class style { + public static final int KeyPreviewAnimation=0x7f0e0001; + public static final int LatinKeyboardBaseView=0x7f0e0000; + public static final int MiniKeyboardAnimation=0x7f0e0002; + } + public static final class xml { + public static final int dictionary=0x7f050000; + public static final int kbd_phone=0x7f050001; + public static final int kbd_phone_black=0x7f050002; + public static final int kbd_phone_symbols=0x7f050003; + public static final int kbd_phone_symbols_black=0x7f050004; + public static final int kbd_popup_narrow_template=0x7f050005; + public static final int kbd_popup_template=0x7f050006; + public static final int kbd_qwerty=0x7f050007; + public static final int kbd_qwerty_black=0x7f050008; + public static final int kbd_symbols=0x7f050009; + public static final int kbd_symbols_black=0x7f05000a; + public static final int kbd_symbols_shift=0x7f05000b; + public static final int kbd_symbols_shift_black=0x7f05000c; + public static final int language_prefs=0x7f05000d; + public static final int method=0x7f05000e; + public static final int popup_at=0x7f05000f; + public static final int popup_comma=0x7f050010; + public static final int popup_domains=0x7f050011; + public static final int popup_mic=0x7f050012; + public static final int popup_punctuation=0x7f050013; + public static final int popup_slash=0x7f050014; + public static final int popup_smileys=0x7f050015; + public static final int prefs=0x7f050016; + public static final int prefs_for_debug=0x7f050017; + } + public static final class styleable { + /** Attributes that can be used with a LatinKeyboardBaseView. +

Includes the following attributes:

+ + + + + + + + + + + + + + + + + + + + +
AttributeDescription
{@link #LatinKeyboardBaseView_backgroundDimAmount keepass2android.softkeyboard:backgroundDimAmount}
{@link #LatinKeyboardBaseView_keyBackground keepass2android.softkeyboard:keyBackground} Image for the key.
{@link #LatinKeyboardBaseView_keyHysteresisDistance keepass2android.softkeyboard:keyHysteresisDistance} Hysteresis distance for key debouncing
{@link #LatinKeyboardBaseView_keyPreviewHeight keepass2android.softkeyboard:keyPreviewHeight} Height of the key press feedback popup.
{@link #LatinKeyboardBaseView_keyPreviewLayout keepass2android.softkeyboard:keyPreviewLayout} Layout resource for key press feedback.
{@link #LatinKeyboardBaseView_keyPreviewOffset keepass2android.softkeyboard:keyPreviewOffset} Vertical offset of the key press feedback from the key.
{@link #LatinKeyboardBaseView_keyTextColor keepass2android.softkeyboard:keyTextColor} Color to use for the label in a key.
{@link #LatinKeyboardBaseView_keyTextSize keepass2android.softkeyboard:keyTextSize} Size of the text for character keys.
{@link #LatinKeyboardBaseView_keyTextStyle keepass2android.softkeyboard:keyTextStyle}
{@link #LatinKeyboardBaseView_keyboardViewStyle keepass2android.softkeyboard:keyboardViewStyle} Default KeyboardView style.
{@link #LatinKeyboardBaseView_labelTextSize keepass2android.softkeyboard:labelTextSize} Size of the text for custom keys with some text and no icon.
{@link #LatinKeyboardBaseView_popupLayout keepass2android.softkeyboard:popupLayout} Layout resource for popup keyboards.
{@link #LatinKeyboardBaseView_shadowColor keepass2android.softkeyboard:shadowColor}
{@link #LatinKeyboardBaseView_shadowRadius keepass2android.softkeyboard:shadowRadius}
{@link #LatinKeyboardBaseView_symbolColorScheme keepass2android.softkeyboard:symbolColorScheme}
{@link #LatinKeyboardBaseView_verticalCorrection keepass2android.softkeyboard:verticalCorrection} Amount to offset the touch Y coordinate by, for bias correction.
+ @see #LatinKeyboardBaseView_backgroundDimAmount + @see #LatinKeyboardBaseView_keyBackground + @see #LatinKeyboardBaseView_keyHysteresisDistance + @see #LatinKeyboardBaseView_keyPreviewHeight + @see #LatinKeyboardBaseView_keyPreviewLayout + @see #LatinKeyboardBaseView_keyPreviewOffset + @see #LatinKeyboardBaseView_keyTextColor + @see #LatinKeyboardBaseView_keyTextSize + @see #LatinKeyboardBaseView_keyTextStyle + @see #LatinKeyboardBaseView_keyboardViewStyle + @see #LatinKeyboardBaseView_labelTextSize + @see #LatinKeyboardBaseView_popupLayout + @see #LatinKeyboardBaseView_shadowColor + @see #LatinKeyboardBaseView_shadowRadius + @see #LatinKeyboardBaseView_symbolColorScheme + @see #LatinKeyboardBaseView_verticalCorrection + */ + public static final int[] LatinKeyboardBaseView = { + 0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003, + 0x7f010004, 0x7f010005, 0x7f010006, 0x7f010007, + 0x7f010008, 0x7f010009, 0x7f01000a, 0x7f01000b, + 0x7f01000c, 0x7f01000d, 0x7f01000e, 0x7f01000f + }; + /** +

This symbol is the offset where the {@link keepass2android.softkeyboard.R.attr#backgroundDimAmount} + attribute's value can be found in the {@link #LatinKeyboardBaseView} array. + + +

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name android:backgroundDimAmount + */ + public static final int LatinKeyboardBaseView_backgroundDimAmount = 13; + /** +

+ @attr description + Image for the key. This image needs to be a StateListDrawable, with the following + possible states: normal, pressed, checkable, checkable+pressed, checkable+checked, + checkable+checked+pressed. + + +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". +

This is a private symbol. + @attr name android:keyBackground + */ + public static final int LatinKeyboardBaseView_keyBackground = 1; + /** +

+ @attr description + Hysteresis distance for key debouncing + + +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:keyHysteresisDistance + */ + public static final int LatinKeyboardBaseView_keyHysteresisDistance = 8; + /** +

+ @attr description + Height of the key press feedback popup. + + +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:keyPreviewHeight + */ + public static final int LatinKeyboardBaseView_keyPreviewHeight = 7; + /** +

+ @attr description + Layout resource for key press feedback. + + +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". +

This is a private symbol. + @attr name android:keyPreviewLayout + */ + public static final int LatinKeyboardBaseView_keyPreviewLayout = 5; + /** +

+ @attr description + Vertical offset of the key press feedback from the key. + + +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:keyPreviewOffset + */ + public static final int LatinKeyboardBaseView_keyPreviewOffset = 6; + /** +

+ @attr description + Color to use for the label in a key. + + +

Must be a color value, in the form of "#rgb", "#argb", +"#rrggbb", or "#aarrggbb". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:keyTextColor + */ + public static final int LatinKeyboardBaseView_keyTextColor = 4; + /** +

+ @attr description + Size of the text for character keys. + + +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:keyTextSize + */ + public static final int LatinKeyboardBaseView_keyTextSize = 2; + /** +

This symbol is the offset where the {@link keepass2android.softkeyboard.R.attr#keyTextStyle} + attribute's value can be found in the {@link #LatinKeyboardBaseView} array. + + +

Must be one or more (separated by '|') of the following constant values.

+ ++++ + + + +
ConstantValueDescription
normal0
bold1
italic2
+ @attr name android:keyTextStyle + */ + public static final int LatinKeyboardBaseView_keyTextStyle = 14; + /** +

+ @attr description + Default KeyboardView style. + + +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". +

This is a private symbol. + @attr name android:keyboardViewStyle + */ + public static final int LatinKeyboardBaseView_keyboardViewStyle = 0; + /** +

+ @attr description + Size of the text for custom keys with some text and no icon. + + +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:labelTextSize + */ + public static final int LatinKeyboardBaseView_labelTextSize = 3; + /** +

+ @attr description + Layout resource for popup keyboards. + + +

Must be a reference to another resource, in the form "@[+][package:]type:name" +or to a theme attribute in the form "?[package:][type:]name". +

This is a private symbol. + @attr name android:popupLayout + */ + public static final int LatinKeyboardBaseView_popupLayout = 10; + /** +

This symbol is the offset where the {@link keepass2android.softkeyboard.R.attr#shadowColor} + attribute's value can be found in the {@link #LatinKeyboardBaseView} array. + + +

Must be a color value, in the form of "#rgb", "#argb", +"#rrggbb", or "#aarrggbb". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name android:shadowColor + */ + public static final int LatinKeyboardBaseView_shadowColor = 11; + /** +

This symbol is the offset where the {@link keepass2android.softkeyboard.R.attr#shadowRadius} + attribute's value can be found in the {@link #LatinKeyboardBaseView} array. + + +

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name android:shadowRadius + */ + public static final int LatinKeyboardBaseView_shadowRadius = 12; + /** +

This symbol is the offset where the {@link keepass2android.softkeyboard.R.attr#symbolColorScheme} + attribute's value can be found in the {@link #LatinKeyboardBaseView} array. + + +

Must be one or more (separated by '|') of the following constant values.

+ ++++ + + +
ConstantValueDescription
white0
black1
+ @attr name android:symbolColorScheme + */ + public static final int LatinKeyboardBaseView_symbolColorScheme = 15; + /** +

+ @attr description + Amount to offset the touch Y coordinate by, for bias correction. + + +

Must be a dimension value, which is a floating point number appended with a unit such as "14.5sp". +Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), +in (inches), mm (millimeters). +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. +

This is a private symbol. + @attr name android:verticalCorrection + */ + public static final int LatinKeyboardBaseView_verticalCorrection = 9; + }; +} diff --git a/src/java/KP2ASoftKeyboard2/java/libs/armeabi-v7a/libjni_latinime.so b/src/java/KP2ASoftKeyboard2/java/libs/armeabi-v7a/libjni_latinime.so new file mode 100644 index 00000000..fce10f89 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/libs/armeabi-v7a/libjni_latinime.so differ diff --git a/src/java/KP2ASoftKeyboard2/java/libs/armeabi/libjni_latinime.so b/src/java/KP2ASoftKeyboard2/java/libs/armeabi/libjni_latinime.so new file mode 100644 index 00000000..3f97a516 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/libs/armeabi/libjni_latinime.so differ diff --git a/src/java/KP2ASoftKeyboard2/java/libs/mips/libjni_latinime.so b/src/java/KP2ASoftKeyboard2/java/libs/mips/libjni_latinime.so new file mode 100644 index 00000000..87fddde6 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/libs/mips/libjni_latinime.so differ diff --git a/src/java/KP2ASoftKeyboard2/java/libs/x86/libjni_latinime.so b/src/java/KP2ASoftKeyboard2/java/libs/x86/libjni_latinime.so new file mode 100644 index 00000000..7dc1bbe4 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/libs/x86/libjni_latinime.so differ diff --git a/src/java/KP2ASoftKeyboard2/java/proguard.flags b/src/java/KP2ASoftKeyboard2/java/proguard.flags new file mode 100644 index 00000000..95c153fd --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/proguard.flags @@ -0,0 +1,8 @@ +-keep class keepass2android.softkeyboard.BinaryDictionary { + int mDictLength; + (...); +} + +-keep class keepass2android.softkeyboard.Suggest { + (...); +} diff --git a/src/java/KP2ASoftKeyboard2/java/project.properties b/src/java/KP2ASoftKeyboard2/java/project.properties new file mode 100644 index 00000000..a3ee5ab6 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-17 diff --git a/src/java/KP2ASoftKeyboard2/java/res/anim/key_preview_fadein.xml b/src/java/KP2ASoftKeyboard2/java/res/anim/key_preview_fadein.xml new file mode 100644 index 00000000..9fad7b9a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/anim/key_preview_fadein.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/anim/key_preview_fadeout.xml b/src/java/KP2ASoftKeyboard2/java/res/anim/key_preview_fadeout.xml new file mode 100644 index 00000000..7de5123c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/anim/key_preview_fadeout.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/anim/mini_keyboard_fadein.xml b/src/java/KP2ASoftKeyboard2/java/res/anim/mini_keyboard_fadein.xml new file mode 100644 index 00000000..9fad7b9a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/anim/mini_keyboard_fadein.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/anim/mini_keyboard_fadeout.xml b/src/java/KP2ASoftKeyboard2/java/res/anim/mini_keyboard_fadeout.xml new file mode 100644 index 00000000..7de5123c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/anim/mini_keyboard_fadeout.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png new file mode 100644 index 00000000..01fc8ca7 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png new file mode 100644 index 00000000..af4017e2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png new file mode 100644 index 00000000..4c35aca9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png new file mode 100644 index 00000000..174f3452 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png new file mode 100644 index 00000000..1fcbd9a8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png new file mode 100644 index 00000000..072753f3 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png new file mode 100644 index 00000000..b6c234c0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png new file mode 100644 index 00000000..73a8cd1c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png new file mode 100644 index 00000000..1ad74605 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_popup_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_popup_normal.9.png new file mode 100644 index 00000000..e3a77d61 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_popup_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png new file mode 100644 index 00000000..431c4496 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png new file mode 100644 index 00000000..ccd59d5f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png new file mode 100644 index 00000000..42c7c146 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png new file mode 100644 index 00000000..01e2506b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.png new file mode 100644 index 00000000..fad0ec45 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png new file mode 100644 index 00000000..83c6eb3f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.png new file mode 100644 index 00000000..215f8157 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.png new file mode 100644 index 00000000..88acdd74 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png new file mode 100644 index 00000000..e047eaff Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png new file mode 100644 index 00000000..218a2d29 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png new file mode 100644 index 00000000..afe49512 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/cancel.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/cancel.png new file mode 100644 index 00000000..506cf99d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/cancel.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/candidate_feedback_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/candidate_feedback_background.9.png new file mode 100644 index 00000000..203c4e64 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/candidate_feedback_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/caution.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/caution.png new file mode 100644 index 00000000..5cb6c54b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/caution.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/dialog_bubble_step02.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/dialog_bubble_step02.9.png new file mode 100644 index 00000000..b338364c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/dialog_bubble_step02.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/dialog_bubble_step07.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/dialog_bubble_step07.9.png new file mode 100644 index 00000000..94b91543 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/dialog_bubble_step07.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/highlight_pressed.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/highlight_pressed.png new file mode 100644 index 00000000..ae04901a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/highlight_pressed.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/hint_popup.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/hint_popup.9.png new file mode 100644 index 00000000..b5ec003e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/hint_popup.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_dialog_keyboard.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_dialog_keyboard.png new file mode 100644 index 00000000..c7729566 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_dialog_keyboard.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_mic_dialog.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_mic_dialog.png new file mode 100644 index 00000000..349dc4b3 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_mic_dialog.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_subtype_keyboard.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_subtype_keyboard.png new file mode 100644 index 00000000..7015e266 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_subtype_keyboard.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_subtype_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_subtype_mic.png new file mode 100644 index 00000000..cb86a559 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_subtype_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_suggest_strip_microphone.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_suggest_strip_microphone.png new file mode 100644 index 00000000..c00b4aaa Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_suggest_strip_microphone.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_suggest_strip_microphone_swipe.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_suggest_strip_microphone_swipe.png new file mode 100644 index 00000000..256dc3d6 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ic_suggest_strip_microphone_swipe.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_background.9.png new file mode 100644 index 00000000..edffac5b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_dark_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_dark_background.9.png new file mode 100644 index 00000000..f315cbdd Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_dark_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_0.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_0.9.png new file mode 100644 index 00000000..271264e9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_0.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_1.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_1.9.png new file mode 100644 index 00000000..eaf37426 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_1.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_2.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_2.9.png new file mode 100644 index 00000000..8a165711 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_2.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_3.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_3.9.png new file mode 100644 index 00000000..34b50110 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_3.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_4.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_4.9.png new file mode 100644 index 00000000..d4cc250d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_4.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_5.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_5.9.png new file mode 100644 index 00000000..6a054b42 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_5.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_6.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_6.9.png new file mode 100644 index 00000000..66e91400 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_6.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_7.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_7.9.png new file mode 100644 index 00000000..5eae24f4 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_7.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_8.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_8.9.png new file mode 100644 index 00000000..ea7f512f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_8.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_9.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_9.9.png new file mode 100644 index 00000000..0bf85de9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_hint_9.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png new file mode 100644 index 00000000..762a2570 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png new file mode 100644 index 00000000..141d2d6b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png new file mode 100644 index 00000000..d6b2c793 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_suggest_strip.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_suggest_strip.9.png new file mode 100644 index 00000000..0ccdb6ab Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_suggest_strip.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png new file mode 100644 index 00000000..7ca3e613 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/list_selector_background_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/list_selector_background_pressed.9.png new file mode 100644 index 00000000..ba79cf7f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/list_selector_background_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/mic_slash.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/mic_slash.png new file mode 100644 index 00000000..dc8da625 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/mic_slash.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ok_cancel.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ok_cancel.png new file mode 100644 index 00000000..f11e57a3 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/ok_cancel.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level0.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level0.png new file mode 100644 index 00000000..342849cf Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level0.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level1.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level1.png new file mode 100644 index 00000000..8947a430 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level1.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level2.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level2.png new file mode 100644 index 00000000..44fc58c4 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level2.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level3.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level3.png new file mode 100644 index 00000000..cfa5c1b8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level3.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level4.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level4.png new file mode 100644 index 00000000..a050d883 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level4.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level5.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level5.png new file mode 100644 index 00000000..8cd5ae7a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level5.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level6.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level6.png new file mode 100644 index 00000000..9f4481eb Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/speak_now_level6.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_123_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_123_mic.png new file mode 100644 index 00000000..3e4eff69 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_123_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_delete.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_delete.png new file mode 100644 index 00000000..1d24cc85 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_delete.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_done.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_done.png new file mode 100644 index 00000000..b77803d2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_done.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_kp2a.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_kp2a.png new file mode 100644 index 00000000..66608769 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_kp2a.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_mic.png new file mode 100644 index 00000000..512f4608 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num0.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num0.png new file mode 100644 index 00000000..678a790d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num0.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num1.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num1.png new file mode 100644 index 00000000..4e68e35b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num1.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num2.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num2.png new file mode 100644 index 00000000..546663fd Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num2.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num3.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num3.png new file mode 100644 index 00000000..57f9a8d8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num3.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num4.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num4.png new file mode 100644 index 00000000..de504388 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num4.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num5.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num5.png new file mode 100644 index 00000000..1d2e1ef8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num5.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num6.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num6.png new file mode 100644 index 00000000..39788b72 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num6.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num7.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num7.png new file mode 100644 index 00000000..fff6f27b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num7.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num8.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num8.png new file mode 100644 index 00000000..8cc1a955 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num8.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num9.png new file mode 100644 index 00000000..02174250 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_num9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numalt.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numalt.png new file mode 100644 index 00000000..200714f6 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numalt.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numpound.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numpound.png new file mode 100644 index 00000000..0a46122b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numpound.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numstar.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numstar.png new file mode 100644 index 00000000..ca22bd53 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_numstar.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_return.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_return.png new file mode 100644 index 00000000..426e1599 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_return.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_search.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_search.png new file mode 100644 index 00000000..1b6f884f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_search.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_settings.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_settings.png new file mode 100644 index 00000000..08ba18f2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_settings.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_shift.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_shift.png new file mode 100644 index 00000000..5a22dd30 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_shift.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_shift_locked.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_shift_locked.png new file mode 100644 index 00000000..56644912 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_shift_locked.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_space.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_space.png new file mode 100644 index 00000000..cd0ebe2f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_space.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_tab.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_tab.png new file mode 100644 index 00000000..3466e127 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_bkeyboard_tab.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_123_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_123_mic.png new file mode 100644 index 00000000..62669803 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_123_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_delete.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_delete.png new file mode 100644 index 00000000..459ebcff Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_delete.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_done.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_done.png new file mode 100644 index 00000000..471c5021 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_done.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png new file mode 100644 index 00000000..eef78968 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png new file mode 100644 index 00000000..8322e8e1 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_done.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_done.png new file mode 100644 index 00000000..7015e266 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_done.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_kp2a.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_kp2a.png new file mode 100644 index 00000000..d4616218 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_kp2a.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png new file mode 100644 index 00000000..889477cf Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png new file mode 100644 index 00000000..b0f6d7fe Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png new file mode 100644 index 00000000..f82c33ae Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png new file mode 100644 index 00000000..819236c8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_return.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_return.png new file mode 100644 index 00000000..f038d3ab Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_return.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_search.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_search.png new file mode 100644 index 00000000..337f9e4f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_search.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_settings.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_settings.png new file mode 100644 index 00000000..8a02be07 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_settings.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png new file mode 100644 index 00000000..abf15f8f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png new file mode 100644 index 00000000..1fd822ea Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_space.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_space.png new file mode 100644 index 00000000..70debca9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_space.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png new file mode 100644 index 00000000..d2efb161 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_kp2a.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_kp2a.png new file mode 100644 index 00000000..2ed9041d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_kp2a.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png new file mode 100644 index 00000000..dcc4bd59 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png new file mode 100644 index 00000000..ecf61a98 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_mic.png new file mode 100644 index 00000000..c8dca62a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num0.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num0.png new file mode 100644 index 00000000..10ac70b9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num0.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num1.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num1.png new file mode 100644 index 00000000..0fc03efa Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num1.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num2.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num2.png new file mode 100644 index 00000000..283560b3 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num2.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num3.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num3.png new file mode 100644 index 00000000..9a3b3294 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num3.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num4.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num4.png new file mode 100644 index 00000000..f13ff1ae Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num4.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num5.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num5.png new file mode 100644 index 00000000..c251329f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num5.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num6.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num6.png new file mode 100644 index 00000000..4acba4c9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num6.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num7.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num7.png new file mode 100644 index 00000000..14931c18 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num7.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num8.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num8.png new file mode 100644 index 00000000..d4973fdc Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num8.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num9.png new file mode 100644 index 00000000..49cec66f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_num9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numalt.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numalt.png new file mode 100644 index 00000000..3cc5311c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numalt.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numpound.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numpound.png new file mode 100644 index 00000000..d0913392 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numpound.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numstar.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numstar.png new file mode 100644 index 00000000..e838e169 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_numstar.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_return.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_return.png new file mode 100644 index 00000000..9d97e1ef Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_return.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_search.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_search.png new file mode 100644 index 00000000..1aa22d7e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_search.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_settings.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_settings.png new file mode 100644 index 00000000..35d1ed6e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_settings.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_shift.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_shift.png new file mode 100644 index 00000000..bf217d14 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_shift.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_shift_locked.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_shift_locked.png new file mode 100644 index 00000000..d11b3971 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_shift_locked.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_space.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_space.png new file mode 100644 index 00000000..fcd20de7 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_space.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_space_led.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_space_led.9.png new file mode 100644 index 00000000..2c6f4a92 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_space_led.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_tab.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_tab.png new file mode 100644 index 00000000..51d17d98 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/sym_keyboard_tab.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/voice_ime_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/voice_ime_background.9.png new file mode 100644 index 00000000..42868522 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/voice_ime_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/voice_swipe_hint.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/voice_swipe_hint.png new file mode 100644 index 00000000..130f83a9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/voice_swipe_hint.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/working.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/working.png new file mode 100644 index 00000000..5ea70230 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-hdpi/working.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-land/btn_keyboard_key.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable-land/btn_keyboard_key.xml new file mode 100644 index 00000000..45578e58 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable-land/btn_keyboard_key.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png new file mode 100644 index 00000000..4e337fa0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png new file mode 100644 index 00000000..fe18497d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png new file mode 100644 index 00000000..00aab3d5 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png new file mode 100644 index 00000000..ac0bfd3c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png new file mode 100644 index 00000000..ea2f3578 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png new file mode 100644 index 00000000..6195ac0d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png new file mode 100644 index 00000000..20f3d508 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png new file mode 100644 index 00000000..1ed3065c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png new file mode 100644 index 00000000..50cd06ae Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png new file mode 100644 index 00000000..02d0fcf9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png new file mode 100644 index 00000000..125ff133 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png new file mode 100644 index 00000000..7ce52f0f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png new file mode 100644 index 00000000..7ba18dd2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png new file mode 100644 index 00000000..bda9b839 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.png new file mode 100644 index 00000000..fad0ec45 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png new file mode 100644 index 00000000..0c16ed50 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.png new file mode 100644 index 00000000..215f8157 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.png new file mode 100644 index 00000000..88acdd74 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png new file mode 100644 index 00000000..39b9314a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png new file mode 100644 index 00000000..bdcf06e1 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png new file mode 100644 index 00000000..79621a9e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/cancel.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/cancel.png new file mode 100644 index 00000000..713a3787 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/cancel.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/candidate_feedback_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/candidate_feedback_background.9.png new file mode 100644 index 00000000..2a80f096 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/candidate_feedback_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/caution.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/caution.png new file mode 100644 index 00000000..eaef5342 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/caution.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/dialog_bubble_step02.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/dialog_bubble_step02.9.png new file mode 100644 index 00000000..d77f85fe Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/dialog_bubble_step02.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/dialog_bubble_step07.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/dialog_bubble_step07.9.png new file mode 100644 index 00000000..80f4a0ea Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/dialog_bubble_step07.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/highlight_pressed.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/highlight_pressed.png new file mode 100644 index 00000000..d27f1061 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/highlight_pressed.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/hint_popup.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/hint_popup.9.png new file mode 100644 index 00000000..444cc26e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/hint_popup.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_dialog_keyboard.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_dialog_keyboard.png new file mode 100644 index 00000000..9a5aada8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_dialog_keyboard.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_mic_dialog.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_mic_dialog.png new file mode 100644 index 00000000..77613ca0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_mic_dialog.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_subtype_keyboard.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_subtype_keyboard.png new file mode 100644 index 00000000..0d7ebd4e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_subtype_keyboard.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_subtype_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_subtype_mic.png new file mode 100644 index 00000000..247d5b3a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_subtype_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_suggest_strip_microphone.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_suggest_strip_microphone.png new file mode 100644 index 00000000..18f314a6 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_suggest_strip_microphone.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_suggest_strip_microphone_swipe.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_suggest_strip_microphone_swipe.png new file mode 100644 index 00000000..ff629b67 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ic_suggest_strip_microphone_swipe.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_background.9.png new file mode 100644 index 00000000..2bd4b628 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_dark_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_dark_background.9.png new file mode 100644 index 00000000..4f81704c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_dark_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_0.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_0.9.png new file mode 100644 index 00000000..61ad1b50 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_0.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_1.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_1.9.png new file mode 100644 index 00000000..cd7772e7 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_1.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_2.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_2.9.png new file mode 100644 index 00000000..fa5f8b79 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_2.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_3.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_3.9.png new file mode 100644 index 00000000..0c7336cb Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_3.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_4.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_4.9.png new file mode 100644 index 00000000..73ef06c0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_4.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_5.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_5.9.png new file mode 100644 index 00000000..aea460e1 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_5.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_6.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_6.9.png new file mode 100644 index 00000000..16a9237e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_6.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_7.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_7.9.png new file mode 100644 index 00000000..6747a19c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_7.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_8.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_8.9.png new file mode 100644 index 00000000..28be2fb8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_8.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_9.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_9.9.png new file mode 100644 index 00000000..731d63b1 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_hint_9.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_key_feedback_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_key_feedback_background.9.png new file mode 100644 index 00000000..a84c19c3 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_key_feedback_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_key_feedback_more_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_key_feedback_more_background.9.png new file mode 100644 index 00000000..82513aad Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_key_feedback_more_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_popup_panel_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_popup_panel_background.9.png new file mode 100644 index 00000000..0d9ab97f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_popup_panel_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_suggest_strip.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_suggest_strip.9.png new file mode 100644 index 00000000..fa6c0fef Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_suggest_strip.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_suggest_strip_divider.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_suggest_strip_divider.png new file mode 100644 index 00000000..36393636 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/keyboard_suggest_strip_divider.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/list_selector_background_pressed.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/list_selector_background_pressed.9.png new file mode 100644 index 00000000..02b4e9a5 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/list_selector_background_pressed.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/mic_slash.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/mic_slash.png new file mode 100644 index 00000000..d04b5634 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/mic_slash.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ok_cancel.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ok_cancel.png new file mode 100644 index 00000000..20d10f98 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/ok_cancel.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level0.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level0.png new file mode 100644 index 00000000..5bd13603 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level0.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level1.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level1.png new file mode 100644 index 00000000..ccb76b87 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level1.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level2.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level2.png new file mode 100644 index 00000000..715f9008 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level2.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level3.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level3.png new file mode 100644 index 00000000..725248a2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level3.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level4.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level4.png new file mode 100644 index 00000000..ff6c50b4 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level4.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level5.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level5.png new file mode 100644 index 00000000..a5d6b89d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level5.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level6.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level6.png new file mode 100644 index 00000000..dcdb48d0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/speak_now_level6.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_123_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_123_mic.png new file mode 100644 index 00000000..0749b5fc Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_123_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_delete.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_delete.png new file mode 100644 index 00000000..1a5ff439 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_delete.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_done.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_done.png new file mode 100644 index 00000000..05ce7c64 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_done.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_kp2a.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_kp2a.png new file mode 100644 index 00000000..300d6b88 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_kp2a.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_mic.png new file mode 100644 index 00000000..a6cb1cc0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num0.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num0.png new file mode 100644 index 00000000..7188f9ca Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num0.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num1.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num1.png new file mode 100644 index 00000000..2a31bd45 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num1.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num2.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num2.png new file mode 100644 index 00000000..c1e9cc9b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num2.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num3.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num3.png new file mode 100644 index 00000000..e9987668 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num3.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num4.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num4.png new file mode 100644 index 00000000..7f0f3ccc Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num4.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num5.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num5.png new file mode 100644 index 00000000..5f748b41 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num5.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num6.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num6.png new file mode 100644 index 00000000..78aae74a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num6.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num7.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num7.png new file mode 100644 index 00000000..5bb874c4 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num7.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num8.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num8.png new file mode 100644 index 00000000..6b58fdc8 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num8.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num9.png new file mode 100644 index 00000000..f348c92a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_num9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numalt.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numalt.png new file mode 100644 index 00000000..4fa410b6 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numalt.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numpound.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numpound.png new file mode 100644 index 00000000..9126eed0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numpound.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numstar.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numstar.png new file mode 100644 index 00000000..9b9f1b98 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_numstar.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_return.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_return.png new file mode 100644 index 00000000..e76225d0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_return.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_search.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_search.png new file mode 100644 index 00000000..1f180155 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_search.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_settings.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_settings.png new file mode 100644 index 00000000..08ba18f2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_settings.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_shift.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_shift.png new file mode 100644 index 00000000..c981188d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_shift.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_shift_locked.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_shift_locked.png new file mode 100644 index 00000000..b8cebd06 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_shift_locked.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_space.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_space.png new file mode 100644 index 00000000..4da7ee86 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_space.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_tab.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_tab.png new file mode 100644 index 00000000..2cb991cb Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_bkeyboard_tab.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_123_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_123_mic.png new file mode 100644 index 00000000..35afe082 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_123_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_delete.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_delete.png new file mode 100644 index 00000000..1b0f3f83 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_delete.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_done.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_done.png new file mode 100644 index 00000000..c0d6d139 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_done.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_123_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_123_mic.png new file mode 100644 index 00000000..c556c35c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_123_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_delete.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_delete.png new file mode 100644 index 00000000..a79f1585 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_delete.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_done.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_done.png new file mode 100644 index 00000000..0d7ebd4e Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_done.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_kp2a.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_kp2a.png new file mode 100644 index 00000000..c3dc5a9c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_kp2a.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.png new file mode 100644 index 00000000..eecb0269 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_left.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.png new file mode 100644 index 00000000..7e10ae3a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_language_arrows_right.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_mic.png new file mode 100644 index 00000000..3ed0782d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_numalt.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_numalt.png new file mode 100644 index 00000000..bc8f1cfc Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_numalt.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_return.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_return.png new file mode 100644 index 00000000..dd99ff38 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_return.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_search.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_search.png new file mode 100644 index 00000000..6b8e01d9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_search.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_settings.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_settings.png new file mode 100644 index 00000000..03bad184 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_settings.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_shift.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_shift.png new file mode 100644 index 00000000..d5635755 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_shift.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_shift_locked.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_shift_locked.png new file mode 100644 index 00000000..494524a6 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_shift_locked.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_space.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_space.png new file mode 100644 index 00000000..36eb60c1 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_space.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png new file mode 100644 index 00000000..a10dc8fa Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_kp2a.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_kp2a.png new file mode 100644 index 00000000..db54e0ba Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_kp2a.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_language_arrows_left.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_language_arrows_left.png new file mode 100644 index 00000000..7067a8bf Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_language_arrows_left.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_language_arrows_right.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_language_arrows_right.png new file mode 100644 index 00000000..f7a133d9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_language_arrows_right.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_mic.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_mic.png new file mode 100644 index 00000000..e926b3fa Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_mic.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num0.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num0.png new file mode 100644 index 00000000..e7007c87 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num0.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num1.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num1.png new file mode 100644 index 00000000..aaac11b0 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num1.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num2.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num2.png new file mode 100644 index 00000000..4372eb8f Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num2.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num3.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num3.png new file mode 100644 index 00000000..6f54c850 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num3.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num4.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num4.png new file mode 100644 index 00000000..3e50bb95 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num4.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num5.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num5.png new file mode 100644 index 00000000..c39ef440 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num5.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num6.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num6.png new file mode 100644 index 00000000..ea88ceb9 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num6.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num7.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num7.png new file mode 100644 index 00000000..ce800ba4 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num7.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num8.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num8.png new file mode 100644 index 00000000..1a8ff94b Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num8.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num9.png new file mode 100644 index 00000000..8b344c0a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_num9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numalt.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numalt.png new file mode 100644 index 00000000..32a2cf3c Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numalt.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numpound.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numpound.png new file mode 100644 index 00000000..b2419d9a Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numpound.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numstar.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numstar.png new file mode 100644 index 00000000..cb66f968 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_numstar.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_return.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_return.png new file mode 100644 index 00000000..0c10f004 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_return.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_search.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_search.png new file mode 100644 index 00000000..614f85f5 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_search.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_settings.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_settings.png new file mode 100644 index 00000000..ad7618fa Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_settings.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift.png new file mode 100644 index 00000000..5109b047 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift_lock.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift_lock.png new file mode 100644 index 00000000..244179c2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift_lock.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift_locked.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift_locked.png new file mode 100644 index 00000000..244179c2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_shift_locked.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_space.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_space.png new file mode 100644 index 00000000..cbe4a88d Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_space.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_space_led.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_space_led.9.png new file mode 100644 index 00000000..1c1ca2cc Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_space_led.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_tab.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_tab.png new file mode 100644 index 00000000..eddb9a59 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/sym_keyboard_tab.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/voice_ime_background.9.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/voice_ime_background.9.png new file mode 100644 index 00000000..9b15bc25 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/voice_ime_background.9.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/voice_swipe_hint.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/voice_swipe_hint.png new file mode 100644 index 00000000..bb887325 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/voice_swipe_hint.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/working.png b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/working.png new file mode 100644 index 00000000..4a930c52 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/drawable-mdpi/working.png differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key.xml new file mode 100644 index 00000000..45578e58 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key2.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key2.xml new file mode 100644 index 00000000..bd745b76 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key2.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key3.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key3.xml new file mode 100644 index 00000000..dbe82d5f --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key3.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_fulltrans.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_fulltrans.xml new file mode 100644 index 00000000..bad2a931 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_fulltrans.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_gingerbread.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_gingerbread.xml new file mode 100644 index 00000000..4a113a8a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_gingerbread.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_gingerbread_popup.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_gingerbread_popup.xml new file mode 100644 index 00000000..9b6d23be --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_gingerbread_popup.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_stone.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_stone.xml new file mode 100644 index 00000000..a6040a04 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/btn_keyboard_key_stone.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/ic_suggest_scroll_background.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/ic_suggest_scroll_background.xml new file mode 100644 index 00000000..9d246e40 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/ic_suggest_scroll_background.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/java/KP2ASoftKeyboard2/java/res/drawable/keyboard_key_feedback.xml b/src/java/KP2ASoftKeyboard2/java/res/drawable/keyboard_key_feedback.xml new file mode 100644 index 00000000..159ba868 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/drawable/keyboard_key_feedback.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/bubble_text.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/bubble_text.xml new file mode 100644 index 00000000..c3957b65 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/bubble_text.xml @@ -0,0 +1,30 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/candidate_preview.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/candidate_preview.xml new file mode 100644 index 00000000..fe2002d4 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/candidate_preview.xml @@ -0,0 +1,29 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/candidates.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/candidates.xml new file mode 100644 index 00000000..f30b817e --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/candidates.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/input_basic.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/input_basic.xml new file mode 100644 index 00000000..25085c77 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/input_basic.xml @@ -0,0 +1,31 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/input_basic_highcontrast.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/input_basic_highcontrast.xml new file mode 100644 index 00000000..ffc1c8ae --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/input_basic_highcontrast.xml @@ -0,0 +1,32 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/input_gingerbread.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/input_gingerbread.xml new file mode 100644 index 00000000..ea4334d7 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/input_gingerbread.xml @@ -0,0 +1,34 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_bold.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_bold.xml new file mode 100644 index 00000000..646465f1 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_bold.xml @@ -0,0 +1,37 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_normal.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_normal.xml new file mode 100644 index 00000000..1af02148 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_normal.xml @@ -0,0 +1,35 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_popup.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_popup.xml new file mode 100644 index 00000000..4e0e9f60 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/input_stone_popup.xml @@ -0,0 +1,41 @@ + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/key_preview.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/key_preview.xml new file mode 100644 index 00000000..de03506a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/key_preview.xml @@ -0,0 +1,29 @@ + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/keyboard_popup.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/keyboard_popup.xml new file mode 100644 index 00000000..d31f81d5 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/keyboard_popup.xml @@ -0,0 +1,41 @@ + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/recognition_status.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/recognition_status.xml new file mode 100644 index 00000000..49af7736 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/recognition_status.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/voice_punctuation_hint.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/voice_punctuation_hint.xml new file mode 100644 index 00000000..629a7f2b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/voice_punctuation_hint.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/layout/voice_swipe_hint.xml b/src/java/KP2ASoftKeyboard2/java/res/layout/voice_swipe_hint.xml new file mode 100644 index 00000000..4e8859a7 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/layout/voice_swipe_hint.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/raw/main.dict b/src/java/KP2ASoftKeyboard2/java/res/raw/main.dict new file mode 100644 index 00000000..472c23a2 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/raw/main.dict differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/raw/type3.ogg b/src/java/KP2ASoftKeyboard2/java/res/raw/type3.ogg new file mode 100644 index 00000000..20e67080 Binary files /dev/null and b/src/java/KP2ASoftKeyboard2/java/res/raw/type3.ogg differ diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ar/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ar/strings.xml new file mode 100644 index 00000000..89b5ef36 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ar/strings.xml @@ -0,0 +1,140 @@ + + + + + "لوحة مفاتيح Android" + "إعدادات لوحة مفاتيح Android" + "خيارات الإرسال" + "اهتزاز عند الضغط على مفتاح" + "صوت عند الضغط على مفتاح" + "انبثاق عند الضغط على المفاتيح" + "تصحيح أخطاء الكتابة" + "تمكين تصحيح خطأ الإدخال" + "أخطاء في الإدخال الأفقي" + "تمكين تصحيح خطأ الإدخال" + "اقتراحات الكلمات" + "تصحيح الكلمة السابقة تلقائيًا" + "اقتراحات الكلمات" + "إعدادات اقتراحات الكلمات" + "تمكين الإكمال التلقائي أثناء الكتابة" + "إكمال تلقائي" + "زيادة حجم الحقل النصي" + "إخفاء اقتراحات الكلمات في طريقة العرض الأفقية" + "استخدام الأحرف الكبيرة تلقائيًا" + "استخدام الأحرف الكبيرة في بداية الجملة" + "ترقيم تلقائي" + + "إصلاحات سريعة" + "تصحيح الأخطاء المكتوبة الشائعة" + "عرض الاقتراحات" + "عرض الكلمات المقترحة أثناء الكتابة" + "إكمال تلقائي" + "مفتاح المسافة والترقيم لإدخال كلمة محددة تلقائيًا" + "عرض مفتاح الإعدادات" + "تلقائي" + "إظهار بشكل دائم" + "إخفاء دومًا" + + + + "اقتراحات ثنائية" + "استخدام الكلمة السابقة لتحسين الاقتراح" + + "لا شيء" + "أساسي" + "متقدم" + + "%s : تم الحفظ" + "اضغط باستمرار على أحد المفاتيح لأسفل لمشاهدة علامات التشكيل" + "اضغط على مفتاح الرجوع ↶ لإغلاق لوحة المفاتيح في أي نقطة" + "الدخول إلى الأرقام والرموز" + "اضغط مع الاستمرار على أقصى يمين الكلمة لإضافتها إلى القاموس" + "المس هذا التلميح للمتابعة »" + "المس هنا لإغلاق هذا التلميح وبدء الكتابة!" + "تفتح لوحة المفاتيح في أي وقت تلمس فيه حقلًا نصيًا" + "المس مع الاستمرار أحد المفاتيح لعرض علامات التشكيل"\n"(ø, ö, ô, ó, وهكذا)" + "التبديل إلى الأرقام والرموز من خلال لمس هذا الزر" + "يمكنك الرجوع إلى الأحرف من خلال لمس هذا المفتاح مرة أخرى" + "المس هذا المفتاح مع الاستمرار لتغيير إعدادات لوحة المفاتيح، مثل الإكمال التلقائي" + "جربه!" + "تنفيذ" + "التالي" + "تم" + "إرسال" + "?123" + "123" + "ب ت ث" + "ALT" + "الإدخال الصوتي" + "الإدخال الصوتي غير معتمد حاليًا للغتك، ولكنه يعمل باللغة الإنجليزية." + "الإدخال الصوتي هو ميزة تجريبية تستخدم التعرف على الكلام المتصل في Google." + "لتشغيل الإدخال الصوتي، انتقل إلى إعدادات لوحة المفاتيح." + "لاستخدام الإدخال الصوتي، اضغط على زر الميكروفون أو مرر إصبعك عبر لوحة المفاتيح على الشاشة." + "تحدث الآن" + "العمل" + + "خطأ. الرجاء المحاولة مرة أخرى." + "تعذر الاتصال" + "خطأ، كلام أكثر مما ينبغي." + "مشكلة بالإعدادات الصوتية" + "خطأ في الخادم" + "لم يتم سماع كلام" + "لم يتمّ العثور على أية تطابقات" + "لم يتم تثبيت البحث الصوتي" + "تلميح:"" مرر عبر لوحة المفاتيح للتحدث" + "تلميح:"" جرب في المرة التالية نطق الترقيم مثل \"نقطة\" أو \"فاصلة\" أو \"علامة استفهام\"." + "إلغاء" + "موافق" + "الإدخال الصوتي" + + "في لوحة المفاتيح الرئيسية" + "على لوحة مفاتيح الرموز" + "إيقاف" + + + "الميكروفون في لوحة المفاتيح الرئيسية" + "الميكروفون على لوحة مفاتيح الرموز" + "تم تعطيل الإدخال الصوتي" + + "إرسال تلقائي بعد الصوت" + "الضغط تلقائيًا على المفتاح enter عند البحث أو الانتقال إلى الحقل التالي." + "افتح لوحة المفاتيح"\n\n"المس أي حقل نصي." + "إغلاق لوحة المفاتيح"\n\n"اضغط على المفتاح \"رجوع\"." + "المس أحد مفاتيح الخيارات مع الاستمرار"\n\n"الدخول إلى الترقيم والحركات." + "إعدادات لوحة المفاتيح"\n\n"المس مع الاستمرار المفتاح ""?123""." + "com." + "net." + "org." + "gov." + "edu." + "تحديد طريقة الإرسال" + "لغات الإدخال" + "مرر إصبعك على مفتاح المسافة لتغيير اللغة" + "← المس مرة أخرى للحفظ" + "القاموس متاح" + "تمكين ملاحظات المستخدم" + "المساعدة في تحسين محرر طريقة الإرسال هذا من خلال إرسال إحصاءات الاستخدام وتقارير الأعطال تلقائيًا إلى Google." + "المس لتصحيح الكلمات" + "المس الكلمات المدخلة لتصحيحها" + "مظهر لوحة المفاتيح" + "لوحة مفاتيح" + "صوت" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-bg/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-bg/strings.xml new file mode 100644 index 00000000..83cfaac3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-bg/strings.xml @@ -0,0 +1,140 @@ + + + + + "Клавиатура на Android" + "Настройки на клавиатурата на Android" + "Опции за въвеждане" + "Да вибрира при натискане на клавиш" + "Звук при натискане на клавиш" + "Изскачащ прозорец при натискане на клавиш" + "Коригиране на грешките при въвеждане" + "Активиране на корекция на грешки при въвеждане" + "Грешки при въвеждане в хоризонтален изглед" + "Активиране на корекция на грешки при въвеждане" + "Предложения на думи" + "Автоматично коригиране на предишната дума" + "Предложения на думи" + "Настройки за предложения на думи" + "Активиране на автодовършване, докато пишете" + "Автодовършване" + "Размерът на текстовото поле да се увеличи" + "Скриване на предложенията на думи в хоризонтален изглед" + "Автоматично поставяне на главни букви" + "Поставя главна буква в началото на изреченията" + "Автоматично поставяне на пунктуация" + + "Бързи корекции" + "Коригира най-честите грешки при въвеждане" + "Показване на предложения" + "Показване на предложения, докато пишете" + "Автоматично завършване" + "Клавишът за интервал и пунктуация поставя автоматично откроена дума" + "Показване на клавиша за настройки" + "Автоматично" + "Да се показва винаги" + "Да се скрива винаги" + + + + "Предложения за биграми" + "Използване на предишната дума за подобряване на предложението" + + "Няма" + "Основен" + "Разширени" + + "%s : Запазено" + "Задръжте клавиша, за да видите ударенията (ø, ö и т.н.)" + "Натиснете клавиша „Назад“ ↶, за да затворите клавиатурата във всяка една точка" + "Достъп до номера и символи" + "Натиснете и задръжте върху най-лявата дума, за да я добавите към речника" + "Докоснете съвета, за да продължите »" + "Докоснете тук, за да затворите този съвет и да започнете да пишете!" + "Клавиатурата се отваря при всяко докосване на текстово поле" + "Докоснете и задръжте клавиша, за да видите ударенията"\n"(ø, ö, ô, ó и т.н.)" + "Докосването на този клавиш води до преминаване към цифри и символи" + "Върнете се към използване на букви чрез повторно докосване на този клавиш" + "Докоснете и задръжте клавиша за промяна на настройките на клавиатурата, напр. автодовършване" + "Пробвайте!" + "Старт" + "Напред" + "Готово" + "Изпращане" + "?123" + "123" + "АБВГ" + "ALT" + "Гласово въвеждане" + "За вашия език понастоящем не се поддържа гласово въвеждане, но можете да го използвате на английски." + "Гласовото въвеждане е експериментална функция, използваща разпознаването на реч в мрежата на Google." + "За да изключите гласовото въвеждане, отворете настройките на клавиатурата." + "За да използвате гласово въвеждане, натиснете бутона на микрофона или плъзнете пръст през екранната клавиатура." + "Говорете сега" + "Обработва се" + + "Грешка. Моля, опитайте отново." + "Не можа да се свърже" + "Грешка, твърде много речева информация." + "Аудиопроблем" + "Грешка в сървъра" + "Не се чува реч" + "Нямаше съответствия" + "Не е инсталирано гласово търсене" + "Съвет:"" Прокарайте палец през клавиатурата, за да говорите" + "Съвет:"" Следващия път опитайте да произнесете знаците за пунктуация, напр. „точка“, „запетая“ или „въпросителен знак“." + "Отказ" + "OK" + "Гласово въвеждане" + + "На основната клавиатура" + "На клавиатурата на символите" + "Изкл." + + + "Микрофон на основната клавиатура" + "Микрофон на клавиатурата на символите" + "Гласовото въвеждане е деактивирано" + + "Автоматично изпращане след глас" + "Да се натиска автоматично „Enter“ при търсене или преминаване към следващото поле." + "Отворете клавиатурата"\n\n"Докоснете текстово поле." + "Затваряне на клавиатурата"\n\n"Натиснете клавиша „Назад“." + "Докоснете и задръжте клавиш за опции"\n\n"Използвайте пунктуация и акценти." + "Настройки на клавиатурата"\n\n"Докоснете и задръжте клавиша ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Избор на метод на въвеждане" + "Входни езици" + "Плъзнете пръст по клавиша за интервал за промяна на езика" + "← Докоснете отново, за да запазите" + "Има достъп до речник" + "Активиране на отзивите от потребителите" + "Помогнете за подобряването на този редактор за въвеждане чрез автоматично изпращане до Google на статистически данни за употребата и сигнали за сривове." + "Докоснете, за да поправите думите" + "Докоснете въведените думи, за да ги поправите" + "Тема на клавиатурата" + "клавиатура" + "гласово" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ca/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ca/strings.xml new file mode 100644 index 00000000..f551d7b8 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ca/strings.xml @@ -0,0 +1,140 @@ + + + + + "Teclat Android" + "Configuració del teclat d\'Android" + "Opcions d\'entrada" + "Vibra en prémer tecles" + "So en prémer una tecla" + "Finestra emergent en prémer un botó" + "Corregeix els errors ortogràfics" + "Activa la correcció d\'errors d\'entrada" + "Errors d\'entrada en horitzontal" + "Activa la correcció d\'errors d\'entrada" + "Suggeriments de paraules" + "Corregeix automàticament la paraula anterior" + "Suggeriments de paraules" + "Configuració de suggeriment de paraules" + "Activa l\'emplenament automàtic mentre s\'escriu" + "Emplenament automàtic" + "Augmenta la mida del camp de text" + "Amaga els suggeriments de paraules en visualització horitzontal" + "Majúscules automàtiques" + "Posa l\'inici d\'una frase en majúscula" + "Puntuació automàtica" + + "Correccions ràpides" + "Corregeix els errors d\'ortografia habituals" + "Mostra els suggeriments" + "Visualitza paraules suggerides mentre s\'escriu" + "Emplenament automàtic" + "La barra espaiadora i la puntuació insereixen automàticament la paraula ressaltada" + "Mostra la tecla de configuració" + "Automàtic" + "Mostra sempre" + "Amaga sempre" + + + + "Suggeriments Bigram" + "Utilitza la paraula anterior per millorar el suggeriment" + + "Cap" + "Bàsic" + "Avançat" + + "%s: desada" + "Manteniu una tecla premuda per veure\'n les variants (ø, ö, etc.)" + "Premeu la tecla Enrere ↶ per tancar el teclat en qualsevol moment" + "Accedeix a números i símbols" + "Manteniu premuda la paraula de l\'extrem esquerre per afegir-la al diccionari" + "Toqueu aquest suggeriment per continuar »" + "Toqueu aquí per tancar aquest suggeriment i començar a escriure." + "S\'obre el teclat cada vegada que toqueu un camp de text" + "Manteniu premuda una tecla per veure\'n les variants"\n"(ø, ö, ô, ó, etc.)" + "Toqueu aquesta tecla per canviar als números i als símbols" + "Torneu a tocar aquesta tecla per tornar a les lletres" + "Manteniu premuda aquesta tecla per canviar la configuració del teclat, com ara l\'emplenament automàtic" + "Proveu-ho!" + "Vés" + "Següent" + "Fet" + "Envia" + "?123" + "123" + "ABC" + "ALT" + "Entrada de veu" + "Actualment, l\'entrada de veu no és compatible amb el vostre idioma, però funciona en anglès." + "L\'entrada de veu és una funció experimental que utilitza el reconeixement de la parla en xarxa de Google." + "Per desactivar l\'entada de veu, aneu a la configuració del teclat." + "Per utilitzar l\'entrada de veu, premeu el botó del micròfon o feu lliscar el dit pel teclat en pantalla." + "Parleu ara" + "S\'està treballant" + + "Error. Torneu-ho a provar." + "No s\'ha pogut connectar" + "Error; s\'ha parlat massa." + "Problema d\'àudio" + "Error del servidor" + "No s\'escolten paraules" + "No hi ha resultats" + "Cerca per veu no instal·lada" + "Consell:"" Feu lliscar el dit pel teclat per parlar" + "Suggeriment:"" La propera vegada, proveu de dir la puntuació, com ara \"punt\", \"coma\" o \"interrogant\"." + "Cancel·la" + "D\'acord" + "Entrada de veu" + + "Al teclat principal" + "Al teclat de símbols" + "Desactivat" + + + "Micròfon al teclat principal" + "Micròfon al teclat de símbols" + "L\'entrada de veu està desactivada" + + "Enviament automàtic després de la veu" + "Prem automàticament Retorn en cercar o en anar al camp següent." + "Obrir el teclat"\n\n"Toqueu qualsevol camp de text." + "Tancar el teclat"\n\n"Premeu la tecla Enrere." + "Manteniu premuda una tecla per veure les opcions"\n\n"Accediu a la puntuació i als accents." + "Configuració del teclat"\n\n"Manteniu premuda la tecla ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Selecciona el mètode d\'entrada" + "Idiomes d\'entrada" + "Feu lliscar el dit a la barra espaiadora per canviar l\'idioma" + "← Torna a tocar per desar" + "Diccionari disponible" + "Activa els comentaris de l\'usuari" + "Ajuda a millorar aquest editor de mètodes d\'entrada enviant automàticament estadístiques d\'ús i informes de bloqueigs a Google." + "Toca per corregir paraules" + "Toca les paraules introduïdes per corregir-les" + "Tema del teclat" + "teclat" + "veu" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-cs/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-cs/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-cs/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-cs/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-cs/donottranslate-altchars.xml new file mode 100644 index 00000000..d91a0e44 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-cs/donottranslate-altchars.xml @@ -0,0 +1,34 @@ + + + + áàâãäåæ + 3éěèêë + íìîï8 + óòôõöœø9 + ůúùûü7 + š§ß + ňñ + čç + ýÿ6 + ď + ř4 + ť5 + ž + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-cs/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-cs/strings.xml new file mode 100644 index 00000000..3bbd758d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-cs/strings.xml @@ -0,0 +1,140 @@ + + + + + "Klávesnice Android" + "Nastavení klávesnice Android" + "Možnosti zadávání textu a dat" + "Při stisku klávesy vibrovat" + "Zvuk při stisku klávesy" + "Zobrazit znaky při stisku klávesy" + "Opravovat překlepy" + "Povolit opravu chyb vstupu" + "Chyby vstupu v zobrazení na šířku" + "Povolit opravu chyb vstupu" + "Návrhy slov" + "Automaticky opravit předchozí slovo" + "Návrhy slov" + "Nastavení návrhů slov" + "Povolit automatické dokončování při psaní" + "Automatické dokončování" + "Zvětšit textové pole" + "Skrýt návrhy slov v zobrazení na šířku" + "Velká písmena automaticky" + "Zahájit větu velkým písmenem" + "Automatická interpunkce" + + "Rychlé opravy" + "Opravuje nejčastější chyby při psaní" + "Zobrazit návrhy" + "Zobrazovat navržená slova během psaní" + "Automatické dokončování" + "Stisknutím mezerníku nebo interpunkčního znaménka automaticky vložíte zvýrazněné slovo." + "Zobrazit klávesu Nastavení" + "Automaticky" + "Vždy zobrazovat" + "Vždy skrývat" + + + + "Návrh Bigram" + "Použít předchozí slovo ke zlepšení návrhu" + + "Žádný" + "Základní" + "Pokročilé" + + "%s: Uloženo" + "Podržením klávesy zobrazíte diakritiku (á, ž apod.)" + "Stisknutím klávesy Zpět ↶ můžete klávesnici kdykoli zavřít." + "Přístup k číslům a symbolům" + "Stisknutím a podržením slova zcela vlevo toto slovo přidáte do slovníku." + "Chcete-li pokračovat, dotkněte se tohoto tipu »" + "Chcete-li tento tip zavřít a začít psát, dotkněte se zde." + "Klávesnice se otevře vždy, když se dotknete textového pole." + "Přidržením klávesy zobrazíte diakritiku"\n"(ó, ø, ö, ô apod.)" + "Chcete-li přepnout na režim zadávání číslic a symbolů, dotkněte se této klávesy." + "Chcete-li přejít zpět k zadávání písmen, dotkněte se této klávesy znovu." + "Přidržením této klávesy změníte nastavení klávesnice (např. automatické dokončování)." + "Vyzkoušejte si to." + "Přejít" + "Další" + "Hotovo" + "Odeslat" + "?123" + "123" + "ABC" + "Alt" + "Hlasový vstup" + "Pro váš jazyk aktuálně není hlasový vstup podporován, ale funguje v angličtině." + "Hlasový vstup je experimentální funkce, která využívá síťové rozpoznávání řeči společnosti Google." + "Chcete-li vypnout hlasový vstup, přejděte do nastavení klávesnice." + "Chcete-li použít hlasový vstup, stiskněte tlačítko mikrofonu nebo přejeďte prstem přes klávesnici na obrazovce." + "Mluvte" + "Probíhá zpracování" + + "Chyba. Zkuste to prosím znovu." + "Připojení se nezdařilo." + "Chyba, řeč je příliš dlouhá." + "Problém se zvukem" + "Chyba serveru" + "Nebyla detekována žádná řeč." + "Nebyly nalezeny žádné shody" + "Hlasové vyhledávání není nainstalováno" + "Nápověda:"" Chcete-li aktivovat hlasový vstup, přejeďte prstem přes klávesnici." + "Nápověda:"" Příště zkuste vyslovit interpunkci, například „tečka“, „čárka“ nebo „otazník“." + "Zrušit" + "OK" + "Hlasový vstup" + + "Na hlavní klávesnici" + "Na klávesnici se symboly" + "Vypnout" + + + "Mikrofon na hlavní klávesnici" + "Mikrofon na klávesnici se symboly" + "Hlasový vstup je deaktivován" + + "Po hlasovém vstupu automaticky odeslat" + "Při vyhledávání nebo přechodu na další pole automaticky stisknout Enter." + "Otevřete klávesnici"\n\n"Dotkněte se libovolného textového pole." + "Zavřete klávesnici"\n\n"Stiskněte tlačítko Zpět." + "Přidržením klávesy zobrazte možnosti"\n\n"Přístup k interpunkčním znaménkům a diakritice." + "Nastavení klávesnice"\n\n"Dotkněte se klávesy ""?123"" a přidržte ji." + ".com" + ".cz" + ".org" + ".net" + ".eu" + "Výběr metody zadávání dat" + "Vstupní jazyky" + "Jazyk můžete změnit posunutím prstu po mezerníku." + "← Dalším dotykem slovo uložíte" + "K dispozici je slovník" + "Aktivovat zasílání statistik užívání a zpráv o selhání" + "Automatickým zasíláním statistik o užívání editoru zadávání dat a zpráv o jeho selhání do Googlu můžete přispět k vylepšení tohoto nástroje." + "Dotykem aktivovat opravy" + "Opravy napsaných slov dotykem" + "Motiv klávesnice" + "klávesnice" + "hlas" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-da/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-da/donottranslate-altchars.xml new file mode 100644 index 00000000..b1cc8b62 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-da/donottranslate-altchars.xml @@ -0,0 +1,38 @@ + + + + áàâąã + 3éèêëę€ + íìîï8 + óòôõ9 + úùûū7 + śšşß + ńñň + çćč + ýÿü6 + ðď + ř4 + ťþ5 + źžż + ł + w + ä + öœ + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-da/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-da/strings.xml new file mode 100644 index 00000000..f1fe6ecc --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-da/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android-tastatur" + "Indstillinger for Android-tastatur" + "Indstillinger for input" + "Vibration ved tastetryk" + "Lyd ved tastetryk" + "Popup ved tastetryk" + "Ret stavefejl" + "Aktiver fejlretning af input" + "Inputfejl i landskab" + "Aktiver fejlretning af input" + "Ordforslag" + "Ret automatisk det forrige ord" + "Ordforslag" + "Indstillinger for ordforslag" + "Aktiver automatisk udfyldelse, når du indtaster" + "Automatisk udfyldelse" + "Forøg tekstfeltets størrelse" + "Skjul ordforslag i landskabsvisning" + "Skriv aut. med stort" + "Første bogstav i en sætning skrives med stort" + "Foretag automatisk tegnsætning" + + "Hurtige løsninger" + "Retter almindelige stavefejl" + "Vis forslag" + "Vis ordforslag under indtastning" + "Udfyld automatisk" + "Mellemrumstast og tegnsætning indsætter automatisk fremhævet ord" + "Vis indstillingsnøgle" + "Automatisk" + "Vis altid" + "Skjul altid" + + + + "Bigram-forslag" + "Brug forrige ord for at forbedre forslag" + + "Ingen" + "Grundlæggende" + "Avanceret" + + "%s: Gemt" + "Hold en tast nede for at se accenter (ø, ö osv.)" + "Tryk på knappen Tilbage ↶ for når som helst at lukke for tastaturet" + "Få adgang til tal og symboler" + "Tryk og hold på ordet længst til venstre for at føje det til ordbogen" + "Berør dette tip for at fortsætte »" + "Berør her for at lukke dette tip og begynde at indtaste!" + "Tastaturet åbner når som helst, du berører et tekstfelt" + "Tryk på en tast, og hold den nede for a vise accenter"\n"(ø, ö, ô, ó osv.)" + "Skift til tal og symboler ved at røre denne tast" + "Gå tilbage til bogstaver ved at berøre denne tast igen" + "Tryk på denne tast, og hold den nede for at ændre tastaturindstillingerne, som f.eks. automatisk udfyldelse" + "Prøv det!" + "Gå" + "Næste" + "Udfør" + "Send" + "?123" + "123" + "ABC" + "ALT" + "Stemmeinput" + "Stemmeinput understøttes i øjeblikket ikke for dit sprog, men fungerer på engelsk." + "Stemme-input er en funktion på forsøgsbasis, som bruger Googles netværksstemmegenkendelse." + "Slå stemmeinput fra i indstillingerne for tastaturet." + "For at bruge stemme-input skal du trykke på knappen mikrofon eller lade glide fingeren hen over skærmtastaturet." + "Tal nu" + "Arbejder" + + "Fejl. Prøv igen." + "Kunne ikke oprette forbindelse" + "Fejl. For meget tale." + "Lydproblem" + "Serverfejl" + "Der høres ingen tale" + "Der blev ikke fundet nogen matches" + "Stemmesøgning er ikke installeret" + "Tip:"" Glid hen over tastaturet for at tale" + "Tip:"" Næste gang kan du forsøge at sige tegnsætning, f.eks. \"punktum\", \"komma\" eller \"spørgsmålstegn\"." + "Annuller" + "OK" + "Stemmeinput" + + "På hovedtastatur" + "På symboltastatur" + "Fra" + + + "Mikrofon på hovedtastatur" + "Mikrofon på symboltastatur" + "Stemmeinput er deaktiveret" + + "Send automatisk efter stemme" + "Tryk automatisk på enter, når du søger eller går til det næste felt." + "Åbn tastaturet"\n\n"Tryk på et hvilket som helst tekstfelt." + "Luk tastaturet"\n\n"Tryk på knappen Tilbage." + "Tryk på en tast, og hold den nede for valgmuligheder"\n\n"Få adgang til tegnsætning og accenter." + "Tastaturindstillinger"\n\n"Tryk på tasten ""?123"", og hold den nede." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Vælg inputmetode" + "Inputsprog" + "Træk fingeren på mellemrumstasten for at skifte sprog" + "← Tryk igen for at gemme" + "Ordbog er tilgængelig" + "Aktiver brugerfeedback" + "Vær med til at forbedre denne inputmetode ved at sende anvendelsesstatistikker og rapporter om nedbrud til Google." + "Tryk for at rette ord" + "Tryk på de indtastede ord for at rette dem" + "Tastaturtema" + "tastatur" + "stemme" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-de/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-de/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-de/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-de/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-de/donottranslate-altchars.xml new file mode 100644 index 00000000..df27bce2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-de/donottranslate-altchars.xml @@ -0,0 +1,31 @@ + + + + ä + 3èéêë + ìíîï8 + ö9 + ùúûü7 + §ß + ñ + ç + ýÿ + 6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-de/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-de/strings.xml new file mode 100644 index 00000000..e474bd73 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-de/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android-Tastatur" + "Android-Tastatureinstellungen" + "Eingabeoptionen" + "Vibrieren b. Tastendruck" + "Ton bei Tastendruck" + "Pop-up bei Tastendruck" + "Eingabefehler korrigieren" + "Korrektur von Eingabefehlern aktivieren" + "Eingabefehler im Querformat" + "Korrektur von Eingabefehlern aktivieren" + "Wortvorschläge" + "Vorheriges Wort automatisch korrigieren" + "Wortvorschläge" + "Einstellungen für Wortvorschläge" + "Automatische Vervollständigung während der Eingabe aktivieren" + "Autom. vervollständigen" + "Textfeld vergrößern" + "Wortvorschläge in Querformat ausblenden" + "Autom. Groß-/Kleinschr." + "Sätze mit Großbuchstaben beginnen" + "Autom. Zeichensetzung" + + "Quick Fixes" + "Korrigiert gängige Tippfehler" + "Vorschläge anzeigen" + "Vorgeschlagene Wörter während des Tippens anzeigen" + "Autom. vervollständigen" + "Leertaste und Interpunktion fügen autom. ein markiertes Wort ein" + "Einstellungstaste anz." + "Automatisch" + "Immer anzeigen" + "Immer ausblenden" + + + + "Bigramm-Vorschläge" + "Zur Verbesserung des Vorschlags vorheriges Wort verwenden" + + "Kein" + "Standard" + "Erweitert" + + "%s: gespeichert" + "Zur Anzeige von Umlauten (ä, ö usw.) Taste gedrückt halten" + "Zum Schließen der Tastatur ↶ drücken" + "Auf Zahlen und Symbole zugreifen" + "Lange auf das Wort ganz links außen drücken, um es zum Wörterbuch hinzuzufügen" + "Diesen Hinweis berühren, um fortzufahren »" + "Hier berühren, um diesen Hinweis zu schließen und mit dem Tippen zu beginnen!" + "Die Tastatur wird immer dann geöffnet, wenn Sie ein Textfeld berühren." + "Halten Sie eine Taste gedrückt, um Akzente anzuzeigen"\n"(ø, ö, ô, ó usw.)." + "Wechseln Sie zu Ziffern und Symbolen, indem Sie diese Taste berühren." + "Durch erneutes Drücken dieser Taste gelangen Sie zurück zu den Buchstaben." + "Halten Sie diese Taste gedrückt, um die Tastatureinstellungen, wie beispielsweise die automatische Vervollständigung, zu ändern." + "Probieren Sie es aus!" + "Los" + "Weiter" + "Fertig" + "Senden" + "?123" + "123" + "ABC" + "ALT" + "Spracheingabe" + "Spracheingaben werden derzeit nicht für Ihre Sprache unterstützt, funktionieren jedoch in Englisch." + "Die Spracheingabe ist eine Funktion im Versuchsstadium, die die vernetzte Spracherkennung von Google verwendet." + "Wenn Sie die Spracheingabe deaktivieren möchten, rufen Sie die Tastatureinstellungen auf." + "Um die Spracheingabe zu verwenden, drücken Sie die Mikrofontaste oder ziehen Sie Ihren Finger über die Bildschirmtastatur." + "Jetzt sprechen" + "Vorgang läuft" + + "Fehler. Versuchen Sie es erneut.." + "Keine Verbindung" + "Fehler – Text zu lang" + "Audio-Problem" + "Serverfehler" + "Keine Sprache zu hören" + "Keine Treffer gefunden" + "Sprachsuche nicht installiert" + "Hinweis:"" Ziehen Sie zum Sprechen den Finger über die Tastatur." + "Hinweis:"" Versuchen Sie beim nächsten Mal, Satzzeichen wie \"Punkt\", \"Komma\" oder \"Fragezeichen\" per Sprachbefehl einzugeben." + "Abbrechen" + "OK" + "Spracheingabe" + + "Auf Haupttastatur" + "Auf Symboltastatur" + "Aus" + + + "Mikrofon auf Haupttastatur" + "Mikrofon auf Symboltastatur" + "Spracheingabe ist deaktiviert" + + "Nach Sprachaufnahme automatisch senden" + "Drücken Sie auf die Eingabetaste, wenn Sie einen Suchvorgang durchführen oder zum nächsten Feld wechseln." + "Tastatur öffnen"\n\n"Berühren Sie ein beliebiges Textfeld." + "Tastatur schließen"\n\n"Drücken Sie die Zurücktaste." + "Für Optionen eine Taste berühren und gedrückt halten"\n\n"Greifen Sie auf Satzzeichen und Akzente zu." + "Tastatureinstellungen"\n\n"Berühren und halten Sie die Taste ""?123"" gedrückt." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Eingabemethode auswählen" + "Eingabesprachen" + "Finger über die Leertaste bewegen, um die Eingabesprache zu wechseln" + "← Zum Speichern erneut berühren" + "Wörterbuch verfügbar" + "Nutzer-Feedback aktivieren" + "Tragen Sie zur Verbesserung dieses Eingabemethodeneditors bei, indem Sie automatisch Nutzungsstatistiken und Absturzberichte an Google senden." + "Wortkorrektur" + "Zum Korrigieren auf eingegebene Wörter tippen" + "Tastaturdesign" + "Tastatur" + "Sprache" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-el/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-el/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-el/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-el/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-el/strings.xml new file mode 100644 index 00000000..5e5c583b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-el/strings.xml @@ -0,0 +1,140 @@ + + + + + "Πληκτρολόγιο Android" + "Ρυθμίσεις πληκτρολογίου Android" + "Επιλογές εισόδου" + "Δόνηση κατά το πάτημα πλήκτρων" + "Ήχος κατά το πάτημα πλήκτρων" + "Εμφάνιση με το πάτημα πλήκτρου" + "Διόρθωση σφαλμάτων πληκτρολόγησης" + "Ενεργοποίηση διόρθωσης σφαλμάτων εισόδου" + "Σφάλματα οριζόντιας εισαγωγής" + "Ενεργοποίηση διόρθωσης σφαλμάτων εισόδου" + "Υποδείξεις λέξεων" + "Αυτόματη διόρθωση της προηγούμενης λέξης" + "Υποδείξεις λέξεων" + "Ρυθμίσεις υποδείξεων λέξεων" + "Ενεργοποίηση αυτόματης συμπλήρωσης κατά την πληκτρολόγηση" + "Αυτόματη συμπλήρωση" + "Αυξήστε το μέγεθος του πεδίου κειμένου" + "Απόκρυψη υποδείξεων λέξεων στην οριζόντια προβολή" + "Αυτόματη χρήση κεφαλαίων" + "Κεφαλαίο το πρώτο γράμμα της πρότασης" + "Αυτόματος τονισμός" + + "Γρήγορες διορθώσεις" + "Διορθώνει συνηθισμένα λάθη πληκτρολόγησης" + "Εμφάνιση υποδείξεων" + "Προβολή προτεινόμενων λέξεων κατά την πληκτρολόγηση" + "Αυτόματη συμπλήρωση" + "Τα πλήκ.διαστήμ.και τονισμού εισάγ.αυτόμ.την επιλ.λέξη" + "Εμφάνιση πλήκτρου ρυθμίσεων" + "Αυτόματο" + "Να εμφανίζεται πάντα" + "Πάντα απόκρυψη" + + + + "Προτάσεις bigram" + "Χρήση προηγούμενης λέξης για τη βελτίωση πρότασης" + + "Καμία" + "Βασική" + "Σύνθετη" + + "%s : Αποθηκεύτηκε" + "Κρατήστε πατημένο ένα πλήκτρο για να δείτε τους τονισμένους χαρακτήρες (ø, ö, κ.τ.λ.)" + "Πατήστε το πλήκτρο Πίσω ↶ για να κλείσετε το πληκτρολόγιο ανά πάσα στιγμή" + "Πρόσβαση σε αριθμούς και σύμβολα" + "Κρατήστε πατημένη τη λέξη στην άκρη αριστερά, για να την προσθέσετε στο λεξικό" + "Αγγίξτε αυτή τη συμβουλή για να συνεχίσετε »" + "Αγγίξτε εδώ για να κλείσετε τη συμβουλή και να ξεκινήσετε την πληκτρολόγηση!" + "Το πληκτρολόγιο ανοίγει κάθε φορά που αγγίζετε ένα πεδίο κειμένου" + "Αγγίξτε και κρατήστε κάποιο πλήκτρο για να προβάλετε τους τονισμένους χαρακτήρες"\n"(ø, ö, ô, ó κ.τ.λ.)" + "Αλλαγή σε αριθμούς και σύμβολα με το πάτημα αυτού του πλήκτρου" + "Επιστρέψτε στα γράμματα αγγίζοντας ξανά αυτό το πλήκτρο" + "Αγγίξτε και κρατήστε πατημένο αυτό το πληκτρολόγιο για να αλλάξετε τις ρυθμίσεις πληκτρολογίου, όπως η αυτόματη συμπλήρωση" + "Δοκιμάστε το!" + "Μετ." + "Επόμενο" + "Τέλος" + "Αποστολή" + "?123" + "123" + "ΑΒΓ" + "ALT" + "Φωνητική είσοδος" + "Η φωνητική είσοδος δεν υποστηρίζεται αυτή τη στιγμή για τη γλώσσα σας, ωστόσο λειτουργεί στα Αγγλικά." + "Οι φωνητικές εντολές είναι μια πειραματική λειτουργία, η οποία χρησιμοποιεί τη δικτυακή αναγνώριση ομιλίας της Google." + "Για να απενεργοποιήσετε τη φωνητική είσοδο, μεταβείτε στις ρυθμίσεις πληκτρολογίου." + "Για να χρησιμοποιήσετε τις φωνητικές εντολές, πιέστε το κουμπί μικροφώνου ή σύρετε το δάχτυλό σας κατά μήκος του πληκτρολογίου της οθόνης." + "Μιλήστε τώρα" + "Σε λειτουργία" + + "Σφάλμα. Δοκιμάστε ξανά." + "Δεν ήταν δυνατή η σύνδεση" + "Σφάλμα, πολλές λέξεις." + "Πρόβλημα ήχου" + "Σφάλμα διακομιστή" + "Δεν ακούγεται ομιλία" + "Δεν βρέθηκε καμία αντιστοίχιση" + "Η Φωνητική αναζήτηση δεν εγκαταστάθηκε" + "Υπόδειξη:"" Σύρετε κατά μήκος του πληκτρολογίου για να μιλήσετε" + "Υπόδειξη:"" Την επόμενη φορά, προσπαθήστε να προφέρετε σημεία στίξης, όπως \"τελεία\", \"κόμμα\" ή \"ερωτηματικό\"." + "Ακύρωση" + "ΟΚ" + "Φωνητική είσοδος" + + "Στο κύριο πληκτρολόγιο" + "Πληκτρολόγιο συμβόλων ενεργοποίησης" + "Απενεργοποίηση" + + + "Μικρόφωνο στο κύριο πληκτρολόγιο" + "Μικρόφωνο στο πληκτρολόγιο συμβόλων" + "Η φωνητική είσοδος είναι απενεργοποιημένη" + + "Αυτόματη υποβολή μετά από ήχο" + "Πατήστε enter αυτόματα κατά την αναζήτηση ή τη μετάβαση στο επόμενο πεδίο." + "Ανοίξτε το πληκτρολόγιο"\n\n"Αγγίξτε οποιοδήποτε πεδίο κειμένου." + "Κλείστε το πληκτρολόγιο"\n\n"Πατήστε το πλήκτρο Πίσω." + "Αγγίξτε και κρατήστε ένα πλήκτρο για ορισμό επιλογών"\n\n"Πρόσβαση στα σημεία στίξης και τονισμού." + "Ρυθμίσεις πληκτρολογίου"\n\n"Αγγίξτε και κρατήστε το πλήκτρο ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Επιλογή μεθόδου εισόδου" + "Γλώσσες εισόδου" + "Σύρετε το δάχτυλο στο πλήκτρο διαστήματος για να αλλάξετε γλώσσα" + "← Αγγίξτε ξανά για αποθήκευση" + "Λεξικό διαθέσιμο" + "Ενεργοποίηση σχολίων χρηστών" + "Βοηθήστε μας να βελτιώσουμε αυτό το πρόγραμμα επεξεργασίας μεθόδου εισόδου στέλνοντας αυτόματα στατιστικά στοιχεία και αναφορές σφαλμάτων στην Google." + "Αγγίξτε για διόρθωση λέξεων" + "Αγγίξτε τις λέξεις που εισάγετε για να τις διορθώσετε" + "Θέμα πληκτρολογίου" + "πληκτρολόγιο" + "φωνητική" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-en-rGB/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-en-rGB/strings.xml new file mode 100644 index 00000000..56d666a3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-en-rGB/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android keyboard" + "Android keyboard settings" + "Input options" + "Vibrate on key-press" + "Sound on key-press" + "Pop-up on key press" + "Correct typing errors" + "Enable input error correction" + "Landscape input errors" + "Enable input error correction" + "Word suggestions" + "Automatically correct the previous word" + "Word suggestions" + "Word suggestion settings" + "Enable auto-completion while typing" + "Auto-completion" + "Increase text field size" + "Hide word suggestions in landscape view" + "Auto-capitalisation" + "Capitalise the start of a sentence" + "Auto-punctuate" + + "Quick fixes" + "Corrects commonly typed mistakes" + "Show suggestions" + "Display suggested words while typing" + "Auto-complete" + "Spacebar and punctuation automatically insert highlighted word" + "Show settings key" + "Automatic" + "Always show" + "Always hide" + + + + "Bigram Suggestions" + "Use previous word to improve suggestion" + + "None" + "Basic" + "Advanced" + + "%s : Saved" + "Hold a key down to see accents (ø, ö, etc.)" + "Press the back key ↶ to close the keyboard at any point" + "Access numbers and symbols" + "press and hold the left-most word to add it to the dictionary" + "Touch this hint to continue »" + "Touch here to close this hint and start typing!" + "The keyboard opens any time you touch a text field" + "Touch & hold a key to view accents"\n"(ø, ö, ô, ó and so on)" + "Switch to numbers and symbols by touching this key" + "Go back to letters by touching this key again" + "Touch & hold this key to change keyboard settings, like auto-complete" + "Try it!" + "Go" + "Next" + "Done" + "Send" + "?123" + "123" + "ABC" + "ALT" + "Voice input" + "Voice input is not currently supported for your language, but does work in English." + "Voice input is an experimental feature using Google\'s networked speech recognition." + "To turn off voice input, go to keyboard settings." + "To use voice input, press the microphone button or slide your finger across the on-screen keyboard." + "Speak now" + "Working" + + "Error: Please try again." + "Couldn\'t connect" + "Error, too much speech." + "Audio problem" + "Server error" + "No speech heard" + "No matches found" + "Voice search not installed" + "Hint:"" Swipe across keyboard to speak" + "Hint:"" Next time, try speaking punctuation marks, like \"full stop\", \"comma\" or \"question mark\"." + "Cancel" + "OK" + "Voice input" + + "On main keyboard" + "On symbols keyboard" + "Off" + + + "Mic on main keyboard" + "Mic on symbols keyboard" + "Voice input is disabled" + + "Auto-submit after voice" + "Automatically press enter when searching or going to the next field." + "Open the keyboard"\n\n"Touch any text field." + "Close the keyboard"\n\n"Press the Back key." + "Touch & hold a key for options"\n\n"Access punctuation and accents." + "Keyboard settings"\n\n"Touch & hold the ""?123"" key." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Select input method" + "Input languages" + "Slide finger on spacebar to change language" + "← Touch again to save" + "Dictionary available" + "Enable user feedback" + "Help improve this input method editor by sending usage statistics and crash reports automatically to Google." + "Touch to correct words" + "Touch words entered to correct them" + "Keyboard Theme" + "keyboard" + "voice" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-en/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-en/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-en/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-en/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-en/donottranslate-altchars.xml new file mode 100644 index 00000000..083befa1 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-en/donottranslate-altchars.xml @@ -0,0 +1,27 @@ + + + + àáâãäåāæ + 3èéêëē + ìíîïī8 + òóôõöōœø9 + ùúûüū7 + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-es-rUS/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-es-rUS/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-es-rUS/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-es-rUS/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-es-rUS/strings.xml new file mode 100644 index 00000000..0cd8a50a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-es-rUS/strings.xml @@ -0,0 +1,140 @@ + + + + + "Teclado de Android" + "Configuración de teclado de Android" + "Opciones de entrada" + "Vibrar al pulsar teclas" + "Sonar al pulsar las teclas" + "Aviso emergente al pulsar tecla" + "Corregir errores de escritura" + "Habilitar corrección de error de entrada" + "Errores de entrada apaisada" + "Habilitar corrección de error de entrada" + "Sugerencias de palabras" + "Corregir automáticamente la palabra anterior" + "Sugerencias de palabras" + "Configuración de sugerencia de palabra" + "Habilitar finalización automática al escribir" + "Finalización automática" + "Aumentar el tamaño del campo de texto" + "Ocultar sugerencias de palabras en vista apaisada" + "Mayúsculas automáticas" + "Poner en mayúscula el inicio de una oración" + "Puntuación automática" + + "Arreglos rápidos" + "Corrige errores de escritura comunes" + "Mostrar sugerencias" + "Mostrar palabras sugeridas mientras escribe" + "Completar automát." + "La barra espaciadora o la puntuación insertan automáticamente la palabra resaltada." + "Mostrar tecla de configuración" + "Automático" + "Mostrar siempre" + "Ocultar siempre" + + + + "Sugerencias de Vigoran" + "Utiliza la palabra anterior para mejorar la sugerencia" + + "Ninguno" + "Básico" + "Avanzado" + + "%s: guardada" + "Mantén una tecla presionada para ver los acentos (ø, ö, etc.)" + "Pulsa la tecla hacia atrás ↶ para cerrar el teclado en cualquier momento" + "Acceder a números y símbolos" + "Presiona y mantén presionada la palabra de la izquierda para agregarla al diccionario" + "Toca esta sugerencia para continuar »" + "Toca aquí para cerrar esta sugerencia y comenzar a escribir." + "El teclado se abre cada vez que tocas un campo de texto." + "Toca y mantén presionada una tecla para ver los acentos"\n"(ø, ö, ô, ó, y así sucesivamente)." + "Cambia de números a símbolos tocando esta tecla." + "Vuelve a letras tocando esta tecla nuevamente." + "Toca y mantén presionada esta tecla para cambiar la configuración del teclado, como completar automáticamente." + "¡Pruébalo!" + "Ir" + "Siguiente" + "Hecho" + "Enviar" + "?123" + "123" + "ABC" + "ALT" + "Entrada por voz" + "La entrada por voz no está admitida en tu idioma, pero sí funciona en inglés." + "La entrada por voz es una característica experimental que utiliza la red de reconocimiento de voz de Google." + "Para desactivar la entrada por voz, ve a configuración del teclado." + "Para realizar entrada por voz, presiona el botón del micrófono o desliza tus dedos por el teclado en pantalla." + "Habla ahora" + "Procesando" + + "Error. Vuelve a intentarlo." + "No se pudo establecer la conexión." + "Error, demasiado discurso." + "Problema de audio" + "Error del servidor" + "No se oyó la voz" + "No se encontraron coincidencias" + "Búsqueda por voz no instalada" + "Sugerencia:"" Deslizar en el teclado para hablar" + "Sugerencia:"" La próxima vez intenta decir la puntuación como \"punto\", \"coma\" o \"signo de pregunta\"." + "Cancelar" + "Aceptar" + "Entrada por voz" + + "En el teclado principal" + "En el teclado de símbolos" + "Apagado" + + + "Micrófono en el teclado principal" + "Micrófono en el teclado de símbolos" + "La entrada por voz está inhabilitada." + + "Enviar automáticamente después del audio" + "Presionar automáticamente Ingresar al buscar o ir al campo siguiente." + "Abrir el teclado"\n\n"Tocar cualquier campo de texto." + "Cerrar el teclado"\n\n"Presionar la tecla Atrás." + "Tocar & y mantener presionada una tecla para las opciones"\n\n"Acceder a puntuación y acentos." + "Configuración del teclado"\n\n"Tocar & y mantener presionada la tecla ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Seleccionar método de entrada" + "Idiomas de entrada" + "Deslizarse manualmente por la barra espaciadora para cambiar el idioma" + "← Tocar de nuevo para guardar" + "Diccionario disponible" + "Habilitar los comentarios del usuario" + "Ayuda a mejorar este editor de método de introducción de texto al enviar las estadísticas de uso y los informes de error a Google." + "Tocar para corregir palabras" + "Toca las palabras ingresadas que desees corregir" + "Tema del teclado" + "Teclado" + "Voz" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-es/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-es/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-es/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-es/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-es/donottranslate-altchars.xml new file mode 100644 index 00000000..721062d2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-es/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + á + + ìíîï8 + ó9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-es/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-es/strings.xml new file mode 100644 index 00000000..6e5963fb --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-es/strings.xml @@ -0,0 +1,140 @@ + + + + + "Teclado de Android" + "Ajustes del teclado de Android" + "Opciones introducción texto" + "Vibrar al pulsar tecla" + "Sonido al pulsar tecla" + "Popup al pulsar tecla" + "Corregir errores de escritura" + "Habilitar la introducción de corrección de errores" + "Errores de introducción de datos en vista horizontal" + "Habilitar la introducción de corrección de errores" + "Sugerencias de palabras" + "Corregir automáticamente la palabra anterior" + "Sugerencias de palabras" + "Ajustes de sugerencia de palabras" + "Habilitar Autocompletar al escribir" + "Autocompletar" + "Aumentar el tamaño del campo de texto" + "Ocultar sugerencias de palabras en la vista horizontal" + "Mayúsculas automáticas" + "Escribir en mayúscula el principio de la frase" + "Puntuación automática" + + "Correcciones rápidas" + "Corrige los errores tipográficos que se cometen con más frecuencia." + "Mostrar sugerencias" + "Muestra las palabras sugeridas mientras se escribe." + "Autocompletar" + "La barra espaciadora y los signos de puntuación insertan automáticamente la palabra resaltada." + "Mostrar tecla de ajustes" + "Automáticamente" + "Mostrar siempre" + "Ocultar siempre" + + + + "Sugerencias de bigramas" + "Usar palabra anterior para mejorar sugerencias" + + "Ninguno" + "Básico" + "Avanzado" + + "%s: guardada" + "Mantén pulsada una tecla para ver los caracteres acentuados (ø, ö, etc.)." + "Pulsa la tecla \"Atrás\" ↶ para cerrar el teclado en cualquier momento." + "Acceso a números y símbolos" + "Mantén pulsada la palabra situada más a la izquierda para añadirla al diccionario." + "Toca esta sugerencia para continuar »" + "Toca aquí para cerrar la sugerencia y comenzar a escribir." + "El teclado se abre cada vez que tocas un campo de texto""." + "Mantén pulsada una tecla para ver los caracteres acentuados"\n"(ø, ö, ô, ó, etc.)." + "Cambiar a números y a símbolos tocando esta tecla" + "Volver a las letras tocando esta tecla de nuevo" + "Mantén pulsada esta tecla para cambiar la configuración de teclado a, por ejemplo, autocompletar""." + "¡Pruébalo!" + "Ir" + "Sig." + "Listo" + "Enviar" + "?123" + "123" + "ABC" + "ALT" + "Introducción de voz" + "Actualmente la introducción de voz no está disponible en tu idioma, pero se puede utilizar en inglés." + "La introducción de voz es una función en fase experimental que utiliza la tecnología de reconocimiento de voz en red de Google." + "Para desactivar la función de introducción de voz, accede a la configuración del teclado." + "Para utilizar la función de introducción de voz, pulsa el botón de micrófono o desliza el dedo por el teclado en pantalla." + "Habla ahora" + "En curso" + + "Se ha producido un error. Inténtalo de nuevo." + "No se ha podido establecer conexión." + "Se ha producido un error debido a un exceso de introducción de datos de voz." + "Problema de audio" + "Error del servidor" + "Ninguna conversación escuchada" + "No se ha encontrado ninguna coincidencia." + "La búsqueda por voz no está instalada." + "Sugerencia:"" muévete por el teclado para hablar." + "Sugerencia:"" la próxima vez, prueba a indicar signos de puntuación como, por ejemplo, \"punto\", \"coma\" o \"signo de interrogación\"." + "Cancelar" + "Aceptar" + "Introducción de voz" + + "En teclado principal" + "En teclado de símbolos" + "Desactivado" + + + "Micrófono en teclado principal" + "Micrófono en teclado de símbolos" + "La función de introducción de voz no está habilitada." + + "Enviar automáticamente después de la introducción de voz" + "Pulsar Intro automáticamente al buscar o al pasar al siguiente campo" + "Abrir el teclado"\n\n"Toca cualquier campo de texto." + "Cerrar el teclado"\n\n"Pulsa la tecla \"Atrás\"." + "Mantén pulsada una tecla para acceder a las opciones."\n\n"Accede a los signos de puntuación y a los acentos." + "Ajustes del teclado"\n\n"Mantén pulsada la tecla ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Seleccionar método de introducción de texto" + "Idiomas" + "Deslizar el dedo por la barra espaciadora para cambiar el idioma" + "← Volver a tocar para guardar" + "Hay un diccionario disponible." + "Habilitar comentarios de usuarios" + "Ayuda a mejorar este editor de método de introducción de texto enviando estadísticas de uso e informes de error a Google." + "Tocar para corregir palabras" + "Tocar palabras introducidas para corregirlas" + "Tema de teclado" + "teclado" + "voz" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fa/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fa/strings.xml new file mode 100644 index 00000000..cc4391a0 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fa/strings.xml @@ -0,0 +1,140 @@ + + + + + "صفحه کلید Android" + "تنظیمات صفحه کلید Android" + "گزینه های ورودی" + "لرزش با فشار کلید" + "صدا با فشار کلید" + "بازشو با فشار کلید" + "تصحیح خطاهای تایپی" + "فعال کردن تصحیح خطای ورودی" + "خطاهای ورود افقی" + "فعال کردن تصحیح خطای ورودی" + "پیشنهادات کلمه" + "تصحیح خودکار کلمه قبلی" + "پیشنهادات کلمه" + "تنظیمات پیشنهاد کلمه" + "فعال کردن تکمیل خودکار در حین تایپ" + "تکمیل خودکار" + "افزایش اندازه قسمت متنی" + "پنهان کردن پیشنهادات کلمه در نمای افقی" + "نوشتن با حروف بزرگ خودکار" + "بزرگ کردن اول هر جمله" + "نشان گذاری خودکار" + + "راه حل های سریع" + "تصحیح خطاهای تایپی رایج" + "نمایش پیشنهادات" + "نمایش واژه های پیشنهادی در حین تایپ" + "تکمیل خودکار" + "کلید خط فاصله و علائم نگارشی به صورت خودکار کلمه برجسته شده را وارد می کنند." + "نمایش کلید تنظیمات" + "خودکار" + "همیشه نمایش" + "همیشه پنهان" + + + + "توضیحات بیگرام" + "برای بهبود پیشنهاد از کلمه قبلی استفاده شود" + + "هیچکدام" + "پایه" + "پیشرفته" + + "%s : ذخیره شد" + "برای مشاهده علائم تکیه (ø، ö و موارد دیگر) کلیدی را پایین نگه دارید" + "برای بستن صفحه کلید در هر نقطه که بخواهید، کلید برگشت ↶ را فشار دهید" + "دسترسی به اعداد و نمادها" + "انتهای سمت چپ واژه را برای افزودن آن به فرهنگ لغت فشار داده و نگه دارید" + "این نکته را برای ادامه لمس کنید »" + "برای بستن این نکته و شروع تایپ، اینجا را لمس کنید!" + "هر زمان که قسمت متنی را لمس می کنید، صفحه کلید باز می شود" + "یک کلید را برای مشاهده تکیه های صدا لمس کرده و نگه دارید (ø، ö، ô، ó و موارد دیگر)"\n + "تغییر شماره ها و نمادها با لمس این کلید" + "با لمس مجدد این کلید، به حروف برگردید" + "این کلید را برای تغییر تنظیمات صفحه کلید مانند تکمیل خودکار لمس کرده و فشار دهید" + "امتحان کنید!" + "برو" + "بعدی" + "انجام شد" + "ارسال" + "?123" + "123" + "ABC" + "ALT" + "ورودی صوتی" + "ورودی صوتی در حال حاضر برای زبان شما پشتیبانی نمی شود اما برای زبان انگلیسی فعال است." + "ورودی صوتی یک ویژگی آزمایشی با استفاده از تشخیص گفتار شبکه Google است." + "برای خاموش کردن ورودی صدا، به تنظیمات صفحه کلید بروید." + "برای استفاده از ورودی صوتی، دکمه میکروفن را فشار دهید یا انگشت خود را روی صفحه کلید روی صفحه حرکت دهید." + "اکنون صحبت کنید" + "در حال کار" + + "خطا: لطفاً دوباره امتحان کنید." + "متصل نشد" + "خطا، گفتار بسیار زیاد است." + "مشکل صوتی" + "خطای سرور" + "گفتاری شنیده نشد" + "مورد منطبقی یافت نشد" + "جستجوی صوتی نصب نشده است" + "نکته: "" برای صحبت روی صفحه کلید ضربه بزنید" + "نکته: دفعه دیگر، از نشانه گذاری های گفتاری مانند \"نقطه\"، \"کاما\" یا \"علامت سؤال\" استفاده کنید." + "لغو" + "تأیید" + "ورودی صوتی" + + "در صفحه کلید اصلی" + "در صفحه کلید نمادها" + "خاموش" + + + "میکروفن در صفحه کلید اصلی" + "میکروفن در صفحه کلید نمادها" + "ورودی صوتی غیر فعال شده است" + + "ارائه خودکار بعد از صدا" + "هنگام جستجو یا رفتن به قسمت بعدی، Enter را به صورت خودکار فشار دهید." + "صفحه کلید را باز کنید"\n\n"هر قسمت متنی را لمس کنید." + "بستن صفحه کلید"\n\n"کلید برگشت را فشار دهید." + "یک کلید را برای گزینه های"\n\n" دسترسی به علائم نگارشی و تکیه های صدا لمس کرده و نگه دارید." + "تنظیمات صفحه کلید"\n\n"کلید ""?123"" را لمس کرده و نگهدارید." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "انتخاب روش ورودی" + "زبان های ورودی" + "برای تغییر زبان انگشت را روی کلید فاصله بلغزانید" + "← جهت ذخیره دوباره لمس کنید" + "دیکشنری موجود است" + "فعال کردن بازخورد کاربر" + "با ارسال خودکار آمارهای کاربرد و گزارش های خرابی به Google، به بهبود این ویرایشگر روش ورودی کمک کنید." + "برای تصحیح کلمات لمس کنید" + "برای تصحیح کلمات وارد شده آنها را لمس کنید" + "طرح زمینه صفحه کلید" + "صفحه کلید" + "صوتی" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fi/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fi/strings.xml new file mode 100644 index 00000000..3c36a632 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fi/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android-näppäimistö" + "Android-näppäimistön asetukset" + "Syöttövalinnat" + "Käytä värinää näppäimiä painettaessa" + "Toista ääni näppäimiä painettaessa" + "Ponnahdusikkuna painalluksella" + "Korjaa kirjoitusvirheet" + "Ota syöttövirheen korjaus käyttöön" + "Vaakasuunnan syöttövirheet" + "Ota syöttövirheen korjaus käyttöön" + "Sanaehdotukset" + "Korjaa edellinen sana automaattisesti" + "Sanaehdotukset" + "Sanaehdotusasetukset" + "Ota automaattinen täydennys käyttöön kirjoitettaessa" + "Automaattinen täydennys" + "Suurenna tekstikenttää" + "Piilota sanaehdotukset vaakasuuntaisessa näkymässä" + "Automaattiset isot kirjaimet" + "Aloittaa lauseet isolla kirjaimella" + "Automaattiset välimerkit" + + "Pikakorjaukset" + "Korjaa yleiset kirjoitusvirheet" + "Näytä ehdotukset" + "Näytä sanaehdotukset kirjoitettaessa" + "Automaattinen täydennys" + "Välilyönti ja välimerkki lisäävät automaattisesti korostetun sanan" + "Näytä asetukset-näppäin" + "Automaattinen" + "Näytä aina" + "Piilota aina" + + + + "Bigram-ehdotukset" + "Paranna ehdotusta aiemman sanan avulla" + + "Ei mitään" + "Tavallinen" + "Edistynyt" + + "%s : Tallennettu" + "Näet aksenttimerkit (ø, ö jne.) pitämällä näppäintä painettuna." + "Voit sulkea näppäimistön milloin tahansa painamalla Takaisin-painiketta ↶" + "Käytä numeroita ja symboleita" + "Lisää vasemmanpuoleinen sana sanakirjaan pitämällä sitä painettuna" + "Jatka koskettamalla tätä vihjettä »" + "Sulje tämä vihje ja aloita kirjoittaa koskettamalla tätä!" + "Näppäimistö avautuu, kun kosketat tekstikenttää" + "Näytä aksenttimerkit pitämällä näppäintä painettuna"\n"(ø, ö, ô, ó ja niin edelleen" + "Vaihda numeroihin ja symboleihin koskettamalla tätä näppäintä" + "Siirry takaisin kirjaimiin koskettamalla tätä näppäintä uudelleen" + "Muuta näppäimistön asetuksia, kuten automaattista täydentämistä, pitämällä tätä näppäintä painettuna" + "Kokeile!" + "Siirry" + "Seuraava" + "Valmis" + "Lähetä" + "?123" + "123" + "ABC" + "ALT" + "Äänisyöte" + "Äänisyötettä ei vielä tueta kielelläsi, mutta voit käyttää sitä englanniksi." + "Äänisyöte on kokeellinen Googlen puheentunnistusta käyttävä ominaisuus." + "Siirry näppäimistön asetuksiin poistaaksesi äänisyötteen käytöstä." + "Käytä äänisyötettä painamalla mikrofonipainiketta tai liu\'uttamalla sormeasi näytön näppäimistön poikki." + "Puhu nyt" + "Työstetään" + + "Virhe. Yritä uudelleen." + "Ei yhteyttä" + "Virhe, liikaa puhetta." + "Ääniongelma" + "Palvelinvirhe" + "Puhetta ei kuulu" + "Ei vastineita" + "Äänihakua ei asennettu" + "Vihje:"" liu\'uta sormea näppäimistöllä ja puhu" + "Vihje:"" kokeile seuraavalla kerralla puhua välimerkit, kuten \"period\" (piste), \"comma\" (pilkku) tai \"question mark\" (kysymysmerkki)." + "Peruuta" + "OK" + "Äänisyöte" + + "Päänäppäimistössä" + "Symbolinäppäimistössä" + "Pois käytöstä" + + + "Päänäppäimistön mikrofoni" + "Symbolinäppäimistön mikrofoni" + "Äänisyöte ei ole käytössä" + + "Lähetä automaattisesti puheen jälkeen" + "Paina automaattisesti enter-näppäintä tehdessäsi hakuja tai siirtyessäsi seuraavaan kenttään." + "Avaa näppäimistö"\n\n"Kosketa tekstikenttää." + "Sulje näppäimistö"\n\n"Paina Takaisin-näppäintä." + "Näet asetukset pitämällä näppäintä painettuna"\n\n"Käytä välimerkkejä ja aksenttimerkkejä." + "Näppäimistön asetukset"\n\n"Pidä painettuna""?123""-näppäintä." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Valitse syöttötapa" + "Syöttökielet" + "Vaihda kieltä liu\'uttamalla sormea välilyöntinäppäimellä" + "← Tallenna koskettamalla uudelleen" + "Sanakirja saatavilla" + "Ota käyttäjäpalaute käyttöön" + "Auta parantamaan tätä syöttötavan muokkausohjelmaa lähettämällä automaattisesti käyttötietoja ja kaatumisraportteja Googlelle." + "Korjaa sanoja koskettamalla" + "Korjaa sanoja koskettamalla niitä" + "Näppäimistön teema" + "näppäimistö" + "ääni" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fr-rCA/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fr-rCA/strings.xml new file mode 100644 index 00000000..b56463ed --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fr-rCA/strings.xml @@ -0,0 +1,19 @@ + + + + "Clavier Android" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fr/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fr/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fr/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fr/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fr/donottranslate-altchars.xml new file mode 100644 index 00000000..874d89da --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fr/donottranslate-altchars.xml @@ -0,0 +1,33 @@ + + + + 1àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + + + 2 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fr/donottranslate.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fr/donottranslate.xml new file mode 100644 index 00000000..b79df7b3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fr/donottranslate.xml @@ -0,0 +1,25 @@ + + + + + .\u0009\u0020,;:!?\'\n()[]*&@{}/<>_+=|\u0022 + + ., + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-fr/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-fr/strings.xml new file mode 100644 index 00000000..06ba1eae --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-fr/strings.xml @@ -0,0 +1,140 @@ + + + + + "Clavier Android" + "Paramètres du clavier Android" + "Options de saisie" + "Vibrer à chaque touche" + "Son à chaque touche" + "Agrandir les caractères" + "Corriger les fautes de frappe" + "Activer la correction des erreurs de saisie" + "Erreurs de saisie en mode paysage" + "Activer la correction des erreurs de saisie" + "Saisie prédictive" + "Corriger automatiquement le mot précédent" + "Saisie prédictive" + "Paramètres de la saisie prédictive" + "Activer la saisie semi-automatique" + "Saisie semi-automatique" + "Agrandir le champ de texte" + "Masquer la saisie prédictive en mode paysage" + "Majuscules auto" + "Mettre en majuscule la première lettre de chaque phrase" + "Ponctuation automatique" + + "Corrections rapides" + "Corrige les fautes de frappe courantes" + "Afficher les suggestions" + "Afficher les suggestions de terme lors de la saisie" + "Saisie semi-automatique" + "Insérer autom. terme surligné (pression sur barre espace/ponctuation)" + "Afficher touche param." + "Automatique" + "Toujours afficher" + "Toujours masquer" + + + + "Suggestions de type bigramme" + "Améliorer la suggestion en fonction du mot précédent" + + "Aucun" + "Simple" + "Avancé" + + "%s : enregistré" + "Maintenir une touche enfoncée pour afficher les accents (à, é, etc.)" + "Appuyez sur la touche Retour ↶ pour fermer le clavier à tout moment." + "Accéder aux chiffres et symboles" + "Appuyer et maintenir le doigt sur le mot le plus à gauche pour l\'ajouter au dictionnaire" + "Touchez ce conseil pour continuer »" + "Touchez ici pour fermer ce conseil et commencer à saisir votre texte." + "Le clavier s\'affiche à chaque fois que vous touchez une zone de texte." + "Maintenez une touche enfoncée pour afficher les accents"\n"(ø, ö, ô, ó, etc.)""." + "Appuyez sur cette touche pour basculer vers les chiffres et les symboles." + "Appuyez de nouveau sur cette touche pour retourner aux lettres." + "Maintenez cette touche enfoncée afin de modifier les paramètres du clavier, tels que la saisie semi-automatique." + "Essayez !" + "OK" + "Suivant" + "OK" + "Envoyer" + "?123" + "123" + "ABC" + "ALT" + "Saisie vocale" + "La saisie vocale n\'est pas encore prise en charge pour votre langue, mais elle fonctionne en anglais." + "La saisie vocale est une fonctionnalité expérimentale qui fait appel à la reconnaissance vocale en réseau de Google." + "Pour désactiver la saisie vocale, accédez aux paramètres du clavier." + "Pour utiliser la saisie vocale, appuyez sur la touche du microphone ou faites glisser votre doigt sur le clavier à l\'écran." + "Parlez maintenant" + "Traitement en cours" + + "Erreur. Veuillez réessayer." + "Connexion impossible" + "Erreur, discours trop long." + "Problème audio" + "Erreur serveur" + "Aucune requête vocale détectée" + "Aucune correspondance n\'a été trouvée." + "Recherche vocale non installée" + "Astuce :"" Faites glisser votre doigt sur le clavier pour parler." + "Astuce :"" La prochaine fois, essayez de prononcer la ponctuation, en énonçant des termes tels que \"point\", \"virgule\" ou \"point d\'interrogation\"." + "Annuler" + "OK" + "Saisie vocale" + + "Sur le clavier principal" + "Sur le clavier des symboles" + "Désactivée" + + + "Micro sur le clavier principal" + "Micro sur le clavier des symboles" + "Saisie vocale désactivée" + + "Envoi automatique après la saisie vocale" + "Appuyez automatiquement sur Entrée pour effectuer une recherche ou accéder au champ suivant." + "Ouvrir le clavier"\n\n"Appuyez sur un champ de texte." + "Fermer le clavier"\n\n"Appuyez sur la touche Retour." + "Appuyez sur une touche de manière prolongée pour accéder aux options"\n\n"Accédez aux signes de ponctuation et aux accents." + "Paramètres du clavier"\n\n"Appuyez sur la touche ""?123"" de manière prolongée." + ".com" + ".net" + ".org" + ".gouv" + ".edu" + "Sélectionner un mode de saisie." + "Langues de saisie" + "Faites glisser votre doigt sur la barre d\'espacement pour changer la langue." + "← Appuyer de nouveau pour enregistrer" + "Dictionnaire disponible" + "Autoriser les commentaires des utilisateurs" + "Contribuer à l\'amélioration de cet éditeur du mode de saisie grâce à l\'envoi automatique de statistiques d\'utilisation et de rapports d\'incident à Google." + "Appuyer pour corriger" + "Appuyer sur les mots saisis pour les corriger" + "Thème du clavier" + "clavier" + "voix" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-hr/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-hr/strings.xml new file mode 100644 index 00000000..a97c9536 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-hr/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android tipkovnica" + "Postavke tipkovnice za Android" + "Opcije ulaza" + "Vibracija pri pritisku na tipku" + "Zvuk pri pritisku tipke" + "Povećanja na pritisak tipke" + "Ispravi pogreške u pisanju" + "Omogućavanje ispravka pogreške pri unosu" + "Pogreške pri pejzažnom unosu" + "Omogućavanje ispravka pogreške pri unosu" + "Prijedlozi riječi" + "Automatsko ispravljanje prethodne riječi" + "Prijedlozi riječi" + "Postavke prijedloga riječi" + "Omogućavanje automatskog dovršavanja pri upisivanju" + "Automatsko dovršavanje" + "Povećaj tekstualno polje" + "Sakrij prijedloge riječi u pejzažnom prikazu" + "Automatsko pisanje velikih slova" + "Stavi veliko slovo na početku rečenice" + "Automatsko stavljanje interpunkcije" + + "Brzi popravci" + "Ispravlja uobičajene pogreške u pisanju" + "Pokaži prijedloge" + "Prikazivanje predloženih riječi prilikom upisivanja" + "Automatsko dovršavanje" + "Razmaknica i interpunkcija automatski umeću istaknutu riječ" + "Prikaži tipku postavki" + "Automatski" + "Uvijek prikaži" + "Uvijek sakrij" + + + + "Bigram prijedlozi" + "Upotrijebi prethodnu riječ radi poboljšanja prijedloga" + + "Nijedan" + "Osnovni" + "Napredno" + + "%s : Spremljeno" + "Pritisnite i držite tipku da biste vidjeli naglaske (ø, ö itd.)" + "Pritisnite tipku \"Natrag\" ↶ za zatvaranje tipkovnice" + "Pristup brojevima i simbolima" + "Pritisnite i držite krajnju lijevu riječ da biste je dodali u rječnik." + "Dodirnite ovaj savjet za nastavak »" + "Dodirnite ovdje da biste zatvorili savjet i počeli upisivati!" + "Tipkovnica se otvara svaki put kada dodirnete tekstualno polje" + "Dodirnite i držite tipku da biste vidjeli naglaske"\n"(ø, ö, ô, ó i tako dalje)" + "Prijeđite na brojeve i simbole dodirom na ovu tipku" + "Dodirnite ponovo ovu tipku za povratak na slova" + "Dodirnite i držite ovu tipku da biste promijenili postavke tipkovnice, poput automatskog dovršavanja" + "Isprobajte!" + "Idi" + "Dalje" + "Gotovo" + "Pošalji" + "?123" + "123" + "ABC" + "ALT" + "Glasovni ulaz" + "Vaš jezik trenutno nije podržan za glasovni unos, ali radi za engleski." + "Glasovni unos je pokusna značajka koja koristi Googleovo umreženo prepoznavanje govora." + "Za isključivanje glasovnog unosa idite na postavke tipkovnice." + "Da biste koristili glasovni unos pritisnite gumb mikrofona ili kliznite prstom preko tipkovnice na zaslonu." + "Govorite sad" + "Obrada" + + "Pogreška. Pokušajte ponovo." + "Spajanje nije bilo moguće" + "Pogreška, predugi govor." + "Problem sa zvukom" + "Pogreška na poslužitelju" + "Nije se čuo govor" + "Nisu pronađeni rezultati" + "Glasovno pretraživanje nije instalirano" + "Savjet:"" Prijeđite preko tipkovnice pa govorite" + "Savjet:"" Sljedeći put pokušajte izgovoriti znakove interpunkcije poput \"točka, \"zarez\" ili \"upitnik\"." + "Odustani" + "U redu" + "Glasovni ulaz" + + "Na glavnoj tipkovnici" + "Na tipkovnici sa simbolima" + "Isključeno" + + + "Mikrofon na glavnoj tipkovnici" + "Mikrofon na tipkovnici sa simbolima" + "Glasovni unos je onemogućen" + + "Automatski pošalji nakon glasovnog unosa" + "Automatski se pritišće \"Enter\" kad pretražujete ili idete na sljedeće polje." + "Otvaranje tipkovnice"\n\n"Dodirnite bilo koje tekstualno polje" + "Zatvaranje tipkovnice"\n\n"Pritisnite tipku \"Natrag\"." + "Dodirnite i držite tipku da biste vidjeli opcije"\n\n"Pristup interpunkciji i naglascima." + "Postavke tipkovnice"\n\n"Dodirnite i držite tipku ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Odabir ulazne metode" + "Jezici unosa" + "Kliznite prstom po razmaknici za promjenu jezika" + "← Dodirnite opet za spremanje" + "Rječnik je dostupan" + "Omogući korisničke povratne informacije" + "Pomozite u poboljšanju ovog urednika ulazne metode automatskim slanjem statistike upotrebe i padova Googleu." + "Dodirnite za ispravak riječi" + "Dodirnite unesene riječi radi ispravka" + "Tema tipkovnice" + "tipkovnica" + "glas" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-hu/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-hu/strings.xml new file mode 100644 index 00000000..7c2f2164 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-hu/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android-billentyűzet" + "Android billentyűzetbeállítások" + "Beviteli beállítások" + "Rezgés billentyű megnyomása esetén" + "Hangjelzés billentyű megnyomása esetén" + "Legyen nagyobb billentyű lenyomásakor" + "Gépelési hibák kijavítása" + "Beviteli hibák javításának engedélyezése" + "Fekvő beviteli hibák" + "Beviteli hibák javításának engedélyezése" + "Szójavaslatok" + "Az előző szó automatikus kijavítása" + "Szójavaslatok" + "Szójavaslati beállítások" + "Automatikus kiegészítés engedélyezése gépelés közben" + "Automatikus kiegészítés" + "A szövegmező méretének növelése" + "Szójavaslatok elrejtése fekvő nézetben" + "Automatikusan nagy kezdőbetű" + "Nagybetűvel kezdi a mondatot" + "Automatikus központozás" + + "Gyorsjavítások" + "Kijavítja a gyakori gépelési hibákat" + "Javaslatok megjelenítése" + "A javasolt szavak megjelenítése gépelés közben" + "Automatikus kiegészítés" + "A szóköz és az írásjelek használata automatikusan beszúrja a kiemelt szót" + "Beállítások billentyű megjelenítése" + "Automatikus" + "Mindig látszik" + "Mindig rejtve" + + + + "Bigram javaslatok" + "Előző szó használata a javaslatok javításához" + + "Nincs" + "Alap" + "Speciális" + + "%s : mentve" + "Az ékezetes betűk megtekintéséhez tartsa lenyomva valamelyik billentyűt (ø, ö stb.)" + "A vissza gomb ↶ megnyomásával bármikor elrejtheti a billentyűzetet" + "Számok és szimbólumok elérése" + "A szótárhoz történő hozzáadásához nyomja meg hosszan a bal oldali legszélső szót" + "A folytatáshoz érintse meg ezt a tippet »" + "Érintse meg itt a tipp bezárásához és a gépelés megkezdéséhez." + "Szövegmező megérintésekor a billentyűzet mindig megjelenik" + "Érintse meg és tartsa lenyomva valamelyik billentyűt az ékezetes betűk megtekintéséhez"\n"(ø, ö, ô, ó stb.)" + "Számokra és szimbólumokra ennek a billentyűnek a megérintésével válthat" + "A billentyű újbóli megérintésével visszatérhet a betűkhöz" + "Érintse meg és tartsa lenyomva ezt a billentyűt a billentyűzet-beállítások (pl. az automatikus kiegészítés) módosításához" + "Próbálja ki!" + "Ugrás" + "Tovább" + "Kész" + "Küldés" + "?123" + "123" + "ABC" + "ALT" + "Hangbevitel" + "A hangbevitel szolgáltatás jelenleg nem támogatja az Ön nyelvét, ám angolul működik." + "A hangbevitel a Google hálózati beszédfelismerését alkalmazó kísérleti funkció." + "A hangbevitelt a billentyűzet beállításai között lehet kikapcsolni." + "A hangbevitel használatához nyomja meg a mikrofon gombját vagy húzza végig az ujját a képernyő-billentyűzeten." + "Most beszéljen" + "Feldolgozás" + + "Hiba történt. Kérjük, próbálja újra." + "Nem sikerült kapcsolódni" + "Hiba történt; túl sokat beszélt." + "Hangprobléma" + "Szerverhiba" + "Nem hallatszott beszéd" + "Nem található egyezés" + "A hangalapú keresés nincs telepítve" + "Tipp:"" húzza végig az ujját a billentyűzeten a beszédhez" + "Tipp:"" következő alkalommal próbálja ki az írásjelek kimondását is, pl. \"period\", \"comma\" vagy \"question mark\"." + "Mégse" + "OK" + "Hangbevitel" + + "Főbillentyűzeten" + "Szimbólumbillentyűzeten" + "Ki" + + + "Mikrofon a főbillentyűzeten" + "Mikrofon a szimbólumbillentyűzeten" + "A hangbevitel ki van kapcsolva" + + "Automatikus küldés a beszéd után" + "Az Enter automatikus megnyomása keresés vagy a következő mezőre ugrás során." + "A billentyűzet megjelenítése"\n\n"Érintse meg valamelyik szövegmezőt." + "A billentyűzet bezárása"\n\n"Nyomja meg a Vissza billentyűt." + "A lehetőségek megjelenítéséhez érintse meg és tartsa lenyomva valamelyik billentyűt"\n\n"Az írásjelek és az ékezetes betűk elérése." + "Billentyűzetbeállítások"\n\n"Érintse meg és tartsa lenyomva a ""?123"" billentyűt." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Beviteli mód kiválasztása" + "Beviteli nyelvek" + "A nyelv módosításához húzza végig az ujját a szóköz billentyűn" + "← Érintse meg újra a mentéshez" + "Van elérhető szótár" + "Felhasználói visszajelzés engedélyezése" + "Segíthet ennek a beviteli módszernek a javításában, ha engedélyezi a használati statisztikák és a hibajelentések elküldését a Google-nak." + "Javítás a szavak megérintésével" + "A beírt szavakat megérintve kijavíthatja őket" + "Billentyűzettéma" + "billentyűzet" + "hang" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-in/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-in/strings.xml new file mode 100644 index 00000000..73b57c7b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-in/strings.xml @@ -0,0 +1,140 @@ + + + + + "Keyboard Android" + "Setelan keyboard Android" + "Opsi masukan" + "Getar jika tombol ditekan" + "Berbunyi jika tombol ditekan" + "Muncul saat tombol ditekan" + "Perbaiki kesalahan ketik" + "Aktifkan perbaikan galat masukan" + "Galat masukan lanskap" + "Aktifkan perbaikan galat masukan" + "Saran kata" + "Perbaiki kata sebelumnya secara otomatis" + "Saran kata" + "Setelan saran kata" + "Aktifkan pengisian otomatis saat mengetik" + "Pengisian otomatis" + "Tambah ukuran bidang teks" + "Sembunyikan saran kata dalam tampilan melintang" + "Kapitalisasi otomatis" + "Kapitalisasi awal kalimat" + "Beri tanda baca otomatis" + + "Perbaikan cepat" + "Memperbaiki kesalahan ketik umum" + "Perlihatkan saran" + "Tampilkan kata yang disarankan ketika mengetik" + "Pengisian otomatis" + "Bilah spasi dan tanda baca secara otomatis memasukkan kata yang disorot" + "Lihat tombol setelan" + "Otomatis" + "Selalu tampilkan" + "Selalu sembunyikan" + + + + "Saran Bigram" + "Gunakan kata sebelumnya untuk meningkatkan sara" + + "Tak Satu Pun" + "Dasar" + "Lanjutan" + + "%s : Telah disimpan" + "Tahan tombol untuk melihat aksen (ø, ö, dll.)" + "Tekan tombol kembali ↶ untuk menutup keyboard kapan saja" + "Akses angka dan simbol" + "Tekan terus kata yang paling kiri untuk menambahkannya ke kamus" + "Sentuh petunjuk ini untuk melanjutkan »" + "Sentuh di sini untuk menutup petunjuk dan mulailah mengetik!" + "Keyboard terbuka setiap kali Anda menyentuh bidang teks" + "Sentuh & tahan tombol untuk melihat aksen"\n"(ø, ö, ô, ó, dan seterusnya)" + "Beralih ke angka dan simbol dengan menekan tombol ini" + "Kembali ke huruf dengan menekan tombol ini lagi" + "Sentuh & tahan tombol ini untuk mengubah setelan keyboard, seperti lengkapi otomatis" + "Cobalah!" + "Buka" + "Berikutnya" + "Selesai" + "Kirimkan" + "?123" + "123" + "ABC" + "ALT" + "Masukan suara" + "Masukan suara saat ini tidak didukung untuk bahasa Anda, tetapi bekerja dalam Bahasa Inggris." + "Masukan suara adalah fitur eksperimental yang menggunakan pengenal suara berjaringan Google." + "Untuk mematikan masukan suara, buka setelan keyboard." + "Untuk menggunakan masukan suara, tekan tombol mikrofon atau geser jari Anda di sepanjang keyboard pada layar." + "Ucapkan sekarang" + "Bekerja" + + "Galat: Coba lagi." + "Tidak dapat menyambung" + "Galat, terlalu banyak ucapan." + "Masalah audio" + "Galat server" + "Tidak terdengar ucapan" + "Tak ditemukan yang cocok" + "Penelusuran suara tidak terpasang" + "Petunjuk:"" Gesek keyboard untuk berbicara" + "Petunjuk:"" Selanjutnya, coba ucapkan tanda baca seperti \"titik\", \"koma\", atau \"tanda tanya\"." + "Batal" + "OK" + "Masukan suara" + + "Di keyboard utama" + "Di keyboard simbol" + "Mati" + + + "Mik di keyboard utama" + "Mik di keyboard simbol" + "Masukan suara dinonaktifkan" + + "Kirim otomatis setelah suara" + "Tekan enter secara otomatis saat menelusuri atau menuju ke bidang berikutnya." + "Buka keyboard"\n\n"Sentuh bidang teks mana pun." + "Tutup keyboard"\n\n"Tekan tombol Kembali." + "Sentuh & tahan tombol tertentu untuk opsi"\n\n"Akses tanda baca dan aksen." + "Setelan keyboard"\n\n"Sentuh & tahan tombol ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Pilih metode masukan" + "Bahasa masukan" + "Geser jari pada bilah spasi untuk mengubah bahasa" + "← Sentuh sekali lagi untuk menyimpan" + "Kamus yang tersedia" + "Aktifkan umpan balik pengguna" + "Bantu tingkatkan metode editor masukan dengan mengirim statistik penggunaan dan laporan kerusakan ke Google secara otomatis." + "Sentuh untuk memperbaiki kata" + "Sentuh kata yang dimasukkan untuk memperbaikinya" + "Tema Keyboard" + "keyboard" + "suara" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-it/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-it/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-it/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-it/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-it/donottranslate-altchars.xml new file mode 100644 index 00000000..23960171 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-it/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àá + 3èé + ìíîï8 + òó9 + ùúûü7 + § + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-it/donottranslate.xml b/src/java/KP2ASoftKeyboard2/java/res/values-it/donottranslate.xml new file mode 100644 index 00000000..3e3f3ef2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-it/donottranslate.xml @@ -0,0 +1,23 @@ + + + + + .\u0009\u0020,;:!?\'\n()[]*&@{}/<>_+=|\u0022 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-it/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-it/strings.xml new file mode 100644 index 00000000..3768dc23 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-it/strings.xml @@ -0,0 +1,140 @@ + + + + + "Tastiera Android" + "Impostazioni tastiera Android" + "Opzioni inserimento" + "Vibrazione tasti" + "Suono tasti" + "Popup sui tasti" + "Correggi errori di digitazione" + "Attiva la correzione degli errori di inserimento" + "Errori di inserimento in visualizzazione orizzontale" + "Attiva la correzione degli errori di inserimento" + "Suggerimenti parola" + "Correggi automaticamente la parola precedente" + "Suggerimenti parola" + "Impostazioni suggerimento parole" + "Attiva il completamento automatico durante la digitazione" + "Completamento automatico" + "Aumenta dimensioni campo di testo" + "Nascondi i suggerimenti delle parole in visualizzazione orizzontale" + "Maiuscole automatiche" + "Rendi maiuscole le iniziali delle frasi" + "Punteggiatura automat." + + "Correzioni veloci" + "Corregge gli errori di digitazione più comuni" + "Mostra suggerimenti" + "Visualizza le parole suggerite durante la digitazione" + "Completamento autom." + "Barra spaziatrice e punteggiatura inseriscono la parola evidenziata" + "Mostra tasto impostaz." + "Automatico" + "Mostra sempre" + "Nascondi sempre" + + + + "Suggerimenti sui bigrammi" + "Utilizza parola precedente per migliorare il suggerimento" + + "Nessuna" + "Base" + "Avanzate" + + "%s : parola salvata" + "Tieni premuto un tasto per vedere le lettere con segni diacritici (ø, ö etc.)" + "Premi il tasto Indietro ↶ per chiudere la tastiera" + "Accedi a numeri e simboli" + "Tieni premuto sulla parola all\'estrema sinistra per aggiungerla al dizionario" + "Tocca questo suggerimento per continuare »" + "Tocca qui per chiudere questo suggerimento e iniziare a digitare." + "La tastiera si apre ogni volta che tocchi un campo di testo" + "Tocca e tieni premuto un pulsante per visualizzare le lettere con segni diacritici"\n"(ø, ö, ô, ó e così via)" + "Passa a numeri e simboli toccando questo pulsante" + "Torna alle lettere toccando di nuovo questo pulsante" + "Tocca e tieni premuto questo pulsante per modificare le impostazioni della tastiera, come il completamento automatico" + "Prova!" + "Vai" + "Avanti" + "Fine" + "Invia" + "?123" + "123" + "ABC" + "ALT" + "Comandi vocali" + "I comandi vocali non sono attualmente supportati per la tua lingua ma funzionano in inglese." + "I comandi vocali sono una funzione sperimentale che utilizza il riconoscimento vocale in rete di Google." + "Per disattivare i comandi vocali, vai alle impostazioni della tastiera." + "Per utilizzare i comandi vocali, premi il pulsante del microfono o fai scorrere il dito sulla tastiera sullo schermo." + "Parla ora" + "Elaborazione in corso" + + "Errore. Riprova più tardi." + "Impossibile connettersi." + "Errore: conversazione troppo lunga." + "Problema audio" + "Errore del server" + "Nessuna frase vocale rilevata" + "Nessuna corrispondenza trovata" + "Ricerca vocale non installata" + "Suggerimento."" Fai scorrere il dito sulla tastiera per parlare" + "Suggerimento."" La prossima volta, prova a pronunciare termini relativi alla punteggiatura come \"punto\", \"virgola\" o \"punto di domanda\"." + "Annulla" + "OK" + "Comandi vocali" + + "Su tastiera principale" + "Su tastiera simboli" + "Non attivi" + + + "Microfono su tastiera principale" + "Microfono su tastiera simboli" + "Comandi vocali disabilitati" + + "Invia automaticamente dopo comando vocale" + "Premi automaticamente \"Invio\" durante una ricerca o un passaggio al campo successivo." + "Apertura tastiera"\n\n"Tocca qualsiasi campo di testo." + "Chiusura tastiera"\n\n"Premi il tasto Indietro." + "Tocca e tieni premuto un pulsante per le opzioni"\n\n"Accesso a punteggiatura e accenti." + "Impostazioni tastiera"\n\n"Tocca e tieni premuto il pulsante ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Seleziona metodo di inserimento" + "Lingue comandi" + "Scorri il dito sulla barra spaziatrice per cambiare la lingua" + "← Tocca di nuovo per salvare" + "Dizionario disponibile" + "Attiva commenti degli utenti" + "Aiuta a migliorare l\'editor del metodo di inserimento inviando automaticamente a Google statistiche sull\'utilizzo e segnalazioni sugli arresti anomali." + "Tocca per correggere" + "Tocca le parole inserite per correggerle" + "Tema della tastiera" + "tastiera" + "vocale" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-iw/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-iw/strings.xml new file mode 100644 index 00000000..abc5c397 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-iw/strings.xml @@ -0,0 +1,140 @@ + + + + + "מקלדת Android" + "הגדרות מקלדת של Android" + "אפשרויות קלט" + "רטט עם לחיצה על מקשים" + "צלילים עם לחיצה על מקשים" + "חלון קופץ עם לחיצה על מקשים" + "תקן שגיאות הקלדה" + "הפוך תיקון שגיאות קלט לפעיל" + "שגיאות קלט בפריסה לרוחב" + "הפוך תיקון שגיאות קלט לפעיל" + "הצעות למילים" + "תקן באופן אוטומטי את המילה הקודמת" + "הצעות למילים" + "הגדרות של הצעות מילים" + "הפוך השלמה אוטומטית לפעילה בעת הקלדה" + "השלמה אוטומטית" + "הגדל את הגודל של שדה הטקסט" + "הסתר הצעות למילים בתצוגה לרוחב" + "הפיכה אוטומטית של אותיות לרישיות" + "הוסף אות רישית בתחילת משפט" + "פיסוק אוטומטי" + + "תיקונים מהירים" + "מתקן שגיאות הקלדה נפוצות" + "הצג הצעות" + "הצג הצעות למילים בעת הקלדה" + "השלמה אוטומטית" + "הקשה על מקש הרווח וסימני הפיסוק תוסיף באופן אוטומטי את המילה המסומנת" + "הצג מקש הגדרות" + "אוטומטי" + "הצג תמיד" + "הסתר תמיד" + + + + "הצעות של צמדי אותיות (Bigram)" + "השתמש במילה הקודמת כדי לשפר את ההצעה" + + "ללא" + "בסיסי" + "מתקדם" + + "%s : נשמרה" + "החזק מקש לחוץ כדי לראות אקצנטים (ø, ö וכדומה)" + "לחץ על המקש \'הקודם\' ↶ כדי לסגור את המקלדת בכל עת" + "גישה למספרים וסמלים" + "לחץ על המילה השמאלית הקיצונית והחזק אותה לחוצה כדי להוסיף למילון" + "גע ברמז זה כדי להמשיך »" + "גע כאן כדי לסגור רמז זה ולהתחיל בהקלדה!" + "המקלדת נפתחת בכל פעם שאתה נוגע בשדה טקסט" + "גע במקש והחזק אותו לחוץ כדי להציג אקצנטים"\n"(ø, ö, ô, ó וכדומה)" + "עבור למספרים וסמלים על ידי נגיעה במקש זה" + "חזור לאותיות על ידי מגע במקש זה שוב" + "גע במקש זה והחזק אותו לחוץ כדי לשנות את הגדרות המקלדת, כגון השלמה אוטומטית" + "נסה אותו!" + "בצע" + "הבא" + "בוצע" + "שלח" + "?123" + "123" + "ABC" + "ALT" + "קלט קולי" + "קלט קולי אינו נתמך בשלב זה בשפתך, אך הוא פועל באנגלית." + "קלט קולי הוא תכונה ניסיונית של זיהוי הדיבור ברשת של Google." + "כדי לכבות את הקלט הקולי, עבור להגדרות מקלדת." + "כדי להשתמש בקלט הקולי, לחץ על לחצן המיקרופון או החלק את האצבע על המקלדת שבמסך." + "דבר כעת" + "פועל" + + "שגיאה. נסה שוב." + "אין אפשרות להתחבר" + "שגיאה, דיבור רב מדי." + "בעיה באודיו" + "שגיאת שרת" + "לא נשמע דיבור" + "לא נמצאו התאמות" + "חיפוש קולי לא מותקן" + "רמז:"" העבר על המקלדת כדי לדבר" + "רמז:"" בפעם הבאה, נסה לומר את סימני הפיסוק כגון \"נקודה\", \"פסיק\" או \"סימן שאלה\"." + "ביטול" + "אישור" + "קלט קולי" + + "במקלדת הראשית" + "מקלדת סמלים מופעלת" + "כבוי" + + + "מיקרופון במקלדת הראשית" + "מיקרופון במקלדת סמלים" + "הקלט הקולי מושבת" + + "שליחה אוטומטית לאחר הקלטת קול" + "הקש על Enter באופן אוטומטי בעת חיפוש או מעבר לשדה הבא." + "פתח את המקלדת"\n\n"גע בשדה טקסט כלשהו." + "סגור את המקלדת"\n\n"לחץ על הלחצן \'הקודם\'." + "גע במקש והחזק אותו לחוץ לקבלת אפשרויות"\n\n"קבל גישה לסימני פיסוק ואקצנטים." + "הגדרות מקלדת"\n\n"גע במקש ""?123"" והחזק אותו לחוץ." + "‎.com" + "‎.net" + "‎.org" + "‎.gov" + "‎.edu" + "בחר שיטת קלט" + "שפות קלט" + "החלק את האצבע על מקש הרווח כדי לשנות שפה" + "← גע שוב כדי לשמור" + "מילון זמין" + "הפוך משוב ממשתמשים לפעיל" + "עזור לשפר שיטת קלט זו על ידי שליחה אוטומטית של סטטיסטיקת שימוש ודוחות קריסת מחשב ל-Google." + "גע כדי לתקן מילים" + "גע במילים שהוזנו כדי לתקן אותן" + "עיצוב מקלדת" + "מקלדת" + "קולי" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ja/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ja/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ja/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ja/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ja/strings.xml new file mode 100644 index 00000000..f04790e8 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ja/strings.xml @@ -0,0 +1,140 @@ + + + + + "Androidキーボード" + "Androidキーボードの設定" + "入力オプション" + "キー操作バイブ" + "キー操作音" + "キー押下時ポップアップ" + "入力ミス補正" + "入力間違いを自動修正する" + "横表示での入力修正" + "入力間違いを自動修正する" + "入力候補表示" + "前の単語を自動修正する" + "入力候補表示" + "入力候補の設定" + "オートコンプリートを使用する" + "オートコンプリート" + "入力作業スペースを広げる" + "横表示では入力候補を表示しない" + "自動大文字変換" + "英字入力で文頭文字を大文字にする" + "句読点を自動入力" + + "クイックフィックス" + "よくある誤字・脱字を修正します" + "入力候補を表示" + "入力時に入力候補を表示する" + "オートコンプリート" + "誤入力をスペースまたは句読点キーで修正する" + "設定キーを表示" + "自動" + "常に表示" + "常に非表示" + + + + "バイグラム入力候補表示" + "直前の単語から入力候補を予測します" + + "なし" + "基本" + "高度" + + "%s:保存しました" + "キー長押しでアクセント文字を表示(ø、öなど)" + "戻るキーでキーボードを閉じます" + "数字と記号" + "一番左の単語を長押しすると辞書に追加されます" + "続けるにはここをタッチ" + "タッチしてこのヒントを終了し、入力を開始してください。" + "テキストフィールドを選択するとキーボードが表示されます" + "キーを長押しするとアクセント付き文字"\n"(ø、ö、ô、óなど)が表示されます" + "このキーを押すと、数字/記号入力に切り替わります" + "このキーを押すと、文字入力に再度切り替わります" + "オートコンプリートなどのキーボードの設定を変更するには、このキーを長押しします" + "試してみてください。" + "実行" + "次へ" + "完了" + "送信" + "?123" + "123" + "ABC" + "ALT" + "音声入力" + "音声入力は現在英語には対応していますが、日本語には対応していません。" + "音声入力はGoogleのネットワーク音声認識技術を利用した試験段階の機能です。" + "音声入力をOFFにするには、キーボードの設定を開きます。" + "音声入力するには、マイクボタンを押すか画面キーボードをスワイプしてください。" + "お話しください" + "処理中" + + "エラーです。もう一度お試しください。" + "接続できませんでした" + "音声が長すぎてエラーになりました。" + "オーディオエラー" + "サーバーエラー" + "音声が聞き取れません" + "該当なし" + "Voice Searchはインストールされていません" + "ヒント:"" 音声入力するにはキーボードをスワイプします" + "ヒント:"" 次回は句読点として「period」、「comma」、「question mark」などの音声入力を試してみてください。" + "キャンセル" + "OK" + "音声入力" + + "メインキーボード上" + "記号キーボード上" + "OFF" + + + "メインキーボードのマイク" + "記号キーボードのマイク" + "音声入力は無効です" + + "入力後に自動送信する" + "検索または次のフィールドに進む際、Enterキーが自動的に押されます。" + "キーボードを開く"\n\n"テキストフィールドをタップします。" + "キーボードを閉じる"\n\n"[戻る]キーを押します。" + "キーを長押しして選択する"\n\n"句読点キーとアクセント文字を表示します。" + "キーボードの設定"\n\n"[""?123""]キーを長押しします。" + ".com" + ".net" + ".org" + ".gov" + ".edu" + "入力方法の選択" + "入力言語" + "スペースバーで指をスライドさせて言語を変更する" + "←保存するにはもう一度タップ" + "辞書を利用できます" + "ユーザーフィードバックを有効にする" + "IMEの機能向上のため、使用統計状況やクラッシュレポートをGoogleに自動送信します。" + "タップして語句を修正" + "入力した語句をタップして修正" + "キーボードテーマ" + "キーボード" + "音声" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ko/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ko/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ko/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ko/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ko/strings.xml new file mode 100644 index 00000000..1f966cee --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ko/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android 키보드" + "Android 키보드 설정" + "입력 옵션" + "키를 누를 때 진동 발생" + "키를 누를 때 소리 발생" + "키를 누를 때 팝업" + "입력 오류 수정" + "입력 오류 수정 사용" + "가로 입력 오류" + "입력 오류 수정 사용" + "단어 추천" + "이전 단어를 자동으로 수정" + "단어 추천" + "단어 추천 설정" + "입력할 때 자동 완성 사용" + "자동 완성" + "입력란 크기 늘리기" + "가로 보기에서 추천 단어 숨기기" + "자동 대문자화" + "문장의 첫 글자를 대문자로 표시" + "자동 구두점 입력" + + "빠른 수정" + "자주 발생하는 오타를 수정합니다." + "추천 단어 표시" + "글자를 입력하는 동안 추천 단어를 표시" + "자동 완성" + "스페이스바와 문장부호 키로 강조 표시된 단어를 자동 삽입" + "설정 키 표시" + "자동" + "항상 표시" + "항상 숨기기" + + + + "Bigram 추천" + "이전 단어를 사용하여 추천 기능 개선" + + "없음" + "기본" + "고급" + + "%s: 저장됨" + "키를 길게 누르면 악센트(ø, ö 등)가 표시됩니다." + "키보드를 닫으려면 언제든지 뒤로 키(↶)를 누르세요." + "숫자 및 기호 사용" + "맨 왼쪽에 있는 단어를 길게 누르면 사전에 추가됩니다." + "계속하려면 힌트를 터치하세요. »" + "힌트를 닫고 입력을 시작하려면 여기를 터치하세요." + "언제든지 입력란을 터치하면 키보드가 열립니다." + "키를 길게 터치하면 악센트"\n"(ø, ö, ô, ó 등)가 표시됩니다." + "이 키를 터치하면 숫자 및 기호 키보드로 전환됩니다." + "이 키를 다시 터치하면 문자 키보드로 돌아갑니다." + "자동 완성과 같은 키보드 설정을 변경하려면 이 키를 길게 터치하세요." + "이제 사용해 보세요." + "이동" + "다음" + "완료" + "전송" + "?123" + "123" + "ABC" + "ALT" + "음성 입력" + "음성 입력은 현재 자국어로 지원되지 않으며 영어로 작동됩니다." + "음성 입력은 Google의 네트워크화된 음성 인식을 사용하는 실험적 기능입니다." + "음성 입력을 사용하지 않으려면 키보드 설정으로 이동하세요." + "음성 입력을 사용하려면 마이크 버튼을 누르거나 터치 키보드 위로 손가락을 미끄러지듯 움직이세요." + "지금 말하세요." + "인식 중" + + "오류가 발생했습니다. 다시 시도해 보세요." + "연결할 수 없습니다." + "음성을 너무 많이 입력했습니다." + "오디오 문제" + "서버 오류" + "음성이 인식되지 않았습니다." + "일치하는 항목 없음" + "음성 검색이 설치되지 않았습니다." + "도움말:"" 키보드 위로 손가락을 미끄러지듯 움직이고 나서 말하세요." + "도움말:"" 다음 번에는 \'마침표\', \'쉼표\', \'물음표\'와 같은 구두점을 말해 보세요." + "취소" + "확인" + "음성 입력" + + "기본 키보드" + "기호 키보드" + "사용 안함" + + + "기본 키보드의 마이크" + "기호 키보드의 마이크" + "음성 입력이 사용 중지됨" + + "음성을 입력한 다음 자동 제출" + "검색하거나 다음 입력란으로 이동할 때 자동으로 Enter 키를 누릅니다." + "키보드 열기"\n\n"아무 텍스트 입력란이나 터치하세요." + "키보드 닫기"\n\n"\'뒤로\' 키를 누르세요." + "키를 길게 눌러 옵션 보기"\n\n"문장 부호 및 악센트 기호 입력창이 열립니다." + "키보드 설정"\n\n"?123"" 키를 길게 누르세요." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "입력 방법 선택" + "입력 언어" + "손가락을 스페이스바에서 미끄러지듯 움직여 언어 변경" + "← 저장하려면 다시 터치하세요." + "사전 사용 가능" + "사용자 의견 사용" + "사용 통계 및 충돌 보고서를 Google에 자동으로 전송하여 입력 방법 편집기의 개선에 도움을 줍니다." + "터치하여 단어 수정" + "입력한 단어를 터치하여 수정" + "키보드 테마" + "키보드" + "음성" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-land/dimens.xml b/src/java/KP2ASoftKeyboard2/java/res/values-land/dimens.xml new file mode 100644 index 00000000..043f4b36 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-land/dimens.xml @@ -0,0 +1,35 @@ + + + + + + 0.250in + 0.020in + 0.270in + 0.0in + 38dip + 63dip + 2dip + + + 0.459in + + -0.270in + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-lt/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-lt/strings.xml new file mode 100644 index 00000000..3a806552 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-lt/strings.xml @@ -0,0 +1,140 @@ + + + + + "„Android“ klaviatūra" + "„Android“ klaviatūros nustatymai" + "Įvesties parinktys" + "Vibruoti, kai paspaudžiami klavišai" + "Klavišo paspaudimo garsas" + "Iššoka paspaudus klavišą" + "Taisyti rašybos klaidas" + "Įgalinti įvesties klaidos taisymą" + "Gulsčia įvestis" + "Įgalinti įvesties klaidos taisymą" + "Žodžių pasiūlymai" + "Automatiškai taisyti ankstesnį žodį" + "Žodžių pasiūlymai" + "Žodžių pasiūlymo nustatymai" + "Įgalinti automatinį užbaigimą, kai įvedinėjamas tekstas" + "Automatinis užbaigimas" + "Padidinti teksto lauko dydį" + "Gulsčiame rodinyje slėpti žodžių pasiūlymus" + "Automatinis didžiųjų raidžių rašymas" + "Sakinio pradžią rašyti didžiąja raide" + "Automatiškai dėti skyrybos ženklus" + + "Greiti pataisymai" + "Taiso dažnai padarytas rašybos klaidas" + "Rodyti pasiūlymus" + "Įvedant tekstą pateikti siūlomus žodžius" + "Automatiškai užbaigti" + "Tarpo klavišas ir skyrybos ženklai automatiškai įterpia paryškintą žodį" + "Rodyti nustatymų raktą" + "Automatinis" + "Visada rodyti" + "Visada slėpti" + + + + "Digramų pasiūlymai" + "Naudoti ankstesnį žodį pasiūlymui patobulinti" + + "Nėra" + "Paprastas" + "Išplėstinis" + + "%s: išsaugota" + "Laikykite klavišą nuspaudę, kad pamatytumėte kirčius (ø, ö ir t. t.)" + "Paspauskite klavišą „Atgal“ ↶, kad uždarytumėte klaviatūrą" + "Pasiekti skaičius ir simbolius" + "Paspauskite ir laikykite nuspaudę kairiausią žodį, kad pridėtumėte jį prie žodyno" + "Palieskite šią užuominą, jei norite tęsti »" + "Paleiskite čia, kad uždarytumėte šią užuominą ir pradėtumėte įvedinėti tekstą!" + "Klaviatūra atsidarys kaskart, kai paliesite teksto lauką" + "Palieskite ir laikykite klavišą, kad pamatytumėte kirčius"\n"(ø, ö, ô, ó, and so on)" + "Perjunkite į skaičius ir simbolius, paliesdami šį klavišą" + "Grįžkite prie raidžių dar kartą paliesdami šį klavišą" + "Palieskite ir laikykite šį klavišą, kad pakeistumėte klaviatūros nustatymus, pvz., automatinį užbaigimą" + "Išbandykite tai!" + "Pradėti" + "Kitas" + "Atlikta" + "Siųsti" + "?123" + "123" + "ABC" + "ALT" + "Balso įvestis" + "Šiuo metu balso įvestis jūsų kompiuteryje nepalaikoma, bet ji veikia anglų k." + "Balso įvestis – tai eksperimentinė funkcija, naudojanti „Google“ tinklo kalbos atpažinimą." + "Jei norite išjungti balso įvestį, eikite į klaviatūros nustatymus." + "Jei norite naudoti balso įvestį, paspauskite mikrofono mygtuką arba pirštu slyskite ekranine klaviatūra." + "Kalbėkite dabar" + "Veikia" + + "Klaida. Bandykite dar kartą." + "Nepavyko prijungti" + "Klaida, per daug kalbos." + "Problema su garsu" + "Serverio klaida" + "Negirdima jokia kalba" + "Atitikmenų nerasta" + "Balso paieška neįdiegta" + "Užuomina:"" perbraukite klaviatūra, kad galėtumėte kalbėti" + "Užuomina:"" kitą kartą pabandykite sakyti skyrybos ženklų pavadinimus, pvz., „taškas“, „kablelis“ arba „klaustukas“." + "Atšaukti" + "Gerai" + "Balso įvestis" + + "Pagrindinėje klaviatūroje" + "Simbolių klaviatūroje" + "Išjungta" + + + "Pagrindinės klaviatūros mikrofonas" + "Mikrofonas simbolių klaviatūroje" + "Balso įvestis išjungta" + + "Automatiškai pateikti po balso" + "Automatiškai spausti „Įvesti“ ieškant ar einant į kitą lauką." + "Atidarykite klaviatūrą"\n\n"Palieskite bet kurį teksto lauką." + "Uždarykite klaviatūrą"\n\n"Paspauskite klavišą „Atgal“." + "Palieskite ir laikykite klavišą, kad pamatytumėte parinktis"\n\n"Pasiekite skyrybos ženklus ir kirčius." + "Klaviatūros nustatymai"\n\n"Palieskite ir laikykite klavišą ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Pasirinkti įvesties metodą" + "Įvesties kalbos" + "Pirštu slyskite tarpo klavišu, kad pakeistumėte kalbą" + "← Kad išsaugotumėte, dar kartą palieskite" + "Žodynas galimas" + "Įgalinti naudotojų atsiliepimus" + "Padėkite patobulinti šią įvesties metodo redagavimo programą automatiškai „Google“ siųsdami naudojimo statistiką ir strigčių ataskaitas." + "Jei norite ištais. žodž., paliesk." + "Jei norite ištaisyti įvestus žodžius, palieskite juos" + "Klaviatūros tema" + "klaviatūra" + "Voice" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-lv/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-lv/strings.xml new file mode 100644 index 00000000..3c0be251 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-lv/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android tastatūra" + "Android tastatūras iestatījumi" + "Ievades opcijas" + "Vibrēt, nospiežot taustiņu" + "Skaņa, nospiežot taustiņu" + "Nospiežot taustiņu, parādīt uznirstošo izvēlni" + "Labot drukas kļūdas" + "Iespējot ievades kļūdu labošanu" + "Ainavas orientācijas ievades kļūdas" + "Iespējot ievades kļūdu labošanu" + "Vārdu ieteikumi" + "Automātiski labot iepriekšējo vārdu" + "Vārdu ieteikumi" + "Vārdu ieteikumu iestatījumi" + "Iespējot automātisko pabeigšanu ievades laikā" + "Automātiska pabeigšana" + "Palielināt teksta lauka lielumu" + "Ainavas skatījumā slēpt vārdu ieteikumus" + "Automātiska lielo burtu lietošana" + "Sākt teikumu ar lielo burtu" + "Automātiska pieturzīmju lietošana" + + "Ātrie labojumi" + "Nodrošina izplatītu drukas kļūdu labošanu." + "Rādīt ieteikumus" + "Ievades laikā attēlot ieteiktos vārdus" + "Automātiska pabeigšana" + "Automātiski ievietot iezīmēto vārdu, izmantojot atstarpes taustiņu un pieturzīmes" + "Rādīt iestatījumu taustiņu" + "Automātiski" + "Vienmēr rādīt" + "Vienmēr slēpt" + + + + "Bigram ieteikumi" + "Ieteikuma uzlabošanai izmantot iepriekšējo vārdu" + + "Nav" + "Pamata" + "Uzlabots" + + "%s: saglabāts" + "Turiet taustiņu nospiestu, lai skatītu uzsvēruma zīmes (ø, ö u.c.)." + "Jebkurā brīdī nospiediet taustiņu Atpakaļ ↶, lai aizvērtu tastatūru." + "Piekļūt cipariem un simboliem" + "Nospiediet kreisajā pusē esošo vārdu un turiet, lai pievienotu to vārdnīcai." + "Pieskarieties šim ieteikumam, lai turpinātu »" + "Pieskarieties šeit, lai aizvērtu šo ieteikumu un sāktu ievadi." + "Tastatūra tiek atvērta ikreiz, kad pieskaraties teksta laukam""." + "Pieskarieties taustiņam un turiet, lai skatītu uzsvara zīmes"\n"(ø, ö, ô, ó utt.)." + "Pieskarieties šim taustiņam, lai izmantotu ciparus un simbolus." + "Vēlreiz pieskarieties šim taustiņam, lai atkal izmantotu burtus." + "Pieskarieties taustiņam un turiet, lai mainītu tastatūras iestatījumus, piemēram, automātisko pabeigšanu." + "Izmēģiniet to!" + "Sākt" + "Tālāk" + "Gatavs" + "Sūtīt" + "?123" + "123" + "ABC" + "ALT" + "Balss ievade" + "Balss ievade jūsu valodā pašlaik netiek atbalstīta, taču tā ir pieejama angļu valodā." + "Balss ievade ir izmēģinājuma funkcija, kuras pamatā ir Google tīkla runas atpazīšanas līdzeklis." + "Lai izslēgtu balss ievadi, atveriet tastatūras iestatījumus." + "Lai izmantotu balss ievadi, nospiediet mikrofona pogu vai slidiniet pirkstus pāri ekrāna tastatūrai." + "Runājiet!" + "Notiek apstrāde" + + "Kļūda. Lūdzu, mēģiniet vēlreiz." + "Nevar izveidot savienojumu." + "Kļūda, pārāk ilga balss ievade." + "Audio problēma" + "Servera kļūda" + "Nekas nav dzirdams." + "Nav atrasta neviena atbilstība." + "Balss meklēšana nav instalēta." + "Ieteikums:"" slidiniet pirkstu pār tastatūru, lai veiktu balss ievadi." + "Ieteikums:"" nākamreiz mēģiniet izrunāt pieturzīmes, piemēram, “punkts”, “komats” vai “jautājuma zīme”." + "Atcelt" + "Labi" + "Balss ievade" + + "Izmantojot galveno tastatūru" + "Izmantojot simbolu tastatūru" + "Izsl." + + + "Galvenās tastatūras mikrofons" + "Simbolu tastatūras mikrofons" + "Balss ievade ir atspējota" + + "Automātiski iesniegt pēc balss ievades" + "Automātiski nospiest ievades taustiņu, meklējot vai pārejot uz nākamo lauku." + "Tastatūras atvēršana"\n\n"Pieskarieties jebkuram teksta laukam." + "Tastatūras aizvēršana"\n\n"Nospiediet taustiņu Atpakaļ." + "Pieskarieties taustiņam un turiet, lai skatītu opcijas."\n\n"Piekļūstiet pieturzīmēm un uzsvara zīmēm." + "Tastatūras iestatījumi"\n\n"Pieskarieties taustiņam ""?123"" un turiet." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Atlasīt ievades metodi" + "Ievades valodas" + "Slidiniet pirkstu uz atstarpes taustiņa, lai mainītu valodu" + "← Pieskarieties vēlreiz, lai saglabātu" + "Ir pieejama vārdnīca." + "Iespējot lietotāju atsauksmes" + "Palīdziet uzlabot šo ievades metodes redaktoru, automātiski nosūtot lietojuma statistiku un pārskatus par avārijām uzņēmumam Google." + "Pieskarties, lai izlabotu vārdus" + "Pieskarties ievadītajiem vārdiem, lai tos labotu" + "Tastatūras motīvs" + "tastatūra" + "balss" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-nb/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-nb/donottranslate-altchars.xml new file mode 100644 index 00000000..6257dfc3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-nb/donottranslate-altchars.xml @@ -0,0 +1,37 @@ + + + + äáàâąã + 3éèêëę€ + íìîï8 + öóòôõ9 + üúùûū7 + śšşß + ńñň + çćč + ýÿ6 + ðď + ř4 + ťþ5 + źžż + ł + w + œ + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-nb/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-nb/strings.xml new file mode 100644 index 00000000..c7ccce89 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-nb/strings.xml @@ -0,0 +1,140 @@ + + + + + "Skjermtastatur" + "Innstillinger for skjermtastatur" + "Inndataalternativer" + "Vibrer ved tastetrykk" + "Lyd ved tastetrykk" + "Hurtigvindu ved tastetrykk" + "Rett opp skrivefeil" + "Slå på retting av skrivefeil" + "Rett opp skrivefeil i breddeformat" + "Slå på retting av skrivefeil" + "Autokorrektur" + "Autokorriger forrige ord" + "Ordforslag" + "Innstillinger for ordforslag" + "Skru på autofullføring under skriving" + "Autofullfør" + "Større tekstfelt" + "Skjul ordforslag i breddeformat" + "Stor forbokstav" + "Start automatisk setninger med stor bokstav" + "Automatisk punktum" + + "Autokorrektur" + "Retter vanlige stavefeil" + "Vis forslag" + "Vis foreslåtte ord under skriving" + "Autofullføring" + "Mellomrom og punktum setter automatisk inn valgt ord" + "Vis innstillingsnøkkel" + "Automatisk" + "Vis alltid" + "Skjul alltid" + + + + "Bigram-forslag" + "Bruk forrige ord til å forbedre forslaget" + + "Ingen" + "Grunnleggende" + "Avansert" + + "%s: Lagret" + "Hold en tast nede for å se aksenterte tegn (ø, ö, osv.)" + "Trykk tilbakeknappen, ↶, for å lukke tastaturet" + "Få tilgang til tall og symboler" + "Trykk lenge på ordet lengst til venstre for å legge det til i ordlisten" + "Trykk på dette hintet for å forsette »" + "Trykk her for å lukke dette hintet og begynne å skrive!" + "Tastaturet åpnes når du tar på et tekstfelt" + "Trykk på og hold nede en tast for å se aksenter"\n"(ø, ö, ô, ó, osv.)" + "Bytt til tall og symboler ved å trykke på denne tasten" + "Gå tilbake til bokstaver igjen ved å trykke på denne tasten" + "Trykk på og hold nede denne tasten for å endre tastaturinnstillinger, som autofullføring" + "Prøv det!" + "Gå" + "Neste" + "Utfør" + "Send" + "?123" + "123" + "ABC" + "ALT" + "Stemmedata" + "Stemmedata håndteres foreløpig ikke på ditt språk, men fungerer på engelsk." + "Talekommandoer er en eksperimentell funksjon som bruker Googles nettverksbaserte talegjenkjenning." + "Gå til innstillinger for tastatur for å slå av stemmedata." + "Du bruker talekommandoer ved å trykke på mikrofonknappen eller skyve fingeren over tastaturet på skjermen." + "Snakk nå" + "Arbeider" + + "Feil. Prøv på nytt." + "Kunne ikke koble til" + "Feil – for mye tale" + "Lydproblem" + "Tjenerfeil" + "Ingen tale høres" + "Ingen treff" + "Talesøk ikke installert" + "Hint:"" Sveip over tastaturet for å snakke" + "Hint:"" Neste gang kan du prøve å tale inn tegnsettingen ved for eksempel å si «punktum», «komma» eller «spørsmålstegn»." + "Avbryt" + "OK" + "Talekommando" + + "På hovedtastatur" + "På talltastatur" + "Av" + + + "Mikrofon på hovedtastatur" + "Mikrofon på talltastatur" + "Talekommando er deaktivert" + + "Send inn automatisk etter tale" + "Trykk Enter automatisk ved søk eller flytting til neste felt." + "Åpne tastaturet"\n\n"Trykk på et tekstfelt." + "Lukke tastaturet"\n\n"Trykk på tilbaketasten." + "Trykk og hold nede en tast for flere valg"\n\n"Få tilgang til skilletegn og aksenter." + "Innstillinger for tastatur"\n\n"Trykk på & hold ""?123""-tasten." + ".no" + ".com" + ".net" + ".org" + ".info" + "Velg inndatametode" + "Inndataspråk" + "Dra fingeren på mellomromstasten for å endre språk" + "Trykk på nytt for å lagre" + "Ordbok tilgjengelig" + "Aktiver brukertilbakemelding" + "Ved å sende bruksstatistikk og programstopprapporter til Google automatisk, hjelper du oss med å gjøre redigeringsfunksjonen for denne inndatametoden enda bedre." + "Trykk for å endre ord" + "Trykk på ord du har skrevet inn, for å endre dem" + "Tastaturtema" + "tastatur" + "stemme" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-nl/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-nl/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-nl/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-nl/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-nl/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-nl/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-nl/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-nl/strings.xml new file mode 100644 index 00000000..2dc77c70 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-nl/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android-toetsenbord" + "Instellingen voor Android-toetsenbord" + "Invoeropties" + "Trillen bij toetsaanslag" + "Geluid bij toetsaanslag" + "Pop-up bij toetsaanslag" + "Typefouten corrigeren" + "Foutcorrectie tijdens invoer inschakelen" + "Invoerfouten in liggende weergave" + "Foutcorrectie tijdens invoer inschakelen" + "Woordsuggesties" + "Het vorige woord automatisch corrigeren" + "Woordsuggesties" + "Instellingen voor woordsuggesties" + "Automatisch voltooien tijdens typen inschakelen" + "Automatisch voltooien" + "Tekstveld vergroten" + "Woordsuggesties verbergen in liggende weergave" + "Auto-hoofdlettergebruik" + "Hoofdletter gebruiken aan het begin van een zin" + "Automatische interpunctie" + + "Snelle oplossingen" + "Hiermee worden veelvoorkomende typefouten gecorrigeerd" + "Suggesties weergeven" + "Voorgestelde woorden weergeven tijdens typen" + "Auto-aanvullen" + "Gemarkeerd woord automatisch invoegen met spatiebalk en interpunctie" + "Instellingscode weergeven" + "Automatisch" + "Altijd weergeven" + "Altijd verbergen" + + + + "Digram-suggesties" + "Vorig woord gebruiken om suggestie te verbeteren" + + "Geen" + "Basis" + "Geavanceerd" + + "%s: opgeslagen" + "Houd een toets ingedrukt om diakritische tekens weer te geven (ø, ö, enzovoort)" + "Druk op elk gewenst moment op de toets Terug ↶ om het toetsenbord te sluiten" + "Toegang tot cijfers en symbolen" + "Blijf drukken op het meest linkse woord om het toe te voegen aan het woordenboek" + "Raak deze tip aan om door te gaan »" + "Raak dit punt aan om deze tip te sluiten en te beginnen met typen." + "Het toetsenbord wordt geopend wanneer u een tekstveld aanraakt" + "Blijf een toets aanraken om diakritische tekens weer te geven"\n"(ø, ö, ô, ó, enzovoort)" + "Schakel over naar cijfers en symbolen door deze toets aan te raken" + "Ga terug naar letters door deze toets nogmaals aan te raken" + "Blijf deze toets aanraken om toetsenbordinstellingen te wijzigen, zoals auto-aanvullen" + "Probeer het zelf!" + "Start" + "Volgende" + "Gereed" + "Verzenden" + "?123" + "123" + "ABC" + "Alt" + "Spraakinvoer" + "Spraakinvoer wordt momenteel niet ondersteund in uw taal, maar is wel beschikbaar in het Engels." + "Spraakinvoer is een experimentele functie met de spraakherkenning van het Google-netwerk." + "Als u spraakinvoer wilt uitschakelen, gaat u naar de toetsenbordinstellingen." + "Als u spraakinvoer gebruikt, drukt u op de microfoonknop of schuift u uw vinger over het schermtoetsenbord." + "Nu spreken" + "Wordt uitgevoerd" + + "Fout. Probeer het opnieuw." + "Kan geen verbinding maken" + "Fout, te lange spraakinvoer." + "Audioprobleem" + "Serverfout" + "Geen spraak te horen" + "Geen resultaten gevonden" + "Spraakgestuurd zoeken is niet geïnstalleerd" + "Hint:"" schuif over het toetsenbord om te spreken" + "Hint:"" spreek de volgende keer interpunctie uit, zoals \'period\' (punt), \'comma\' (komma) of \'question mark\' (vraagteken)." + "Annuleren" + "OK" + "Spraakinvoer" + + "Op hoofdtoetsenbord" + "Op toetsenbord voor symbolen" + "Uit" + + + "Microfoon op hoofdtoetsenbord" + "Microfoon op toetsenbord voor symbolen" + "Spraakinvoer is uitgeschakeld" + + "Automatisch verzenden na spraak" + "Drukt automatisch op Enter tijdens het zoeken of wanneer u naar het volgende veld wilt gaan." + "Het toetsenbord openen"\n\n"Raak een tekstveld aan." + "Het toetsenbord sluiten"\n\n"Druk op de terugtoets." + "Een toets blijven aanraken voor opties"\n\n"Toegang tot interpunctie en diakritische tekens." + "Toetsenbordinstellingen"\n\n"Blijf de toets \'""?123""\' aanraken." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Invoermethode selecteren" + "Invoertalen" + "Schuif uw vinger over de spatiebalk om de taal te wijzigen" + "← Raak nogmaals aan om op te slaan" + "Woordenboek beschikbaar" + "Gebruikersfeedback inschakelen." + "Help deze invoermethode te verbeteren door automatisch gebruiksstatistieken en crashmeldingen naar Google te verzenden." + "Raak aan om woorden te corrigeren" + "Raak ingevoerde woorden aan om ze te corrigeren" + "Toetsenbordthema" + "toetsenbord" + "spraak" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pl/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pl/bools.xml new file mode 100644 index 00000000..897f4b3d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pl/bools.xml @@ -0,0 +1,22 @@ + + + + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pl/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pl/donottranslate-altchars.xml new file mode 100644 index 00000000..da6b5fd5 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pl/donottranslate-altchars.xml @@ -0,0 +1,32 @@ + + + + ą + ę3 + ìíîï8 + ó9 + ùúûü7 + ś + ń + ć + ýÿ6 + źż + ł + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pl/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pl/strings.xml new file mode 100644 index 00000000..8fbb74e3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pl/strings.xml @@ -0,0 +1,140 @@ + + + + + "Klawiatura Android" + "Ustawienia klawiatury Android" + "Opcje wprowadzania" + "Wibracja przy naciśnięciu" + "Dźwięk przy naciśnięciu" + "Powiększ po naciśnięciu" + "Popraw błędy pisowni" + "Włącz poprawianie błędów wprowadzania" + "Błędy wprowadzania w orientacji poziomej" + "Włącz poprawianie błędów wprowadzania" + "Sugestie słów" + "Automatycznie poprawiaj poprzednie słowo" + "Sugestie słów" + "Ustawienia propozycji słów" + "Włącz autouzupełnianie podczas wpisywania" + "Autouzupełnianie" + "Zwiększ rozmiar pola tekstowego" + "Wyłącz sugestie słów w orientacji poziomej" + "Wstawiaj wielkie litery" + "Zamieniaj na wielką pierwszą literę zdania" + "Automatyczna interpunkcja" + + "Szybkie poprawki" + "Poprawia częste błędy wpisywania" + "Pokaż sugestie" + "Wyświetl sugerowane słowa podczas wpisywania" + "Autouzupełnianie" + "Spacja i znaki przestankowe wstawiają podświetlone słowo" + "Pokaż klawisz ustawień" + "Automatycznie" + "Zawsze pokazuj" + "Zawsze ukrywaj" + + + + "Sugestie dla bigramów" + "Używaj poprzedniego wyrazu, aby polepszyć sugestię" + + "Brak" + "Podstawowy" + "Zaawansowany" + + "%s : Zapisano" + "Przytrzymaj klawisz, aby wyświetlić znaki akcentowane (ą, ó itp.)" + "Naciśnij klawisz cofania ↶, aby zamknąć klawiaturę w dowolnym momencie" + "Przejdź do cyfr i symboli" + "Naciśnij i przytrzymaj słowo po lewej stronie w celu dodania go do słownika" + "Dotknij tej podpowiedzi, aby kontynuować »" + "Dotknij tutaj, aby zamknąć tę podpowiedź i zacząć pisać!" + "Klawiatura jest otwierana po każdym dotknięciu pola tekstowego." + "Dotknij i przytrzymaj klawisz, aby wyświetlić znaki akcentowane"\n"(ą, ę, ł, ó itd.)." + "Przełącz na cyfry i symbole, dotykając tego klawisza." + "Wróć do trybu liter, dotykając ponownie tego klawisza." + "Dotknij i przytrzymaj ten klawisz, aby zmienić ustawienia klawiatury, takie jak autouzupełnianie." + "Wypróbuj!" + "OK" + "Dalej" + "OK" + "Wyślij" + "?123" + "123" + "ABC" + "ALT" + "Wprowadzanie głosowe" + "Wprowadzanie głosowe obecnie nie jest obsługiwane w Twoim języku, ale działa w języku angielskim." + "Wprowadzanie głosowe to funkcja eksperymentalna wykorzystująca funkcję firmy Google umożliwiającą rozpoznawanie mowy przy użyciu sieci." + "Aby wyłączyć wprowadzanie głosowe, przejdź do ustawień klawiatury." + "Aby skorzystać z wprowadzania głosowego, naciśnij przycisk mikrofonu lub przesuń palcem po klawiaturze ekranowej." + "Mów teraz" + "W toku" + + "Błąd. Spróbuj ponownie." + "Nie można nawiązać połączenia" + "Błąd, zbyt długa wypowiedź." + "Problem z dźwiękiem" + "Błąd serwera" + "Nie wykryto mowy" + "Brak wyników" + "Wyszukiwanie głosowe nie jest zainstalowane" + "Wskazówka:"" przesuń palcem po klawiaturze, aby mówić." + "Wskazówka:"" następnym razem spróbuj wypowiadać nazwy znaków interpunkcyjnych: „kropka”, „przecinek” lub „pytajnik”." + "Anuluj" + "OK" + "Wprowadzanie głosowe" + + "Na klawiaturze głównej" + "Na klawiaturze z symbolami" + "Wyłączone" + + + "Mikrofon na klawiaturze głównej" + "Mikrofon na klawiaturze z symbolami" + "Wprowadzanie głosowe jest wyłączone" + + "Automatyczne przesyłanie uruchamiane głosem" + "Podczas wyszukiwania lub przechodzenia do następnego pola automatycznie naciśnij klawisz Enter." + "Otwórz klawiaturę"\n\n"Dotknij dowolnego pola tekstowego." + "Zamknij klawiaturę"\n\n"Naciśnij klawisz Wróć." + "Dotknij klawisza i przytrzymaj go, aby wyświetlić opcje"\n\n"Dostęp do znaków przestankowych i akcentowanych." + "Ustawienia klawiatury"\n\n"Dotknij klawisza ""?123"" i przytrzymaj go." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Wybierz sposób wprowadzania tekstu" + "Języki wprowadzania" + "Przesuń palcem po spacji, aby zmienić język" + "← Dotknij ponownie, aby zapisać" + "Słownik dostępny" + "Włącz przesyłanie opinii użytkownika" + "Pomóż ulepszyć edytor wprowadzania tekstu, automatycznie wysyłając do Google statystyki użycia i raporty o awariach." + "Popraw dotknięte słowo" + "Dotknięte słowo zostanie poprawione" + "Motyw klawiatury" + "klawiatura" + "głosowe" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pt-rPT/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pt-rPT/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pt-rPT/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pt-rPT/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pt-rPT/strings.xml new file mode 100644 index 00000000..7495b66e --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pt-rPT/strings.xml @@ -0,0 +1,140 @@ + + + + + "Teclado do Android" + "Definições de teclado do Android" + "Opções de introdução" + "Vibrar ao primir as teclas" + "Som ao premir as teclas" + "Mostrar popup ao premir tecla" + "Corrigir erros de escrita" + "Activar a correcção de erros de entrada" + "Erros de entrada na horizontal" + "Activar a correcção de erros de entrada" + "Sugestões de palavras" + "Corrigir automaticamente a palavra anterior" + "Sugestões de palavras" + "Definições de sugestão de palavras" + "Activar a conclusão automática durante a escrita" + "Conclusão automática" + "Aumentar o tamanho do campo de texto" + "Ocultar sugestões de palavras na vista horizontal" + "Letras maiúsculas automáticas" + "Colocar inicial maiúscula no início de uma frase" + "Pontuação automática" + + "Correcções rápidas" + "Corrige os erros de escrita comuns" + "Mostrar sugestões" + "Apresentar sugestões de palavras ao escrever" + "Conclusão automática" + "A barra de espaços e a pontuação inserem automaticamente uma palavra realçada" + "Mostrar tecla das definições" + "Automático" + "Mostrar sempre" + "Ocultar sempre" + + + + "Sugestões Bigram" + "Utilizar a palavra anterior para melhorar a sugestão" + + "Nenhum" + "Básico" + "Avançados" + + "%s: guardada" + "Mantenha uma tecla premida para ver os acentos (ø, ö, etc.)" + "Prima a tecla de retrocesso ↶ para fechar o teclado a qualquer momento" + "Aceder a números e símbolos" + "Prima e mantenha premida a palavra mais à esquerda para a adicionar ao dicionário" + "Toque nesta sugestão para continuar »" + "Toque aqui para fechar esta sugestão e começar a escrever!" + "O teclado abre quando tocar num campo de texto" + "Mantenha premida uma tecla para ver os acentos"\n"(ø, ö, ô, ó, etc.)" + "Mude para números e símbolos tocando nesta tecla" + "Regresse às letras tocando novamente nesta tecla" + "Mantenha premida esta tecla para alterar definições do teclado, tais como a conclusão automática" + "Experimente!" + "Ir" + "Seguinte" + "Feito" + "Enviar" + "?123" + "123" + "ABC" + "ALT" + "Entrada de voz" + "Actualmente, a entrada de voz não é suportada para o seu idioma, mas funciona em inglês." + "A entrada de voz é uma funcionalidade experimental que utiliza o reconhecimento de voz em rede da Google." + "Para desactivar a entrada de voz, aceda às definições do teclado." + "Para utilizar a entrada de voz, prima o botão do microfone ou deslize o dedo no teclado do ecrã." + "Falar agora" + "A executar" + + "Erro. Tente novamente." + "Não foi possível ligar" + "Erro, discurso demasiado longo." + "Problema de áudio" + "Erro no servidor" + "Nenhuma voz ouvida" + "Não foram encontradas correspondências" + "Pesquisa de voz não instalada" + "Sugestão:"" Deslize no teclado para falar" + "Sugestão:"" Da próxima vez, experimente dizer a pontuação como \"ponto final\", \"vírgula\" ou \"ponto de interrogação\"." + "Cancelar" + "OK" + "Entrada de voz" + + "No teclado principal" + "No teclado de símbolos" + "Desactivada" + + + "Microfone no teclado principal" + "Microfone no teclado de símbolos" + "A entrada de voz está desactivada" + + "Enviar automaticamente depois da voz" + "Premir automaticamente ENTER ao pesquisar ou avançar para o campo seguinte." + "Abra o teclado"\n\n"Toque em qualquer campo de texto." + "Feche o teclado"\n\n"Prima a tecla \"Anterior\"." + "Mantenha premida uma tecla para as opções"\n\n"Aceder a pontuação e acentos." + "Definições do teclado"\n\n"Mantenha premida a tecla ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Seleccionar método de entrada" + "Idiomas de entrada" + "Deslize o dedo pela barra de espaço para alterar o idioma" + "← Toque novamente para guardar" + "Dicionário disponível" + "Activar comentários do utilizador" + "Envie automaticamente estatísticas de utilização e relatórios de falhas para a Google e ajude-nos a melhor este editor de método de introdução." + "Tocar para corrigir palavras" + "Tocar nas palavras introduzidas para as corrigir" + "Tema do teclado" + "teclado" + "voz" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pt/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pt/donottranslate-altchars.xml new file mode 100644 index 00000000..d3beafad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pt/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóôõöœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-pt/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-pt/strings.xml new file mode 100644 index 00000000..d359ce93 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-pt/strings.xml @@ -0,0 +1,140 @@ + + + + + "Teclado Android" + "Configurações de teclado Android" + "Opções de entrada" + "Vibrar ao tocar a tecla" + "Som ao tocar a tecla" + "Exibir pop-up ao digitar" + "Corrigir erros de digitação" + "Ativar a correção de erro de entrada" + "Erros de entrada de paisagem" + "Ativar a correção de erro de entrada" + "Sugestões de palavra" + "Corrigir automaticamente a palavra anterior" + "Sugestões de palavra" + "Configurações de sugestão de palavra" + "Ativar a conclusão automática durante a digitação" + "Conclusão automática" + "Aumentar o tamanho do arquivo de texto" + "Ocultar sugestões de palavra na visualização da paisagem" + "Capitaliz. automática" + "Colocar em maiúscula o início de uma frase" + "Pontuação automática" + + "Reparos rápidos" + "Corrige erros comuns de digitação" + "Mostrar sugestões" + "Exibir sugestões de palavras durante a digitação" + "Conclusão automática" + "Barra de espaço e pontuação inserem a palavra destacada" + "Mostrar tecla de config." + "Automático" + "Mostrar sempre" + "Sempre ocultar" + + + + "Sugestões de bigrama" + "Usar palavra anterior para melhorar a sugestão" + + "Nenhum" + "Básico" + "Avançado" + + "%s : Salvo" + "Segure uma tecla pressionada para ver os acentos (ø, ö, etc.)" + "Apertar a tecla voltar ↶ para fechar o teclado, em qualquer ponto" + "Acessar números e símbolos" + "Pressione e segure a palavra mais à esquerda para adicioná-la ao dicionário" + "Toque nesta dica para continuar »" + "Toque aqui para fechar esta dica e começar a digitar!" + "O teclado abre toda vez que você tocar em um campo de texto" + "Tocar e segurar uma tecla para visualizar acentos"\n"(ø, ö, ô, ó e assim por diante)" + "Alternar para números e símbolos tocando nessa tecla" + "Voltar às letras tocando novamente nessa tecla" + "Tocar e segurar esta tecla para alterar as configurações do teclado, como a conclusão automática" + "Experimente!" + "Ir" + "Avançar" + "Feito" + "Enviar" + "?123" + "123" + "ABC" + "ALT" + "Entrada de voz" + "A entrada de voz não é suportada no momento para o seu idioma, mas funciona em inglês." + "A entrada de voz é um recurso experimental que usa o reconhecimento de fala de rede do Google." + "Para desativar a entrada de voz, vá para as configurações do teclado." + "Para usar a entrada de voz, pressione o botão com o microfone ou deslize o dedo sobre o teclado na tela." + "Fale agora" + "Trabalhando" + + "Erro. Tente novamente." + "Não foi possível conectar" + "Erro, fala muito longa." + "Problema com o áudio" + "Erro do servidor" + "Nenhuma fala ouvida" + "Não há resultados compatíveis" + "A pesquisa por voz não está instalada" + "Dica:"" Deslize sobre o teclado para falar" + "Dica:"" Da próxima vez, tente falar o nome da pontuação como \"ponto\", \"vírgula\" ou \"ponto de interrogação\"." + "Cancelar" + "OK" + "Entrada de voz" + + "No teclado principal" + "No teclado de símbolos" + "Desativado" + + + "Microfone no teclado principal" + "Microfone no teclado de símbolos" + "Entrada de voz desativada" + + "Enviar automaticamente depois de falar" + "Pressione Enter automaticamente ao pesquisar ou ir para o próximo campo." + "Abra o teclado"\n\n"Toque em qualquer campo de texto." + "Feche o teclado"\n\n"Pressione a tecla Voltar." + "Toque e mantenha pressionada uma tecla para ver as opções"\n\n"Acesse a pontuação e as pronúncias." + "Configurações de teclado"\n\n"Toque e mantenha pressionada a tecla ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Selecionar método de entrada" + "Idiomas de entrada" + "Deslize o dedo na barra de espaços para alterar o idioma" + "← Toque novamente para salvar" + "Dicionário disponível" + "Ativar comentário do usuário" + "Ajude a melhorar este editor de método de entrada enviando automaticamente ao Google estatísticas de uso e relatórios de falhas." + "Tocar para corrigir" + "Toque as palavras para corrigi-las" + "Tema do teclado" + "teclado" + "voz" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-rm/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-rm/donottranslate-altchars.xml new file mode 100644 index 00000000..f17026fa --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-rm/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + 3èéêë + ìíîï8 + òóöôõœø9 + ùúûü7 + §ß + ñ + ç + ýÿ6 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-rm/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-rm/strings.xml new file mode 100644 index 00000000..47afae9a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-rm/strings.xml @@ -0,0 +1,148 @@ + + + + + "Tastatura Android" + "Parameters da la tastatura Android" + + + "Vibrar cun smatgar in buttun" + "Tun cun smatgar in buttun" + "Pop-up cun smatgar ina tasta" + "Curreger sbagls d\'endataziun" + "Activar la correctura da sbagls d\'endataziun" + "Sbagls d\'endataziun en il format orizontal" + "Activar la correctura da sbagls d\'endataziun" + "Propostas da pleds" + "Curreger automaticamain il pled precedent" + "Propostas da pleds" + "Parameters da las propostas per pleds" + "Activar la cumplettaziun automatica durant l\'endataziun" + "Cumplettaziun automatica" + "Engrondir il champ da text" + "Zuppentar propostas da pleds en il format orizontal" + "Maiusclas automaticas" + "Scriver grond l\'entschatta da mintga frasa" + "Interpuncziun automatica" + + "Correcturas sveltas" + "Curregia sbagls da tippar currents" + "Mussar las propostas" + "Mussar pleds proponids durant l\'endataziun" + "Cumplettaziun automatica" + "Inserir auto. il pled marcà cun la tasta da vid/interpuncziun" + + + + + + + + + + + + "Propostas da tip bigram" + "Meglierar la proposta cun agid dal pled precedent" + + "Nagin" + "Simpel" + "Avanzà" + + "%s : Memorisà" + "\"Tegnair smatgà per mussar ils accents (à, é, etc.)\"" + "Smatgar ↶ per serrar la tastatura" + "Acceder a cifras e simbols" + "Smatgar ditg sin il pled dal tut a sanestra per l\'agiuntar al dicziunari" + "Tutgar quest commentari per cuntinuar »" + "\"Tutgar qua, per serrar quest commentari e cumenzar a tippar!\"" + "La tastatura vegn adina averta sche Vus tutgais in champ da text." + "\"""Tegnai smatgà ina tasta per mussar ils segns spezials"\n"(ø, ö, ô, ó etc.).""\"" + "Midai a numers e simbols cun tutgar quest buttun." + "Turnai a letras cun smatgar danovamain quest buttun." + "\"""Tegnai smatgà quest buttun per midar ils parameters da tastatura, sco p. ex. la cumplettaziun automatica.""\"" + "Empruvai!" + "Dai" + "Vinavant" + "Finì" + "Trametter" + "?123" + "123" + "ABC" + "ALT" + "Cumonds vocals" + "\"Cumonds vocals en Vossa lingua na vegnan actualmain betg sustegnids, ma la funcziun è disponibla per englais.\"" + "Ils cumonds vocals èn ina funcziunalitad experimentala che utilisescha la renconuschientscha vocala da rait da Google." + "\"Per deactivar ils cumonds vocals, avri ils parameters da tastatura.\"" + "\"Per utilisar ils cumonds vocals, smatgai il buttun dal microfon u stritgai cun il det sur la tastatura dal visur.\"" + "Ussa discurrer" + "Operaziun en progress" + + "Errur. Empruvai anc ina giada." + "Impussibel da connectar." + "Errur - discurrì memia ditg." + "Problem audio" + "Errur dal server" + "Betg udì ina frasa vocala" + "Betg chattà correspundenzas" + "Betg installà la tschertga vocala" + "Commentari:"" Stritgai cun il det sur la tastatura per discurrer." + "\"""Commentari:"" Empruvai la proxima giada d\'agiuntar segns d\'interpuncziun sco \"\"punct\"\", \"\"comma\"\" u \"\"segn da dumonda\"\" cun cumonds vocals.\"" + "Interrumper" + "OK" + "Cumonds vocals" + + "Sin la tastatura principala" + "Sin la tastatura da simbols" + "Deactivà" + + + "Microfon sin la tastatura principala" + "Microfon sin la tastatura da simbols" + "Ils cumonds vocals èn deactivads" + + "Trametter automaticamain suenter il cumond vocal" + "Smatgai sin la tasta enter sche Vus exequis ina tschertga u siglis al proxim champ." + "Avrir la tastatura"\n\n"Tutgai inqual champ da text." + "\"""Serrar la tastatura"\n\n"Smatgai il buttun \"\"Enavos\"\".\"" + "Tutgar e tegnair smatgà in buttun per acceder a las opziuns"\n\n"Accedi a segns d\'interpuncziun ed accents." + "Parameters da tastatura"\n\n"Tutgai e tegnai smatgà il buttun ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + + + "Linguas da cumonds vocals" + "Stritgar cun il det sur la tasta da vid per midar la lingua" + "← Tippar danovamain per memorisar" + "Dicziunari disponibel" + "Activar il feedback da l\'utilisader" + "Gidai a meglierar quest editur da la metoda d\'endataziun cun trametter automaticamain datas statisticas davart l\'utilisaziun e rapports da collaps a Google." + + + + + "Design da la tastatura" + "tastatura" + "vusch" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ro/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ro/strings.xml new file mode 100644 index 00000000..37fdeb4c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ro/strings.xml @@ -0,0 +1,140 @@ + + + + + "Tastatură Android" + "Setările tastaturii Android" + "Opţiuni de introducere text" + "Vibrare la apăsarea tastei" + "Sunet la apăsarea tastei" + "Fereastră pop-up la apăsarea tastei" + "Corectaţi erorile de dactilografiere" + "Activaţi corectarea erorii de intrare" + "Erori de introducere în modul peisaj" + "Activaţi corectarea erorii de intrare" + "Sugestii de cuvinte" + "Corecţie automată a cuvântului anterior" + "Sugestii de cuvinte" + "Setările sugestiei de cuvinte" + "Activaţi completarea automată în timpul introducerii textului" + "Completare automată" + "Măriţi dimensiunea câmpului text" + "Ascundeţi sugestiile de cuvinte în vizualizarea de tip peisaj" + "Auto-capitalizare" + "Doresc să se scrie cu majusculă începutul propoziţiilor" + "Punctuaţie automată" + + "Remedieri rapide" + "Corectează greşelile introduse frecvent" + "Afişaţi sugestiile" + "Afişare sugestii de cuvinte în timpul introducerii de text" + "Completare automată" + "Bara de spaţiu şi punctuaţia inserează automat un cuvânt evidenţiat" + "Afişaţi tasta setări" + "Automat" + "Afişaţi întotdeauna" + "Ascundeţi întotdeauna" + + + + "Sugestii pentru cuvinte de două litere" + "Utilizaţi cuvântul anterior pentru a îmbunătăţi sugestia" + + "Niciunul" + "De bază" + "Avansat" + + "%s: salvat" + "Ţineţi o tastă apăsată pentru a vedea accentele (ø, ö, etc.)" + "Apăsaţi tasta Înapoi ↶ pentru a închide oricând tastatura" + "Accesaţi numere şi simboluri" + "Apăsaţi şi ţineţi apăsat pe cuvântul cel mai din stânga, pentru a-l adăuga la dicţionar" + "Atingeţi acest indiciu pentru a continua »" + "Atingeţi aici pentru a închide acest indiciu şi începeţi să introduceţi text!" + "Tastatura se deschide de fiecare dată când atingeţi un câmp text" + "Atingeţi şi ţineţi apăsată o tastă pentru a vizualiza accentele"\n"(ø, ö, ô, ó etc.)" + "Comutaţi între numere şi simboluri atingând această tastă" + "Reveniţi la litere prin atingerea acestei taste din nou" + "Apăsaţi şi ţineţi apăsată această tastă pentru a schimba setările tastaturii, cum ar fi completarea automată" + "Încercaţi!" + "OK" + "Înainte" + "Terminat" + "Trimiteţi" + "?123" + "123" + "ABC" + "ALT" + "Intrare voce" + "Intrarea vocală nu este acceptată în prezent pentru limba dvs., însă funcţionează în limba engleză." + "Intrarea vocală este o funcţie experimentală ce utilizează recunoaşterea vocală în reţea oferită de Google." + "Pentru a dezactiva intrarea vocală, accesaţi setările tastaturii." + "Pentru a utiliza intrarea vocală, apăsaţi butonul de microfon sau glisaţi degetul de-a lungul tastaturii de pe ecran." + "Vorbiţi acum" + "Se analizează" + + "Eroare. Încercaţi din nou." + "Conectare imposibilă" + "Eroare, discurs prea lung." + "Problemă audio" + "Eroare de server" + "Nu s-a auzit vorbirea" + "Nicio potrivire" + "Căutarea vocală nu este instalată" + "Indiciu:"" glisaţi de-a lungul tastaturii pentru a vorbi" + "Indiciu:"" data viitoare, încercaţi să rostiţi şi punctuaţia, cum ar fi „punct”, „virgulă”, sau „semn de întrebare”." + "Anulaţi" + "OK" + "Intrare voce" + + "Pe tastatura principală" + "Pe tastatura de simboluri" + "Dezactivat" + + + "Microfon pe tastatura principală" + "Microfon pe tastatura de simboluri" + "Intrarea vocală este dezactivată" + + "Trimitere automată după intrarea vocală" + "Apăsaţi automat tasta Enter atunci când se face o căutare sau când se trece la câmpul următor." + "Deschideţi tastatura"\n\n"Atingeţi orice câmp de text." + "Închideţi tastatura"\n\n"Apăsaţi pe tasta Înapoi." + "Atingeţi şi ţineţi apăsată o tastă pentru opţiuni"\n\n"Accesaţi punctuaţia şi accentele." + "Setările tastaturii"\n\n"Atingeţi şi ţineţi apăsată tasta ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Selectaţi metoda de introducere a textului" + "Selectaţi limba" + "Glisaţi degetul pe bara de spaţiu pentru a schimba limba" + "← Atingeţi din nou pentru a salva" + "Dicţionar disponibil" + "Activaţi feedback de la utilizatori" + "Ajutaţi la îmbunătăţirea acestui instrument de editare a metodelor de introducere a textului trimiţând în mod automat la Google statistici de utilizare şi rapoarte de blocare." + "Atingeţi pentru a corecta cuvintele" + "Atingeţi cuvintele introduse pentru a le corecta" + "Temă pentru tastatură" + "tastatură" + "voce" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ru/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ru/donottranslate-altchars.xml new file mode 100644 index 00000000..46241a62 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ru/donottranslate-altchars.xml @@ -0,0 +1,32 @@ + + + + àáâãäåæ + èéêë + ìíîï + òóôõöœø + ùúûü + §ß + ñ + ç + ýÿ + ё5 + ъ + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-ru/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-ru/strings.xml new file mode 100644 index 00000000..0b70f0b3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-ru/strings.xml @@ -0,0 +1,140 @@ + + + + + "Клавиатура Android" + "Настройки клавиатуры Android" + "Параметры ввода" + "Виброотклик клавиш" + "Звук клавиш" + "Увеличение нажатых" + "Исправлять опечатки" + "Включить исправление ошибок при вводе" + "Ошибки при вводе в горизонтальной ориентации" + "Включить исправление ошибок при вводе" + "Предложение слов" + "Автоматически исправлять предыдущее слово" + "Предложение слов" + "Настройки подсказок" + "Включить автоматическое завершение слов при вводе" + "Автоматическое завершение" + "Увеличить размер текстового поля" + "Скрывать предложение слов в горизонтальной ориентации" + "Заглавные автоматически" + "Делать заглавной первую букву предложения" + "Автопунктуация" + + "Быстрое исправление" + "Исправлять распространенные опечатки" + "Предлагать варианты" + "Предлагать варианты слов во время ввода" + "Автозавершение" + "При нажатии пробела вставлять предложенное слово" + "Кнопка настроек" + "Автоматически" + "Всегда показывать" + "Всегда скрывать" + + + + "Биграммные подсказки" + "Используйте предыдущее слово, чтобы исправить подсказку" + + "Нет" + "Основной" + "Дополнительно" + + "%s: сохранено" + "Удерживайте клавишу, чтобы увидеть варианты с диакритическими знаками (ø, ö и т.д.)" + "Нажмите клавишу \"Назад\" ↶, чтобы закрыть клавиатуру в любой момент" + "Открыть цифры и символы" + "Нажмите и удерживайте слово слева, чтобы добавить его в словарь" + "Чтобы продолжить, нажмите на эту подсказку »" + "Нажмите здесь, чтобы закрыть подсказку и начать вводить текст." + "Клавиатура появляется автоматически при касании текстового поля" + "Нажмите и удерживайте клавишу для отображения вариантов с диакритическими знаками "\n"(ø, ö, ô, ó и т. п.)" + "Для переключения между вводом цифр и символов используйте эту клавишу" + "Чтобы вернуться к буквенной клавиатуре, снова нажмите на эту клавишу" + "Чтобы изменить настройки клавиатуры (такие как автозавершение), нажмите и удерживайте эту клавишу" + "Попробуйте!" + "Поиск" + "Далее" + "Готово" + "Отправить" + "?123" + "123" + "АБВ" + "ALT" + "Голосовой ввод" + "В настоящее время функция голосового ввода не поддерживает ваш язык, но вы можете пользоваться ей на английском." + "Голосовой ввод – экспериментальная функция на основе технологии сетевого распознавания речи от Google." + "Функция голосового ввода отключается в настройках клавиатуры." + "Чтобы использовать голосовой ввод, нажмите кнопку микрофона или проведите пальцем по экранной клавиатуре." + "Говорите" + "Обработка запроса" + + "Ошибка. Повторите попытку." + "Ошибка подключения" + "Слишком длинная фраза" + "Неполадка со звуком" + "Ошибка сервера" + "Речи не слышно" + "Соответствий не найдено" + "Голосовой поиск не установлен" + "Совет"". Проведите пальцем по клавиатуре для голосового ввода." + "Совет"". В следующий раз проговаривайте знаки препинания, например \"точка\", \"запятая\", \"вопросительный знак\"." + "Отмена" + "ОК" + "Голосовой ввод" + + "Значок на основной клавиатуре" + "Значок на клавиатуре символов" + "Отключить голосовой ввод" + + + "Значок на основной клавиатуре" + "Значок на клавиатуре символов" + "Голосовой ввод отключен" + + "Автоматически отправлять по окончании голосового ввода" + "Автоматически нажимать \"Ввод\" при поиске или переходе к следующему полю." + "Открытие клавиатуры"\n\n"Нажмите на любое текстовое поле." + "Закрытие клавиатуры"\n\n"Нажмите клавишу \"Назад\"." + "Нажмите и удерживайте клавишу для вызова параметров"\n\n"Доступ к пунктуационным и диакритическим знакам." + "Настройки клавиатуры"\n\n"Нажмите и удерживайте клавишу ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Выбрать способ ввода" + "Языки ввода" + "Для изменения языка проведите пальцем по пробелу" + "← Нажмите еще раз, чтобы сохранить" + "Доступен словарь" + "Включить отправку сведений" + "Помогите усовершенствовать редактор способа ввода, разрешив отправку статистики и отчетов о сбоях в Google." + "Исправление нажатием" + "Нажмите на слово, чтобы исправить его" + "Вид клавиатуры" + "клавиатура" + "голосовой" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-sk/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-sk/strings.xml new file mode 100644 index 00000000..89e3bea2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-sk/strings.xml @@ -0,0 +1,140 @@ + + + + + "Klávesnica Android" + "Nastavenia klávesnice Android" + "Možnosti zadávania textu a údajov" + "Pri stlačení klávesu vibrovať" + "Zvuk pri stlačení klávesu" + "Zobraziť znaky pri stlačení klávesu" + "Opravovať preklepy" + "Povoliť opravu chýb vstupu" + "Chyby vstupu v zobrazení na šírku" + "Povoliť opravu chýb vstupu" + "Návrhy slov" + "Automaticky opraviť predchádzajúce slovo" + "Návrhy slov" + "Nastavenia návrhov slov" + "Povoliť automatické dokončovanie pri písaní" + "Automatické dokončovanie" + "Zväčšiť textové pole" + "Skryť návrhy slov v zobrazení na šírku" + "Veľké písmená automaticky" + "Začať vetu veľkým písmenom" + "Automatická interpunkcia" + + "Rýchle opravy" + "Opravuje najčastejšie chyby pri písaní" + "Zobraziť návrhy" + "Zobrazovať navrhované slová počas písania" + "Automatické dokončovanie" + "Stlačením medzerníka alebo interpunkčného znamienka automaticky vložíte zvýraznené slovo." + "Zobraziť kláves Nastavenia" + "Automaticky" + "Vždy zobrazovať" + "Vždy skrývať" + + + + "Návrh Bigram" + "Na zlepšenie návrhu použiť predchádzajúce slovo" + + "Žiadne" + "Základné" + "Rozšírené" + + "%s : Uložené" + "Podržaním klávesu zobrazíte diakritiku (á, ž atď.)" + "Stlačením klávesu Späť ↶ môžete klávesnicu kedykoľvek zavrieť." + "Prístup k číslam a symbolom" + "Stlačením a podržaním slova úplne vľavo toto slovo pridáte do slovníka." + "Ak chcete pokračovať, dotknite sa tohto tipu »" + "Ak chcete tento tip zavrieť a začať písať, dotknite sa tu." + "Klávesnica sa otvorí vždy, keď sa dotknete textového poľa." + "Pridržaním klávesu zobrazíte diakritiku"\n"(ó, ø, ö, ô apod.)" + "Ak chcete prepnúť na režim zadávania číslic a symbolov, dotknite sa tohto klávesu." + "Ak chcete prejsť späť na zadávanie písmen, dotknite sa znova tohto klávesu." + "Pridržaním tohto klávesu zmeníte nastavenia klávesnice (napr. automatické dokončovanie)." + "Skúste si to." + "Hľadať" + "Ďalej" + "Hotovo" + "Odoslať" + "?123" + "123" + "ABC" + "ALT" + "Hlasový vstup" + "Pre váš jazyk aktuálne nie je hlasový vstup podporovaný, ale funguje v angličtine." + "Hlasový vstup je experimentálna funkcia, ktorá využíva sieťové rozpoznanie reči spoločnosti Google." + "Ak chcete vypnúť hlasový vstup, prejdite na nastavenia klávesnice." + "Ak chcete použiť hlasový vstup, stlačte tlačidlo mikrofónu alebo prejdite prstom po klávesnici na obrazovke." + "Hovorte" + "Prebieha spracovanie" + + "Chyba. Skúste to znova." + "Pripojenie sa nepodarilo." + "Chyba, reč je príliš dlhá." + "Problém so zvukom" + "Chyba servera" + "Nebola zistená žiadna reč." + "Nenašli sa žiadne zhody" + "Hlasové vyhľadávanie nie je nainštalované" + "Tip:"" Ak chcete aktivovať hlasový vstup, prejdite prstom po klávesnici." + "Tip:"" Nabudúce skúste vysloviť interpunkciu, napríklad „bodka“, „čiarka“ alebo „otáznik“." + "Zrušiť" + "OK" + "Hlasový vstup" + + "Na hlavnej klávesnici" + "Na klávesnici so symbolmi" + "Vypnuté" + + + "Mikrofón na hlavnej klávesnici" + "Mikrofón na klávesnici so symbolmi" + "Hlasový vstup je zakázaný" + + "Po hlasovom vstupe automaticky odoslať" + "Pri vyhľadávaní alebo prechode na ďalšie pole automaticky stlačiť kláves Enter." + "Otvorte klávesnicu"\n\n"Dotknite sa ľubovoľného textového poľa." + "Zatvorte klávesnicu"\n\n"Stlačte tlačidlo Späť." + "Dotknutím a pridržaním klávesu zobrazíte možnosti"\n\n"Prístup k interpunkčným znamienkam a diakritike." + "Nastavenia klávesnice"\n\n"Dotknite sa klávesu ""?123"" a podržte ho." + ".com" + ".sk" + ".org" + ".net" + ".eu" + "Výber metódy vstupu" + "Jazyky vstupu" + "Jazyk môžete zmeniť posunutím prsta po medzerníku." + "← Ďalším dotykom slovo uložíte" + "K dispozícii je slovník" + "Povoliť spätnú väzbu od používateľov" + "Automatickým zasielaním štatistík o využívaní editora metódy vstupu a správ o jeho zlyhaní do služby Google môžete prispieť k vylepšeniu tohto nástroja." + "Dotykom opravíte slová" + "Dotykom zadaným slov ich opravíte" + "Motív klávesnice" + "klávesnica" + "hlasová" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-sl/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-sl/strings.xml new file mode 100644 index 00000000..090e0b92 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-sl/strings.xml @@ -0,0 +1,140 @@ + + + + + "Tipkovnica Android" + "Nastavitve tipkovnice Android" + "Možnosti vnosa" + "Vibriranje ob pritisku tipke" + "Zvok ob pritisku tipke" + "Pojavno okno ob pritisku tipke" + "Popravljanje tipkarskih napak" + "Omogoči popravljanje napak pri vnosu" + "Napake pri vnosu v ležečem položaju" + "Omogoči popravljanje napak pri vnosu" + "Predlogi besed" + "Samodejno popravi prejšnjo besedo" + "Predlogi besed" + "Nastavitve za predlaganje besede" + "Omogoči samodokončanje med tipkanjem" + "Samodokončanje" + "Povečaj velikost besedilnega polja" + "Skrij predloge besed v ležečem pogledu" + "Samodejne velike začetnice" + "Napiši začetek stavka z veliko začetnico" + "Samodejno vstavljanje ločil" + + "Hitri popravki" + "Popravi pogoste tipkarske napake" + "Pokaži predloge" + "Prikaži predlagane besede med tipkanjem" + "Samodokončanje" + "Preslednica in ločila samodejno vnesejo označeno besedo" + "Pokaži tipko za nastavitve" + "Samodejno" + "Vedno pokaži" + "Vedno skrij" + + + + "Bigramni predlogi" + "Predlog izboljšaj s prejšnjo besedo" + + "Brez" + "Osnovni" + "Dodatno" + + "%s: shranjeno" + "Držite tipko, da prikažete poudarke (ø, ö itd.)" + "Kadar koli lahko pritisnete tipko »Nazaj« ↶, da zaprete tipkovnico" + "Dostop do številk in simbolov" + "Če besedo želite dodati v slovar, jo pridržite" + "Dotaknite se tega nasveta za nadaljevanje »" + "Dotaknite se tukaj, da zaprete nasvet in začnete tipkati!" + "Tipkovnice se odpre, kadar se dotaknete besedilnega polja" + "Za ogled poudarkov pridržite tipko"\n"(ø, ö, ô, ó itd.)" + "Preklopite na številke in simbole z dotikom te tipke" + "Na črke se vrnete, če se še enkrat dotaknete te tipke" + "Pridržite to tipko, če želite spremeniti nastavitve tipkovnice, npr. samodokončanje" + "Poskusite!" + "Pojdi" + "Naprej" + "Dokončano" + "Pošlji" + "?123" + "123" + "ABC" + "ALT" + "Glasovni vnos" + "Glasovni vnos trenutno ni podprt v vašem jeziku, deluje pa v angleščini." + "Glasovni vnos je poskusna funkcija, ki uporablja Googlovo omrežno prepoznavanje govora." + "Če želite izklopiti glasovni vnos, pojdite na nastavitve tipkovnice." + "Če želite uporabiti glasovni vnos, pritisnite gumb z mikrofonom ali podrsajte s prstom po zaslonski tipkovnici." + "Začnite govoriti" + "Obdelava" + + "Napaka. Poskusite znova." + "Povezava ni mogoča" + "Napaka, preveč govora." + "Težave z zvokom" + "Napaka strežnika" + "Govora se ne sliši" + "Ni rezultatov" + "Glasovno iskanje ni nameščeno" + "Nasvet:"" za govorjenje s prstom povlecite po tipkovnici" + "Nasvet:"" naslednjič poskusite ločila izgovoriti, npr. »pika«, »vejica« ali »vprašaj«." + "Prekliči" + "V redu" + "Glasovni vnos" + + "Na glavni tipkovnici" + "Na tipkovnici s simboli" + "Izklopljeno" + + + "Mikrofon na glavni tipkovnici" + "Mikrofon na tipkovnici s simboli" + "Glasovni vnos je onemogočen" + + "Samodejno pošlji po govoru" + "Samodejno pritisni »Enter« pri iskanju ali prehodu na naslednje polje." + "Odprite tipkovnico"\n\n"Dotaknite se katerega koli besedilnega polja." + "Zaprite tipkovnico"\n\n"Pritisnite tipko »Nazaj«." + "Pridržite tipko za ogled možnosti"\n\n"Dostop do ločil in poudarkov." + "Nastavitve "\n\n"Pridržite tipko ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Izberite način vnosa" + "Jeziki vnosa" + "Podrsajte s prstom po preslednici, da zamenjate jezik" + "← Še enkrat se dotaknite, da shranite" + "Slovar je na voljo" + "Omogoči povratne informacije uporabnikov" + "S samodejnim pošiljanjem statističnih podatkov o uporabi in poročil o zrušitvah Googlu nam lahko pomagate izboljšati urejevalnik načina vnosa." + "Dotaknite se besed in jih popravite" + "Dotaknite se vnesenih besed in jih popravite" + "Tema tipkovnice" + "tipkovnica" + "govor" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-sr/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-sr/strings.xml new file mode 100644 index 00000000..7b00501a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-sr/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android тастатура" + "Подешавања Android тастатуре" + "Опције уноса" + "Вибрирај на притисак тастера" + "Звук на притисак тастера" + "Искачући прозор приликом притиска тастера" + "Исправи грешке у куцању" + "Омогућавање исправљања грешака током уноса" + "Грешке приликом уноса у положеном приказу" + "Омогућавање исправљања грешака током уноса" + "Предлагање речи" + "Аутоматско исправљање претходне речи" + "Предлагање речи" + "Подешавања за предлагање речи" + "Омогућавање аутоматског довршавања током уноса текста" + "Аутоматско довршавање" + "Повећај величину поља за текст" + "Скривање предложених речи у положеном приказу" + "Аутоматски унос великих слова" + "Унос великог слова на почетку реченице" + "Аутоматска интерпункција" + + "Брзе исправке" + "Исправља честе грешке у куцању" + "Прикажи предлоге" + "Приказивање предложених речи током уноса текста" + "Аутоматско довршавање" + "Означена реч се аутоматски умеће када притиснете размак или знак интерпункције" + "Прикажи тастер за подешавања" + "Аутоматски" + "Увек прикажи" + "Увек сакриј" + + + + "Bigram предлози" + "Користи претходну реч за побољшање предлога" + + "Ништа" + "Основни" + "Напредно" + + "%s : Сачувано" + "Држите тастер да бисте видели акценте (ø, ö итд.)" + "Притисните тастер „Назад“ ↶ у било ком тренутку да бисте затворили тастатуру" + "Приступите бројевима и симболима" + "Притисните и држите прву реч са леве стране да бисте је додали у речник" + "Додирните овај савет да бисте наставили »" + "Додирните овде да бисте затворили овај савет и почели да уносите текст!" + "Тастатура се отвара сваки пут када додирнете поље за текст" + "Додирните и држите тастер да бисте видели акценте"\n"(ø, ö, ô, ó, и тако даље)" + "Пређите на бројеве и симболе тако што ћете додирнути овај тастер" + "Вратите се на слова тако што ћете поново додирнути овај тастер" + "Додирните и држите овај тастер да бисте променили подешавања тастатуре, као што је аутоматско довршавање" + "Пробајте!" + "Иди" + "Следеће" + "Готово" + "Пошаљи" + "?123" + "123" + "ABC" + "ALT" + "Гласовни унос" + "Гласовни унос тренутно није подржан за ваш језик, али функционише на енглеском." + "Гласовни унос је експериментална функција која користи Google-ово мрежно препознавање гласа." + "Да бисте искључили гласовни унос, идите на подешавања тастатуре." + "Да бисте користили гласовни унос, притисните дугме за микрофон или превуците прст преко тастатуре на екрану." + "Говорите сада" + "Обрада" + + "Грешка. Покушајте поново." + "Повезивање није могуће" + "Грешка, говорите предуго." + "Проблем са звуком" + "Грешка сервера" + "Не чује се говор" + "Нема подударања" + "Гласовна претрага није инсталирана" + "Савет:"" Превуците прстом преко тастатуре за гласовни унос" + "Савет:"" Следећи пут покушајте да изговорите знакове интерпункције као што су „тачка“, „зарез“ или „знак питања“." + "Откажи" + "Потврди" + "Гласовни унос" + + "На главној тастатури" + "На тастатури са симболима" + "Искључено" + + + "Микрофон на главној тастатури" + "Микрофон на тастатури са симболима" + "Гласовни унос је онемогућен" + + "Аутоматски пошаљи после гласа" + "Аутоматски притисак на enter приликом претраге или преласка на следеће поље." + "Активирање тастатуре"\n\n"Додирните било које поље за текст." + "Затварање тастатуре"\n\n"Притисните тастер „Назад“." + "Додирните и држите тастер да би се приказале опције"\n\n"Приступ знаковима интерпункције и акцентима." + "Подешавања тастатуре"\n\n"Додирните и држите тастер ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Изаберите метод уноса" + "Језици за унос" + "Превуците прст преко тастера за размак да бисте променили језик" + "← Поново додирните да бисте сачували" + "Речник је доступан" + "Омогући повратну информацију корисника" + "Помозите да се побољша овај уређивач режима уноса тако што ће се аутоматски послати статистика о коришћењу и извештаји о грешкама компанији Google." + "Додирните да бисте исправили речи" + "Додирните унете речи да бисте их исправили" + "Тема тастатуре" + "тастатура" + "глас" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-sv/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-sv/donottranslate-altchars.xml new file mode 100644 index 00000000..4d26e6c4 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-sv/donottranslate-altchars.xml @@ -0,0 +1,38 @@ + + + + áàâąã + 3éèêëę€ + íìîï8 + óòôõ9 + úùûū7 + śšşß + ńñň + çćč + ýÿü6 + ðď + ř4 + ťþ5 + źžż + ł + w + æ + øœ + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-sv/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-sv/strings.xml new file mode 100644 index 00000000..c736418f --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-sv/strings.xml @@ -0,0 +1,140 @@ + + + + + "Androids tangentbord" + "Inställningar för Androids tangentbord" + "Inmatningsalternativ" + "Vibrera vid tangenttryck" + "Knappljud" + "Popup vid knapptryck" + "Rätta skrivfel" + "Aktivera rättning av felaktiga inmatningar" + "Inmatningsfel i liggande vy" + "Aktivera rättning av felaktiga inmatningar" + "Ordförslag" + "Rätta automatiskt föregående ord" + "Ordförslag" + "Inställningar för ordförslag" + "Aktivera Komplettera automatiskt när du skriver" + "Komplettera automatiskt" + "Gör textfältet större" + "Dölj ordförslag i liggande vy" + "Automatiska versaler" + "Använd versal i början av mening" + "Automatiska punkter" + + "Snabba lösningar" + "Åtgärdar automatiskt vanliga misstag" + "Visa förslag" + "Visar ordförslag när du skriver" + "Komplettera automatiskt" + "Blanksteg och punkt infogar automatiskt markerat ord" + "Visa inställningsknapp" + "Automatiskt" + "Visa alltid" + "Dölj alltid" + + + + "Bigramförslag" + "Förbättra förslaget med föregående ord" + + "Inget" + "Grundinställningar" + "Avancerade" + + "%s: sparat" + "Håll nere en tangent om du vill visa accenter (ø, ö, etc.)" + "Tryck på Tillbaka ↶ om du vill stänga tangentbordet" + "För siffror och symboler" + "Tryck och håll ned ordet längst till vänster om du vill lägga till det i ordlistan" + "Tryck på tipset för att fortsätta »" + "Tryck här om du vill stänga tipset och börja skriva!" + "Tangentbordet öppnas när du trycker på ett textfält" + "Tryck och håll nere en tangent om du vill visa accenter"\n"(ø, ö, ô, ó och så vidare)" + "Växla till siffror och symboler med den här tangenten" + "Återvänd till bokstäver genom att trycka på tangenten en gång till" + "Tryck och håll ned tangenten om du vill ändra inställningarna för tangentbordet, till exempel Komplettera automatiskt" + "Testa!" + "Kör" + "Nästa" + "Färdig" + "Skicka" + "?123" + "123" + "ABC" + "ALT" + "Röstindata" + "Röstindata stöds inte på ditt språk än, men tjänsten fungerar på engelska." + "Röstinmatning är en funktion på experimentstadiet som använder Googles nätverks taligenkänning." + "Om du vill stänga av röstindata öppnar du inställningarna för tangentbordet." + "Om du vill använda röstinmatning trycker du på mikrofonknappen eller drar fingret över tangentbordet på skärmen." + "Tala nu" + "Fungerar" + + "Fel. Försök igen." + "Det gick inte att ansluta" + "Fel, för mycket tal." + "Ljudproblem" + "Serverfel" + "Hörde inget tal" + "Inga träffar hittades" + "Voice Search är inte installerat" + "Tips!"" Dra över tangentbordet om du vill tala" + "Tips!"" Nästa gång testar du att säga skiljetecknen, som \"punkt\", \"komma\" eller \"frågetecken\"." + "Avbryt" + "OK" + "Röstindata" + + "På huvudtangentbordet" + "På symboltangentbordet" + "Av" + + + "Mikrofon på huvudtangentbordet" + "Mikrofon på symboltangentbordet" + "Röstindata är inaktiverat" + + "Skicka automatiskt efter röst" + "Tryck automatiskt på retur vid sökning eller när du fortsätter till nästa fält." + "Öppna tangentbordet"\n\n"Tryck på ett textfält." + "Stäng tangentbordet"\n\n"Tryck på Tillbaka." + "Tryck länge på en tangent om du vill se alternativ"\n\n"Använda skiljetecken och accenter." + "Tangentbordsinställningar"\n\n"Tryck länge på tangenten""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Välj inmatningsmetod" + "Inmatningsspråk" + "Dra med fingret på blanksteg om du vill ändra språk" + "← Tryck igen för att spara" + "En ordlista är tillgänglig" + "Aktivera synpunkter från användare" + "Du kan hjälpa till att förbättra inmatningsmetoden genom att automatiskt skicka användningsstatistik och felrapporter till Google." + "Tryck om du vill korrigera ord" + "Tryck på skrivna ord om du vill korrigera dem" + "Tangentbordstema" + "tangentbord" + "röst" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-th/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-th/strings.xml new file mode 100644 index 00000000..0812a894 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-th/strings.xml @@ -0,0 +1,140 @@ + + + + + "แป้นพิมพ์ Android" + "การตั้งค่าแป้นพิมพ์ Android" + "ตัวเลือกการป้อนข้อมูล" + "สั่นเมื่อกดปุ่ม" + "ส่งเสียงเมื่อกดปุ่ม" + "ป๊อปอัปเมื่อกดแป้น" + "แก้ไขข้อผิดพลาดในการพิมพ์" + "เปิดการใช้งานการแก้ไขข้อผิดพลาดในการป้อนข้อมูล" + "ข้อผิดพลาดในการป้อนข้อมูลแนวนอน" + "เปิดการใช้งานการแก้ไขข้อผิดพลาดในการป้อนข้อมูล" + "การแนะนำคำ" + "แก้ไขคำก่อนหน้าอัตโนมัติ" + "การแนะนำคำ" + "การตั้งค่าการแนะนำคำ" + "เปิดใช้งานการเติมคำอัตโนมัติขณะพิมพ์" + "เติมคำอัตโนมัติ" + "เพิ่มขนาดฟิลด์ข้อความ" + "ซ่อนการแนะนำคำในมุมมองแนวนอน" + "ปรับเป็นตัวพิมพ์ใหญ่อัตโนมัติ" + "ใช้ตัวพิมพ์ใหญ่เมื่อขึ้นต้นประโยค" + "ใส่เครื่องหมายวรรคตอนอัตโนมัติ" + + "แก้ไขด่วน" + "แก้ไขข้อผิดพลาดในการพิมพ์ที่พบบ่อย" + "แสดงคำแนะนำ" + "แสดงคำที่แนะนำขณะพิมพ์" + "เติมคำอัตโนมัติ" + "ใช้แป้นเคาะวรรคและเครื่องหมายวรรคตอนเพื่อแทรกคำที่ไฮไลต์โดยอัตโนมัติ" + "แสดงแป้นการตั้งค่า" + "อัตโนมัติ" + "แสดงตลอดเวลา" + "ซ่อนตลอดเวลา" + + + + "คำแนะนำ Bigram" + "ใช้คำก่อนหน้านี้เพื่อปรับปรุงคำแนะนำ" + + "ไม่มี" + "พื้นฐาน" + "ขั้นสูง" + + "%s : บันทึกแล้ว" + "กดปุ่มค้างไว้เพื่อดูการออกเสียง (ø, ö, ฯลฯ)" + "กดปุ่ม ย้อนกลับ เพื่อปิดแป้นพิมพ์เมื่อใดก็ได้" + "เข้าถึงหมายเลขและสัญลักษณ์" + "กดคำซ้ายสุดค้างไว้เพื่อเพิ่มลงในพจนานุกรม" + "แตะคำแนะนำนี้เพื่อทำงานต่อ »" + "แตะที่นี่เพื่อปิดคำแนะนำนี้และเริ่มพิมพ์!" + "แป้นพิมพ์จะเปิดขึ้นเมื่อคุณแตะฟิลด์ข้อความ" + "แตะปุ่มค้างไว้เพื่อดูการออกเสียง"\n"(ø, ö, ô, ó และอื่นๆ)" + "เปลี่ยนเป็นตัวเลขและสัญลักษณ์เมื่อแตะปุ่มนี้" + "กลับไปที่ตัวอักษรโดยการแตะปุ่มนี้อีกครั้ง" + "แตะปุ่มนี้ค้างไว้เพื่อเปลี่ยนการตั้งค่าแป้นพิมพ์ เช่น การเติมคำอัตโนมัติ" + "ลองดูสิ!" + "ไป" + "ถัดไป" + "เสร็จสิ้น" + "ส่ง" + "?123" + "123" + "ABC" + "ALT" + "การป้อนข้อมูลด้วยเสียง" + "ขณะนี้การป้อนข้อมูลด้วยเสียงยังไม่ได้รับการสนับสนุนในภาษาของคุณ แต่ใช้ได้ในภาษาอังกฤษ" + "การป้อนข้อมูลด้วยเสียงเป็นคุณลักษณะทดลองที่ใช้การจดจำเสียงที่มีการสร้างเครือข่ายไว้ของ Google" + "หากต้องการปิดการป้อนข้อมูลด้วยเสียง ไปที่การตั้งค่าแป้นพิมพ์" + "หากต้องการใช้การป้อนข้อมูลด้วยเสียง กดปุ่มไมโครโฟนหรือเลื่อนนิ้วผ่านแป้นพิมพ์บนหน้าจอ" + "พูดได้เลย" + "กำลังทำงาน" + + "ข้อผิดพลาด โปรดลองอีกครั้ง" + "ไม่สามารถเชื่อมต่อได้" + "ข้อผิดพลาด คำพูดยาวเกินไป" + "ปัญหาด้านเสียง" + "ข้อผิดพลาดของเซิร์ฟเวอร์" + "ไม่ได้ยินเสียง" + "ไม่พบรายการที่ตรงกัน" + "ไม่ได้ติดตั้ง Voice Search" + "คำแนะนำ:"" กวาดผ่านแป้นพิมพ์เพื่อพูด" + "คำแนะนำ:"" ครั้งต่อไป ให้ลองเอ่ยถึงเครื่องหมายวรรคตอน เช่น \"มหัพภาค\" \"จุลภาค\" หรือ \"เครื่องหมายคำถาม\"" + "ยกเลิก" + "ตกลง" + "การป้อนข้อมูลด้วยเสียง" + + "บนแป้นพิมพ์หลัก" + "บนแป้นพิมพ์สัญลักษณ์" + "ปิด" + + + "ไมโครโฟนบนแป้นพิมพ์หลัก" + "ไมโครโฟนบนแป้นพิมพ์สัญลักษณ์" + "การป้อนข้อมูลด้วยเสียงถูกปิดการใช้งาน" + + "ส่งอัตโนมัติหลังบันทึกเสียง" + "กด Enter อัตโนมัติเมื่อค้นหาหรือไปที่ฟิลด์ถัดไป" + "เปิดแป้นพิมพ์"\n\n"แตะฟิลด์ข้อความใดก็ได้" + "ปิดแป้นพิมพ์"\n\n"กดปุ่ม ย้อนกลับ" + "แตะปุ่มค้างไว้เพื่อดูตัวเลือก "\n\n"เข้าถึงเครื่องหมายวรรคตอนและการออกเสียง" + "การตั้งค่าแป้นพิมพ์"\n\n"แตะปุ่ม ""?123""ค้างไว้" + ".com" + ".net" + ".org" + ".gov" + ".edu" + "เลือกวิธีการป้อนข้อมูล" + "ภาษาในการป้อนข้อมูล" + "เลื่อนนิ้วไปบนแป้นเคาะวรรคเพื่อเปลี่ยนภาษา" + "← แตะอีกครั้งเพื่อบันทึก" + "มีพจนานุกรมให้ใช้งาน" + "เปิดใช้งานการแสดงความคิดเห็นจากผู้ใช้" + "ช่วยปรับปรุงตัวแก้ไขวิธีการป้อนข้อมูลนี้โดยการส่งสถิติการใช้งานและรายงานการขัดข้องถึง Google โดยอัตโนมัติ" + "แตะเพื่อแก้ไขคำ" + "แตะคำที่ป้อนไว้เพื่อแก้ไข" + "ชุดรูปแบบแป้นพิมพ์" + "แป้นพิมพ์" + "เสียง" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-tl/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-tl/strings.xml new file mode 100644 index 00000000..d2c25d87 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-tl/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android keyboard" + "Mga setting ng Android keyboard" + "Mga pagpipilian sa input" + "Mag-vibrate sa keypress" + "Tunog sa keypress" + "Popup sa keypress" + "Itama ang mga error sa pag-type" + "Paganahin ang pagtatama ng error sa pag-input" + "Mga error sa pag-input ng landscape" + "Paganahin ang pagtatama ng error sa pag-input" + "Mga suhestiyon ng salita" + "Awtomatikong itama ang nakaraang salita" + "Mga suhestiyon ng salita" + "Mga setting ng suhestiyon ng salita" + "Paganahin ang awtomatikong pagkumpleto habang nagta-type" + "Awtomatikong pagkumpleto" + "Taasan ang laki ng field ng teksto" + "Itago ang mga suhestiyon ng salita sa lanscape na view" + "Auto-capitalization" + "I-capitalize ang simula ng isang pangungusap" + "I-auto-punctuate" + + "Mga mabilisang pagsasaayos" + "Itinatama ang mga karaniwang na-type na mali" + "Ipakita ang mga suhestiyon" + "Ipakita ang mga iminumungkahing salita habang nagta-type" + "I-auto-complete" + "Awtomatikong ipinapasok ng spacebar at bantas ang naka-highlight na salita" + "Ipakita ang key ng mga setting" + "Awtomatiko" + "Palaging ipakita" + "Palaging itago" + + + + "Mga Suhestiyon na Bigram" + "Gamitin ang nakaraang salita upang pahusayin ang suhestiyon" + + "Wala" + "Batayan" + "Advanced" + + "%s : Na-save" + "Pinduting nang matagal ang isang key pababa upang makita ang mga accent (ø, ö, atbp.)" + "Pindutin ang key na bumalik ↶ upang isara ang keyboard anumang oras" + "I-access ang mga numero at simbolo" + "Pindutin nang matagal ang salita sa kaliwang bahagi upang idagdag ito sa diksyunaryo" + "Galawin ang pahiwatig na ito upang magpatuloy »" + "Galawin dito upang isara ang pahiwatig na ito at simulan ang pag-type!" + "Nagbubukas ang keyboard anumang oras na galawin mo ang field ng teksto" + "Galawin & pinduting nang matagal ang isang key upang tingnan ang mga accent"\n"(ø, ö, ô, ó, at iba pa)" + "Lumipat sa mga numero at simbolo sa pamamagitan ng paggalaw sa key na "" na ito" + "Pumunta muli sa mga titik sa pamamagitan ng muling paggalaw sa key na ito" + "Galawin & pinduting nang matagal ang key na ito upang baguhin ang mga setting ng keyboard, tulad ng awtomatikong pagkumpleto" + "Subukan ito!" + "Punta" + "Susunod" + "Tapos na" + "Ipadala" + "?123" + "123" + "ABC" + "ALT" + "Pag-input ng boses" + "Hindi kasalukuyang suportado ang pag-input ng boses para sa iyong wika, ngunit gumagana sa Ingles." + "Ang pag-input ng boses ay isang tampok na pang-eksperimento na gumagamit ng naka-network na pagkilala sa pananalita ng Google." + "Upang i-off ang pag-input ng boses, pumunta sa mga setting ng keyboard." + "Upang gumamit ng pag-input ng boses, pindutin ang pindutang microphone o i-slide ang iyong daliri sa screen keyboard." + "Magsalita ngayon" + "Nagtatrabaho" + + "Error. Pakisubukang muli." + "Hindi makakonekta" + "Error, masyadong maraming pananalita." + "Problema sa audio" + "Error sa server" + "Walang narinig na pananalita" + "Walang nakitang mga tugma" + "Hindi naka-install ang paghahanap ng boses" + "Pahiwatig:"" Mag-swipe sa keyboard upang magsalita" + "Pahiwatig:"" Sa susunod, subukang magsalita ng bantas tulad ng \"tuldok\", \"kuwit\", o \"tandang pananong\"." + "Kanselahin" + "OK" + "Pag-input ng boses" + + "I-on ang pangunahing keyboard" + "Sa mga simbolo ng keyboard" + "Naka-off" + + + "Mic sa pangunahing keyboard" + "Mic sa keyboard ng mga simbolo" + "Hindi pinagana ang pag-input ng boses" + + "Awtomatikong isumite pagkatapos ng boses" + "Awtomatikong pindutin ang enter kapag naghahanap o pupunta sa susunod na field." + "Buksan ang keyboard"\n\n"Galawin ang kahit anong field ng teksto." + "Isara ang keyboard"\n\n"Pindutin ang key na Bumalik." + "Galawin & pinduting nang matagal ang isang key para sa mga pagpipilian"\n\n"I-access ang bantas at mga accent." + "Mga setting ng keyboard"\n\n"Galawin & pindutin nang matagal ang ""?123"" na key." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Pumili ng paraan ng pag-input" + "Mag-input ng mga wika" + "I-slide ang daliri sa spacebar upang palitan ang wika" + "← Pinduting muli upang i-save" + "Available ang diksyunaryo" + "Paganahin ang feedback ng user" + "Tumulong na pahusayin ang editor ng paraan ng pag-input na ito sa pamamagitan ng awtomatikong pagpapadala ng mga istatistika ng paggamit at mga ulat ng crash sa Google." + "Pindutin upang itama ang mga salita" + "Pindutin ang mga ipinasok na salita upang itama ang mga ito" + "Tema ng Keyboard" + "keyboard" + "boses" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-tr/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-tr/donottranslate-altchars.xml new file mode 100644 index 00000000..fb2419c1 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-tr/donottranslate-altchars.xml @@ -0,0 +1,31 @@ + + + + â + 3 + īįíìïîı8 + ōøõóòœôö9 + ūúùûü7 + śşßš + + čćç + 6 + ğ + \ No newline at end of file diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-tr/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-tr/strings.xml new file mode 100644 index 00000000..9248ac4f --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-tr/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android klavyesi" + "Android klavye ayarları" + "Giriş seçenekleri" + "Tuşa basıldığında titret" + "Tuşa basıldığında ses çıkar" + "Tuşa basıldığında pop-up aç" + "Yazım hatalarını düzelt" + "Giriş hatası düzeltmeyi etkinleştir" + "Yatay giriş hataları" + "Giriş hatası düzeltmeyi etkinleştir" + "Kelime önerileri" + "Önceki kelimeyi otomatik olarak düzelt" + "Kelime önerileri" + "Kelime önerme ayarları" + "Yazarken otomatik tamamlamayı etkinleştir" + "Otomatik tamamlama" + "Metin alanı boyutunu artır" + "Yatay görünümde kelime önerilerini gizle" + "Otomatik olarak büyük harf yap" + "Cümlenin baş harfini büyük yap" + "Otomatik noktalama" + + "Hızlı onarımlar" + "Yaygın olarak yapılan yazım hatalarını düzeltir" + "Önerileri göster" + "Yazarken önerilen kelimeleri görüntüle" + "Otomatik tamamla" + "Boşluk tuşu ve noktalama vurgulanan kelimeyi otomatik ekler" + "Ayarları göster tuşu" + "Otomatik" + "Her zaman göster" + "Her zaman gizle" + + + + "Bigram Önerileri" + "Öneriyi geliştirmek için önceki kelimeyi kullanın" + + "Yok" + "Temel" + "Gelişmiş" + + "%s : Kaydedildi" + "Vurguları görmek için bir tuşu basılı tutun (ø, ö, v.b.)" + "Klavyeyi herhangi bir anda kapatmak için geri tuşuna ↶ basın" + "Sayılara ve simgelere erişin" + "Sözlüğe eklemek için en soldaki kelimeye basın ve basılı tutun" + "Devam etmek için bu ipucuna dokunun »" + "Bu ipucunu kapatmak için buraya dokunun ve yazmaya başlayın!" + "Bir metin alanına dokunduğunuzda klavye açılır" + "Vurguları görüntülemek için bir tuşa basın ve basılı tutun"\n"(ø, ö, ô, ó v.b.)" + "Bu tuşa dokunarak sayılar ve simgeler arasında geçiş yap" + "Bu tuşa tekrar dokunarak harflere geri dönün" + "Otomatik tamamlama gibi klavye ayarlarını değiştirmek için bu tuşa basın ve basılı tutun" + "Deneyin!" + "Git" + "İleri" + "Bitti" + "Gönder" + "?123" + "123" + "ABC" + "ALT" + "Ses girişi" + "Ses girişi, şu anda sizin diliniz için desteklenmiyor ama İngilizce dilinde kullanılabilir." + "Ses girişi, Google\'ın ağ bağlantılı ses tanıma işlevini kullanan deneysel bir özelliktir." + "Ses girişini kapatmak için klavye ayarlarına gidin." + "Ses girişini kullanmak için mikrofon düğmesine basın veya parmağınızı dokunmatik klavye üzerinde kaydırın." + "Şimdi konuşun" + "Çalışıyor" + + "Hata. Lütfen tekrar deneyin." + "Bağlanamadı" + "Hata, çok uzun konuşma." + "Ses sorunu" + "Sunucu hatası" + "Konuşma duyulmadı" + "Eşleşme bulunamadı" + "Sesle arama yüklenmedi" + "İpucu:"" Konuşmak için parmağınızı klavye üzerinde kaydırın" + "İpucu:"" Sonraki sefer, \"nokta\", \"virgül\" veya \"soru işareti\" gibi noktalama işaretlerini telaffuz etmeyi deneyin." + "İptal" + "Tamam" + "Ses girişi" + + "Ana klavyede" + "Simge klavyesinde" + "Kapalı" + + + "Ana klavyedeki mikrofon" + "Simge klavyesindeki mikrofon" + "Sesle giriş devre dışı bırakıldı" + + "Sesten sonra otomatik gönder" + "Arama yaparken veya bir sonraki alana giderken enter tuşuna otomatik olarak basın." + "Klavyeyi açın"\n\n"Herhangi bir metin alanına dokunun." + "Klavyeyi kapatın"\n\n"Geri tuşuna basın." + "Seçenekler için bir tuşa dokunun ve basılı tutun"\n\n"Noktalama ve vurgulama işaretlerine erişin." + "Klavye ayarları"\n\n"?123"" tuşuna dokunun ve basılı tutun." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Giriş yöntemini seç" + "Giriş dilleri" + "Dili değiştirmek için parmağınızı boşluk çubuğu üzerinde kaydırın" + "← Kaydetmek için tekrar dokunun" + "Sözlük kullanılabilir" + "Kullanıcı geri bildirimini etkinleştir" + "Kullanım istatistiklerini ve kilitlenme raporlarını Google\'a otomatik olarak göndererek bu giriş yöntemi düzenleyicisinin iyileştirilmesine yardımcı olun." + "Kelimeleri düzeltmek için dokunun" + "Düzeltmek için, girilen kelimelere dokunun" + "Klavye Teması" + "klavye" + "ses" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-uk/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-uk/strings.xml new file mode 100644 index 00000000..8788021b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-uk/strings.xml @@ -0,0 +1,140 @@ + + + + + "Клавіатура Android" + "Налашт-ня клавіат. Android" + "Парам. введення" + "Вібр при натиску клав." + "Звук при натиску клав." + "Сплив. при нат.клав." + "Виправ. помилки вводу" + "Увімкн. виправл. помилок вводу" + "Помилки альбомного вводу" + "Увімкн. виправл. помилок вводу" + "Пропозиції слів" + "Автоматично виправляти попереднє слово" + "Пропозиції слів" + "Налашт-ня пропозицій слів" + "Увімкн. автозаповнення при вводі" + "Автозаповнення" + "Збільш. розмір текст. поля" + "Сховати пропозиції слів в альбом. режимі" + "Авто викор. вел. літер" + "Поч. писати речення з великої літери" + "Авто пунктуація" + + "Шв. виправлення" + "Виправляє поширені помилки" + "Показати пропозиції" + "Відображати при вводі пропоновані слова" + "Автозаповнення" + "Пробіл і пунктуація автоматично вставляє виділене слово" + "Показ. клав. налашт." + "Автоматично" + "Завжди показ." + "Завжди ховати" + + + + "Двобуквені пропозиції" + "Викор. попер. слово для покращ. пропозиції" + + "Немає" + "Базовий" + "Розшир." + + "%s : збережено" + "Утр. клав. натис., щоб див. нагол. (ø, ö, тощо)" + "Натисн. клавішу назад ↶, щоб будь-коли закрити клавіат." + "Доступ до цифр і символів" + "Натисн. і утримуйте ліве крайнє слово, щоб додати його до словн." + "Натис. цю підказку для продовж.»" + "Натисн. тут, щоб закрити цю підказку і почати ввод." + "Клавіатура відривається при торканні текстового поля" + "Натис. і утрим. клавішу для перегл. наголосів"\n"(ø, ö, ô, ó тощо)" + "Перемк. до цифр і символів, натиснувши цю кнопку " + "Поверніться до літер, знову натиснувши цю клавішу" + "Натис. і утрим. клавішу, щоб змін. налашт-ння клавіат., такі як автозапов." + "Спробуйте!" + "Іти" + "Далі" + "Готово" + "Надісл." + "?123" + "123" + "ABC" + "ALT" + "Голос. ввід" + "Голос. ввід наразі не підтрим. для вашої мови, але можна користуватися англійською." + "Голос. ввід є експеремент. ф-цією, яка викор. мережеве розпізнавання голосу Google." + "Щоб вимкн. голос ввід, йдіть до налашт-нь клавіатури." + "Щоб викор. голос. ввід, натисніть кнопку мікрофона або пересуньте палець на екранній клавіатурі." + "Диктуйте" + "Працює" + + "Помилка. Спробуйте ще раз." + "Неможл. під\'єднатися" + "Помилка. Забагато продикт." + "Проблема з аудіо" + "Помилка сервера" + "Не чути диктув." + "Збігів не знайдено" + "Голос. пошук не встановлено" + "Підк:"" горт. на клавіат., щоб продикт." + "Підказка:"" наступного разу продикт. знаки пункт. такі як \"крапка\", \"кома\" чи \"знак пит\"." + "Скасувати" + "OK" + "Голос. ввід" + + "На осн. клавіатурі" + "Символьна клавіатура" + "Вимк." + + + "Miкр. на осн. клавіатурі" + "Miкр. на символ. клавіатурі" + "Голос. ввід вимкнуто" + + "Авто подав. після гол. пош." + "Автомат. натиск. enter під час пошуку або переходу до наступного поля." + "Відкр. клавіатуру"\n\n"Натисн. якесь текст. поле." + "Закрити клавіатуру"\n\n"Натисн. клавішу Назад." + "Натис.і утрим. клавішк для отрим. парам."\n\n"Доступ до пункт. та наголос." + "Налашт-ння клавіатури"\n\n"Натисн. і утрим. клавішу ""?123" + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Вибрати метод введення" + "Мови вводу" + "Переміст. палець на пробіл, щоб змін. мову" + "← Торкн. ще, щоб збер." + "Словник доступний" + "Увімк. відгуки корист." + "Допоможіть покращ. редактор методу введ., автомат. надсилаючи в Google статистику використ. та звіти про збої." + "Торкн., щоб виправ. слова" + "Торкн. введених слів, щоб виправити їх" + "Тема клавіатури" + "клавіатура" + "голос." + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-vi/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-vi/strings.xml new file mode 100644 index 00000000..53ec91c1 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-vi/strings.xml @@ -0,0 +1,140 @@ + + + + + "Bàn phím Android" + "Cài đặt bàn phím Android" + "Tùy chọn nhập" + "Rung khi nhấn phím" + "Âm thanh khi nhấn phím" + "Cửa sổ bật lên khi nhấn phím" + "Sửa lỗi đánh máy" + "Bật sửa lỗi nhập" + "Lỗi nhập theo khổ ngang" + "Bật sửa lỗi nhập" + "Đề xuất từ" + "Tự động sửa từ trước đó" + "Đề xuất từ" + "Cài đặt đề xuất từ" + "Bật tự động hoàn tất khi nhập" + "Tự động hoàn tất" + "Tăng kích cỡ trường văn bản" + "Ẩn đề xuất từ trong chế độ xem ngang" + "Tự động viết hoa" + "Viết hoa chữ cái đầu câu" + "Tự động chấm câu" + + "Sửa nhanh" + "Sửa lỗi nhập thông thường" + "Hiển thị đề xuất" + "Hiển thị từ được đề xuất khi nhập" + "Tự động hoàn tất" + "Dấu cách và dấu câu tự động chèn vào từ được đánh dấu" + "Hiển thị phím cài đặt" + "Tự động" + "Luôn hiển thị" + "Luôn ẩn" + + + + "Đề xuất Bigram" + "Sử dụng từ trước đó để cải tiến đề xuất" + + "Không" + "Cơ bản" + "Nâng cao" + + "%s : Đã lưu" + "Giữ phím xuống để xem dấu trọng âm (ø, ö, v.v...)" + "Nhấn phím quay lại ↶ để đóng bàn phím bất kỳ lúc nào" + "Truy cập các số và ký hiệu" + "Nhấn và giữ từ ngoài cùng bên trái để thêm từ đó vào từ điển" + "Chạm vào gợi ý này để tiếp tục »" + "Chạm vào đây để đóng gợi ý này và bắt đầu nhập" + "Bàn phím mở ra bất cứ khi nào bạn chạm vào trường văn bản" + "Chạm & giữ phím để xem dấu trọng âm"\n"(ø, ö, ô, ó, v.v...)" + "Chuyển sang số và ký hiệu bằng cách chạm vào phím này" + "Quay lại các chữ cái bằng cách chạm vào phím này lần nữa" + "Chạm & giữ phím này để thay đổi cài đặt bàn phím, như tự động hoàn tất" + "Hãy dùng thử!" + "Đến" + "Tiếp theo" + "Xong" + "Gửi" + "?123" + "123" + "ABC" + "ALT" + "Nhập liệu bằng giọng nói" + "Nhập liệu bằng giọng nói hiện không được hỗ trợ cho ngôn ngữ của bạn nhưng hoạt động với ngôn ngữ tiếng Anh." + "Nhập liệu bằng giọng nói là tính năng thử nghiệm sử dụng nhận dạng tiếng nói được kết nối mạng của Google." + "Để tắt nhập liệu bằng giọng nói, đi tới cài đặt bàn phím." + "Để sử dụng nhập liệu bằng giọng nói, hãy nhấn nút micrô hoặc trượt ngón tay trên bàn phím ảo." + "Xin mời nói" + "Đang hoạt động" + + "Lỗi. Vui lòng thử lại." + "Không thể kết nối" + "Lỗi, quá nhiều câu thoại." + "Sự cố âm thanh" + "Lỗi máy chủ" + "Không nghe thấy tiếng nói nào" + "Không tìm thấy kết quả phù hợp" + "Tìm kiếm bằng giọng nói chưa được cài đặt" + "Gợi ý:"" Trượt qua bàn phím để nói" + "Gợi ý:"" Lần tới, thử nói dấu câu như \"dấu chấm\", \"dấu phẩy\" hoặc \"dấu hỏi\"." + "Huỷ" + "OK" + "Nhập liệu bằng giọng nói" + + "Trên bàn phím chính" + "Trên bàn phím có biểu tượng" + "Tắt" + + + "Micrô trên bàn phím chính" + "Micrô trên bàn phím có biểu tượng" + "Nhập liệu bằng giọng nói đã bị vô hiệu hoá" + + "Tự động gửi sau thoại" + "Tự đông nhấn enter khi tìm kiếm hoặc đi tới trường tiếp theo." + "Mở bàn phím"\n\n"Chạm vào bất kỳ trường văn bản nào." + "Đóng bàn phím"\n\n"Nhấn phím Quay lại." + "Chạm & giữ phím cho các tuỳ chọn"\n\n"Truy cập dấu câu và dấu trọng âm." + "Cài đặt bàn phím"\n\n"Chạm & giữ phím ""?123""." + ".com" + ".net" + ".org" + ".gov" + ".edu" + "Chọn phương thức nhập" + "Ngôn ngữ nhập" + "Trượt ngón tay trên phím cách để thay đổi ngôn ngữ" + "← Chạm lại để lưu" + "Có sẵn từ điển" + "Bật phản hồi của người dùng" + "Giúp nâng cao trình chỉnh sửa phương thức nhập này bằng cách tự động gửi thống kê sử dụng và báo cáo sự cố cho Google." + "Chạm để sửa từ" + "Chạm các từ đã nhập để sửa" + "Chủ đề bàn phím" + "bàn phím" + "thoại" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-zh-rCN/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rCN/donottranslate-altchars.xml new file mode 100644 index 00000000..c165b11c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rCN/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + èéêë + ìíîï + òóôõöœø + ùúûü + §ß + ñ + ç + ýÿ + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-zh-rCN/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rCN/strings.xml new file mode 100644 index 00000000..9e8df756 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rCN/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android 键盘" + "Android 键盘设置" + "输入选项" + "按键时振动" + "按键时播放音效" + "按键时显示弹出窗口" + "纠正输入错误" + "启用输入错误纠正功能" + "横向输入错误" + "启用输入错误纠正功能" + "字词建议" + "自动纠正前面的字词" + "字词建议" + "字词建议设置" + "输入时启用自动填写功能" + "自动完成" + "扩大文字字段" + "在横向视图中隐藏字词建议" + "自动大写" + "句首字母大写" + "自动加标点" + + "快速纠正" + "纠正常见的输入错误" + "显示建议" + "输入时启用联想提示" + "自动填写" + "按空格键和标点符号时自动插入突出显示的字词" + "显示设置键" + "自动" + "始终显示" + "始终隐藏" + + + + "双连词建议" + "使用以前的字词改进建议" + + "无" + "基本模式" + "高级" + + "%s:已保存" + "按住某个键可看到重音符号(例如 ø、ö 等)" + "随时可以通过按后退键 ↶ 关闭键盘" + "访问数字和符号" + "长按最左侧的字可将其添加到词典中" + "轻触此提示继续 »" + "轻触此处可关闭该提示,然后便可开始输入内容!" + "您可以随时通过触摸文字字段打开键盘" + "轻触并按住某个键可以查看重音符号"\n"(ø、ö、ô、ó 等)" + "轻触该键即可切换到数字和符号键盘" + "再次轻触该键即可返回字母键盘" + "触摸并按住该键可更改键盘设置,例如自动完成" + "试试吧!" + "开始" + "下一步" + "完成" + "发送" + "?123" + "123" + "ABC" + "ALT" + "语音输入" + "语音输入功能当前还不支持您的语言,您只能输入英语语音。" + "语音输入是一项试验性的功能,它采用了 Google 的网络语音识别功能。" + "要关闭语音输入功能,请转至键盘设置。" + "要使用语音输入,请按麦克风按钮或者在屏幕键盘上滑动手指。" + "请开始说话" + "正在处理" + + "出错,请重试。" + "无法连接" + "出错,语音过长。" + "音频问题" + "服务器出错" + "未听到语音" + "未找到匹配项" + "未安装语音搜索" + "提示:""在键盘上滑动手指可激活语音功能" + "提示:""稍后,请尝试使用语音输入标点符号,如“句号”、“逗号”或“问号”。" + "取消" + "确定" + "语音输入" + + "主键盘上" + "符号键盘上" + "关" + + + "主键盘上的麦克风" + "符号键盘上的麦克风" + "已停用语音输入" + + "语音结束后自动提交" + "搜索或转到下一字段时自动按 Enter。" + "打开键盘"\n\n"触摸任意文本字段。" + "关闭键盘"\n\n"按“返回”键。" + "触摸并按住选项键"\n\n"进入标点/重音符号界面。" + "键盘设置"\n\n"触摸并按住 ""?123"" 键。" + ".com" + ".net" + ".org" + ".gov" + ".edu" + "选择输入法" + "输入语言" + "在空格键上滑动手指可更改语言" + "← 再次触摸即可保存" + "提供字典" + "启用用户反馈" + "自动向 Google 发送使用情况统计信息和崩溃报告,帮助改进该输入法编辑器。" + "触摸以更正字词" + "触摸所输入字词以进行更正" + "键盘主题" + "键盘" + "语音" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-zh-rTW/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rTW/donottranslate-altchars.xml new file mode 100644 index 00000000..c165b11c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rTW/donottranslate-altchars.xml @@ -0,0 +1,30 @@ + + + + àáâãäåæ + èéêë + ìíîï + òóôõöœø + ùúûü + §ß + ñ + ç + ýÿ + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values-zh-rTW/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rTW/strings.xml new file mode 100644 index 00000000..dd5996d2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values-zh-rTW/strings.xml @@ -0,0 +1,140 @@ + + + + + "Android 鍵盤" + "Android 鍵盤設定" + "輸入選項" + "按鍵時震動" + "按鍵時播放音效" + "按鍵時顯示彈出式視窗" + "修正輸入錯誤" + "啟用輸入錯誤修正功能" + "橫向輸入錯誤" + "啟用輸入錯誤修正功能" + "字詞建議" + "自動修正前一個字詞" + "字詞建議" + "字詞建議設定" + "輸入時啟用自動完成" + "自動完成" + "放大文字欄位大小" + "在橫向檢視模式中隱藏字詞建議" + "自動大寫" + "句首字母大寫" + "自動標點" + + "快速修正" + "修正一般打字錯誤" + "顯示建議" + "打字時顯示建議字詞" + "自動完成" + "在反白顯示的字詞處自動插入空白鍵和標點符號鍵盤" + "顯示設定金鑰" + "自動" + "一律顯示" + "永遠隱藏" + + + + "雙連詞建議" + "根據前一個字詞自動找出更適合的建議" + + "無" + "基本模式" + "進階模式" + + "%s:已儲存" + "按住按鍵可查看重音符號 (ø、ö 等)" + "隨時可以透過按後退鍵 ↶ 關閉鍵盤" + "使用數字和符號" + "按住最左邊的字詞,將其新增到字典中" + "輕觸此提示繼續 »" + "輕觸此處以關閉提示,並開始打字!" + "輕觸文字欄位時即會開啟鍵盤" + "輕觸並按住某個鍵即可查看聲調"\n"(ø、ö、ô、ó 等)" + "輕觸此鍵即可切換到數字和符號鍵盤" + "再次輕觸此鍵即可返回到字母鍵盤" + "輕觸並按住此鍵即可變更鍵盤設定,例如自動完成" + "試試看!" + "開始" + "繼續" + "完成" + "傳送" + "?123" + "123" + "ABC" + "ALT" + "語音輸入" + "語音輸入目前不支援您的語言,但是可以辨識英文。" + "語音輸入這項實驗功能運用了 Google 的網路語音辨識系統。" + "請前往鍵盤設定來關閉語音輸入。" + "如要使用語音輸入,按下 [麥克風] 按鈕,或將手指滑過螢幕小鍵盤即可。" + "請說話" + "辨識中" + + "發生錯誤,請再試一次。" + "無法連線" + "錯誤:語音內容過長。" + "音訊問題" + "伺服器錯誤" + "沒有聽到任何聲音" + "找不到相符的項目" + "未安裝語音搜尋" + "提示:""滑過鍵盤即可說話" + "提示:""下次可嘗試說出標點符號,例如「句號」、「逗號」或「問號」。" + "取消" + "確定" + "語音輸入" + + "於主鍵盤" + "符號鍵盤上" + "關閉" + + + "主鍵盤上的麥克風" + "符號鍵盤上的麥克風" + "已停用語音輸入" + + "說話後自動提交" + "搜尋或前往下一個欄位時自動按下輸入。" + "開啟鍵盤"\n\n"輕觸任何文字欄位。" + "關閉鍵盤"\n\n"按下 Back 鍵。" + \n"輕觸並按住按鍵開啟選項"\n"輸入標點與輕重音。" + "鍵盤設定"\n\n"輕觸並按住 ""?123"" 鍵。" + ".com" + ".net" + ".org" + ".gov" + ".edu" + "選取輸入法" + "輸入語言" + "以手指在空白鍵上滑動可變更語言" + "← 再次輕觸即可儲存" + "可使用字典" + "啟用使用者意見回饋" + "自動將使用統計資料和當機報告傳送給 Google,協助改善這個輸入法編輯器。" + "輕觸此處可修正字詞" + "輕觸輸入的字詞即可加以修正" + "鍵盤主題" + "鍵盤" + "語音" + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/attrs.xml b/src/java/KP2ASoftKeyboard2/java/res/values/attrs.xml new file mode 100644 index 00000000..995373e8 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/attrs.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/bools.xml b/src/java/KP2ASoftKeyboard2/java/res/values/bools.xml new file mode 100644 index 00000000..5a24e4c6 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/bools.xml @@ -0,0 +1,33 @@ + + + + + true + + false + + true + true + + true + true + true + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/colors.xml b/src/java/KP2ASoftKeyboard2/java/res/values/colors.xml new file mode 100644 index 00000000..0161589a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/colors.xml @@ -0,0 +1,32 @@ + + + + #FFFFFFFF + #FFFCAE00 + #FFFCAE00 + #00000000 + #80000000 + #80FFFFFF + #FFC0C0C0 + #A0000000 + #FFFFFFFF + #FFFFFFFF + #FF000000 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/config.xml b/src/java/KP2ASoftKeyboard2/java/res/values/config.xml new file mode 100644 index 00000000..edb6cd84 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/config.xml @@ -0,0 +1,32 @@ + + + + + 0 + 10 + 0 + 70 + 0 + 100 + 400 + 50 + 400 + 800 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/dimens.xml b/src/java/KP2ASoftKeyboard2/java/res/values/dimens.xml new file mode 100644 index 00000000..0c3b6ad2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/dimens.xml @@ -0,0 +1,50 @@ + + + + + + 0.290in + 0.035in + 0.325in + 0.06in + 22dip + 42dip + 63dip + 4dip + + 2.5in + 0.13in + 0.083in + 40sp + 0.000in + + 80sp + + + 0.553in + + -0.325in + 0.05in + + -0.05in + 0.3in + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/donottranslate-altchars.xml b/src/java/KP2ASoftKeyboard2/java/res/values/donottranslate-altchars.xml new file mode 100644 index 00000000..bba7282c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/donottranslate-altchars.xml @@ -0,0 +1,46 @@ + + + + àáâãäåæ + èéêë + ìíîï + òóôõöœø + ùúûü + §ß + ñ + ç + ýÿ + 1 + 2 + + 4 + 5 + + + + 0 + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/donottranslate.xml b/src/java/KP2ASoftKeyboard2/java/res/values/donottranslate.xml new file mode 100644 index 00000000..93660992 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/donottranslate.xml @@ -0,0 +1,35 @@ + + + + + .\u0009\u0020,;:!?\n()[]*&@{}/<>_+=|\u0022 + + .,!?) + + !?,\u0022\u0027:()-/@_ + + + + 0 + + 1 + + 2 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/durations.xml b/src/java/KP2ASoftKeyboard2/java/res/values/durations.xml new file mode 100644 index 00000000..92af68e3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/durations.xml @@ -0,0 +1,25 @@ + + + + + + 40 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/keycodes.xml b/src/java/KP2ASoftKeyboard2/java/res/values/keycodes.xml new file mode 100644 index 00000000..6149f9dc --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/keycodes.xml @@ -0,0 +1,33 @@ + + + + + 9 + 10 + 32 + -1 + -2 + -5 + + -100 + -102 + -103 + -200 + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/strings.xml b/src/java/KP2ASoftKeyboard2/java/res/values/strings.xml new file mode 100644 index 00000000..6644d222 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/strings.xml @@ -0,0 +1,379 @@ + + + + + Android keyboard + + Android keyboard settings + + Input options + + + Vibrate on keypress + + + Sound on keypress + + + Popup on keypress + + + Correct typing errors + + + Enable input error correction + + + Landscape input errors + + + Enable input error correction + + + Word suggestions + + + Automatically correct the previous word + + + Word suggestions + + Word suggestion settings + + Enable auto completion while typing + + + Auto completion + + + Increase text field size + + Hide word suggestions in landscape view + + + Auto-capitalization + + Capitalize the start of a sentence + + Auto-punctuate + + + + + Quick fixes + + Corrects commonly typed mistakes + + + Show suggestions + + Display suggested words while typing + + + Auto-complete + + Spacebar and punctuation automatically insert highlighted word + + + Show settings key + + + @string/settings_key_mode_auto + @string/settings_key_mode_always_show + @string/settings_key_mode_always_hide + + + Automatic + + Always show + + Always hide + + + @string/settings_key_mode_auto_name + @string/settings_key_mode_always_show_name + @string/settings_key_mode_always_hide_name + + + + Bigram Suggestions + + Use previous word to improve suggestion + + + + None + Basic + Advanced + + + + 0 + + 1 + + 2 + + + @string/prediction_none + @string/prediction_basic + @string/prediction_full + + + + %s : Saved + + + Hold a key down to see accents (ø, ö, etc.) + + Press the back key \u21B6 to close the keyboard at any point + + Access numbers and symbols + + Press and hold the left-most word to add it to the dictionary + + + + Touch this hint to continue » + + + Touch here to close this hint and start typing! + + + The keyboard opens any time you touch a text field + + + Touch & hold a key to view accents\n(ø, ö, ô, ó, and so on) + + + + Switch to numbers and symbols by touching this key + + + Go back to letters by touching this key again + + + Touch & hold this key to change keyboard settings, like auto complete + + + Try it! + + + + Go + + Next + + Done + + Send + + \?123 + + 123 + + ABC + + ALT + + + + + Voice input + + + Voice input is not currently supported for your language, but does work in English. + + + Voice input is an experimental feature using Google\'s networked speech recognition. + + + To turn off voice input, go to keyboard settings. + + + To use voice input, press the microphone button or slide your finger across the on-screen keyboard. + + + Speak now + + + Working + + + + + + Error. Please try again. + + + Couldn\'t connect + + + Error, too much speech. + + + Audio problem + + + Server error + + + No speech heard + + + No matches found + + + Voice search not installed + + + Hint: Swipe across keyboard to speak + + + Hint: Next time, try speaking punctuation like \"period\", \"comma\", or \"question mark\". + + + Cancel + + + OK + + + Voice input + + + + On main keyboard + On symbols keyboard + Off + + + + 0 + + 1 + + 2 + + + @string/voice_mode_main + @string/voice_mode_symbols + @string/voice_mode_off + + + + + Mic on main keyboard + Mic on symbols keyboard + Voice input is disabled + + + + Auto submit after voice + + + Automatically press enter when searching or going to the next field. + + + + Open the keyboard\n\nTouch any text field. + + + Close the keyboard\n\nPress the Back key. + + + Touch \u0026 hold a key for options\n\nAccess punctuation and accents. + + + Keyboard settings\n\nTouch \u0026 hold the \?123\ key. + + + ".com" + + ".net" + + ".org" + + ".gov" + + ".edu" + + + Select input method + + + Input languages + + Slide finger on spacebar to change language + + + \u2190 Touch again to save + + + Dictionary available + + + Enable user feedback + + Help improve this input method editor by automatically sending usage statistics and crash reports to Google. + + Touch to correct words + + Touch entered words to correct them + + + Keyboard Theme + Basic + Basic (High Contrast) + Stone (bold) + Stone (normal) + Gingerbread + + + @string/layout_basic + @string/layout_high_contrast + @string/layout_stone_normal + @string/layout_stone_bold + @string/layout_gingerbread + + + + 0 + 1 + 2 + 3 + 4 + + + keyboard + voice + + + Android keyboard Debug settings + Debug Mode + diff --git a/src/java/KP2ASoftKeyboard2/java/res/values/styles.xml b/src/java/KP2ASoftKeyboard2/java/res/values/styles.xml new file mode 100644 index 00000000..0372b07c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/values/styles.xml @@ -0,0 +1,44 @@ + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-da/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-da/kbd_qwerty.xml new file mode 100644 index 00000000..e2ec674f --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-da/kbd_qwerty.xml @@ -0,0 +1,536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-da/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-da/kbd_qwerty_black.xml new file mode 100644 index 00000000..50a57b93 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-da/kbd_qwerty_black.xml @@ -0,0 +1,478 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-de/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-de/kbd_qwerty.xml new file mode 100644 index 00000000..2d790f9a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-de/kbd_qwerty.xml @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-de/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-de/kbd_qwerty_black.xml new file mode 100644 index 00000000..01b5f6a3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-de/kbd_qwerty_black.xml @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-fr/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-fr/kbd_qwerty.xml new file mode 100644 index 00000000..d7615020 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-fr/kbd_qwerty.xml @@ -0,0 +1,516 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-fr/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-fr/kbd_qwerty_black.xml new file mode 100644 index 00000000..2f89a82a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-fr/kbd_qwerty_black.xml @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-iw/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-iw/kbd_qwerty.xml new file mode 100644 index 00000000..9a0c6c2e --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-iw/kbd_qwerty.xml @@ -0,0 +1,474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-iw/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-iw/kbd_qwerty_black.xml new file mode 100644 index 00000000..056d18b8 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-iw/kbd_qwerty_black.xml @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-nb/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-nb/kbd_qwerty.xml new file mode 100644 index 00000000..2a7df8ae --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-nb/kbd_qwerty.xml @@ -0,0 +1,536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-nb/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-nb/kbd_qwerty_black.xml new file mode 100644 index 00000000..24c29674 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-nb/kbd_qwerty_black.xml @@ -0,0 +1,478 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-ru/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-ru/kbd_qwerty.xml new file mode 100644 index 00000000..38f687e0 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-ru/kbd_qwerty.xml @@ -0,0 +1,514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-ru/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-ru/kbd_qwerty_black.xml new file mode 100644 index 00000000..63111144 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-ru/kbd_qwerty_black.xml @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-sr/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-sr/kbd_qwerty.xml new file mode 100644 index 00000000..c137b105 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-sr/kbd_qwerty.xml @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-sr/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-sr/kbd_qwerty_black.xml new file mode 100644 index 00000000..fec63804 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-sr/kbd_qwerty_black.xml @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-sv/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-sv/kbd_qwerty.xml new file mode 100644 index 00000000..9a367015 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-sv/kbd_qwerty.xml @@ -0,0 +1,537 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml-sv/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml-sv/kbd_qwerty_black.xml new file mode 100644 index 00000000..083040b3 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml-sv/kbd_qwerty_black.xml @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/dictionary.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/dictionary.xml new file mode 100644 index 00000000..7b770a8b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/dictionary.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone.xml new file mode 100644 index 00000000..10774c66 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_black.xml new file mode 100644 index 00000000..5afa9a19 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_black.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_symbols.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_symbols.xml new file mode 100644 index 00000000..4c928a8d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_symbols.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_symbols_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_symbols_black.xml new file mode 100644 index 00000000..4d686e14 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_phone_symbols_black.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_popup_narrow_template.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_popup_narrow_template.xml new file mode 100644 index 00000000..23c686e8 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_popup_narrow_template.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_popup_template.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_popup_template.xml new file mode 100644 index 00000000..a287be1f --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_popup_template.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_qwerty.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_qwerty.xml new file mode 100644 index 00000000..9173df6a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_qwerty.xml @@ -0,0 +1,505 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_qwerty_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_qwerty_black.xml new file mode 100644 index 00000000..167a3416 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_qwerty_black.xml @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols.xml new file mode 100644 index 00000000..91a3f9c0 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols.xml @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_black.xml new file mode 100644 index 00000000..95b92d31 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_black.xml @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_shift.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_shift.xml new file mode 100644 index 00000000..71697d68 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_shift.xml @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_shift_black.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_shift_black.xml new file mode 100644 index 00000000..bcaabda2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/kbd_symbols_shift_black.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/language_prefs.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/language_prefs.xml new file mode 100644 index 00000000..b7a4c07d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/language_prefs.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/method.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/method.xml new file mode 100644 index 00000000..3cf8d2dd --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/method.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_at.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_at.xml new file mode 100644 index 00000000..197eea44 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_at.xml @@ -0,0 +1,39 @@ + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_comma.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_comma.xml new file mode 100644 index 00000000..7666f4b6 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_comma.xml @@ -0,0 +1,39 @@ + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_domains.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_domains.xml new file mode 100644 index 00000000..4e9789ff --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_domains.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_mic.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_mic.xml new file mode 100644 index 00000000..5bbd7dfa --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_mic.xml @@ -0,0 +1,40 @@ + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_punctuation.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_punctuation.xml new file mode 100644 index 00000000..c429e38b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_punctuation.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_slash.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_slash.xml new file mode 100644 index 00000000..a38fde0e --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_slash.xml @@ -0,0 +1,39 @@ + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/popup_smileys.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_smileys.xml new file mode 100644 index 00000000..1a14e1df --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/popup_smileys.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/prefs.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/prefs.xml new file mode 100644 index 00000000..247f3bc5 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/prefs.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/res/xml/prefs_for_debug.xml b/src/java/KP2ASoftKeyboard2/java/res/xml/prefs_for_debug.xml new file mode 100644 index 00000000..8177d3c6 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/res/xml/prefs_for_debug.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/AutoDictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/AutoDictionary.java new file mode 100644 index 00000000..cb427a2c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/AutoDictionary.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import java.util.HashMap; +import java.util.Set; +import java.util.Map.Entry; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.os.AsyncTask; +import android.provider.BaseColumns; +import android.util.Log; + +/** + * Stores new words temporarily until they are promoted to the user dictionary + * for longevity. Words in the auto dictionary are used to determine if it's ok + * to accept a word that's not in the main or user dictionary. Using a new word + * repeatedly will promote it to the user dictionary. + */ +public class AutoDictionary extends ExpandableDictionary { + // Weight added to a user picking a new word from the suggestion strip + static final int FREQUENCY_FOR_PICKED = 3; + // Weight added to a user typing a new word that doesn't get corrected (or is reverted) + static final int FREQUENCY_FOR_TYPED = 1; + // A word that is frequently typed and gets promoted to the user dictionary, uses this + // frequency. + static final int FREQUENCY_FOR_AUTO_ADD = 250; + // If the user touches a typed word 2 times or more, it will become valid. + private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED; + // If the user touches a typed word 4 times or more, it will be added to the user dict. + private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED; + + private KP2AKeyboard mIme; + // Locale for which this auto dictionary is storing words + private String mLocale; + + private HashMap mPendingWrites = new HashMap(); + private final Object mPendingWritesLock = new Object(); + + private static final String DATABASE_NAME = "auto_dict.db"; + private static final int DATABASE_VERSION = 1; + + // These are the columns in the dictionary + // TODO: Consume less space by using a unique id for locale instead of the whole + // 2-5 character string. + private static final String COLUMN_ID = BaseColumns._ID; + private static final String COLUMN_WORD = "word"; + private static final String COLUMN_FREQUENCY = "freq"; + private static final String COLUMN_LOCALE = "locale"; + + /** Sort by descending order of frequency. */ + public static final String DEFAULT_SORT_ORDER = COLUMN_FREQUENCY + " DESC"; + + /** Name of the words table in the auto_dict.db */ + private static final String AUTODICT_TABLE_NAME = "words"; + + private static HashMap sDictProjectionMap; + + static { + sDictProjectionMap = new HashMap(); + sDictProjectionMap.put(COLUMN_ID, COLUMN_ID); + sDictProjectionMap.put(COLUMN_WORD, COLUMN_WORD); + sDictProjectionMap.put(COLUMN_FREQUENCY, COLUMN_FREQUENCY); + sDictProjectionMap.put(COLUMN_LOCALE, COLUMN_LOCALE); + } + + private static DatabaseHelper sOpenHelper = null; + + public AutoDictionary(Context context, KP2AKeyboard ime, String locale, int dicTypeId) { + super(context, dicTypeId); + mIme = ime; + mLocale = locale; + if (sOpenHelper == null) { + sOpenHelper = new DatabaseHelper(getContext()); + } + if (mLocale != null && mLocale.length() > 1) { + loadDictionary(); + } + } + + @Override + public boolean isValidWord(CharSequence word) { + final int frequency = getWordFrequency(word); + return frequency >= VALIDITY_THRESHOLD; + } + + @Override + public void close() { + flushPendingWrites(); + // Don't close the database as locale changes will require it to be reopened anyway + // Also, the database is written to somewhat frequently, so it needs to be kept alive + // throughout the life of the process. + // mOpenHelper.close(); + super.close(); + } + + @Override + public void loadDictionaryAsync() { + // Load the words that correspond to the current input locale + Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale }); + try { + if (cursor.moveToFirst()) { + int wordIndex = cursor.getColumnIndex(COLUMN_WORD); + int frequencyIndex = cursor.getColumnIndex(COLUMN_FREQUENCY); + while (!cursor.isAfterLast()) { + String word = cursor.getString(wordIndex); + int frequency = cursor.getInt(frequencyIndex); + // Safeguard against adding really long words. Stack may overflow due + // to recursive lookup + if (word.length() < getMaxWordLength()) { + super.addWord(word, frequency); + } + cursor.moveToNext(); + } + } + } finally { + cursor.close(); + } + } + + @Override + public void addWord(String word, int addFrequency) { + final int length = word.length(); + // Don't add very short or very long words. + if (length < 2 || length > getMaxWordLength()) return; + if (mIme.getCurrentWord().isAutoCapitalized()) { + // Remove caps before adding + word = Character.toLowerCase(word.charAt(0)) + word.substring(1); + } + int freq = getWordFrequency(word); + freq = freq < 0 ? addFrequency : freq + addFrequency; + super.addWord(word, freq); + + if (freq >= PROMOTION_THRESHOLD) { + mIme.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD); + freq = 0; + } + + synchronized (mPendingWritesLock) { + // Write a null frequency if it is to be deleted from the db + mPendingWrites.put(word, freq == 0 ? null : new Integer(freq)); + } + } + + /** + * Schedules a background thread to write any pending words to the database. + */ + public void flushPendingWrites() { + synchronized (mPendingWritesLock) { + // Nothing pending? Return + if (mPendingWrites.isEmpty()) return; + // Create a background thread to write the pending entries + new UpdateDbTask(getContext(), sOpenHelper, mPendingWrites, mLocale).execute(); + // Create a new map for writing new entries into while the old one is written to db + mPendingWrites = new HashMap(); + } + } + + /** + * This class helps open, create, and upgrade the database file. + */ + private static class DatabaseHelper extends SQLiteOpenHelper { + + DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + AUTODICT_TABLE_NAME + " (" + + COLUMN_ID + " INTEGER PRIMARY KEY," + + COLUMN_WORD + " TEXT," + + COLUMN_FREQUENCY + " INTEGER," + + COLUMN_LOCALE + " TEXT" + + ");"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w("AutoDictionary", "Upgrading database from version " + oldVersion + " to " + + newVersion + ", which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS " + AUTODICT_TABLE_NAME); + onCreate(db); + } + } + + private Cursor query(String selection, String[] selectionArgs) { + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + qb.setTables(AUTODICT_TABLE_NAME); + qb.setProjectionMap(sDictProjectionMap); + + // Get the database and run the query + SQLiteDatabase db = sOpenHelper.getReadableDatabase(); + Cursor c = qb.query(db, null, selection, selectionArgs, null, null, + DEFAULT_SORT_ORDER); + return c; + } + + /** + * Async task to write pending words to the database so that it stays in sync with + * the in-memory trie. + */ + private static class UpdateDbTask extends AsyncTask { + private final HashMap mMap; + private final DatabaseHelper mDbHelper; + private final String mLocale; + + public UpdateDbTask(Context context, DatabaseHelper openHelper, + HashMap pendingWrites, String locale) { + mMap = pendingWrites; + mLocale = locale; + mDbHelper = openHelper; + } + + @Override + protected Void doInBackground(Void... v) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + // Write all the entries to the db + Set> mEntries = mMap.entrySet(); + for (Entry entry : mEntries) { + Integer freq = entry.getValue(); + db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?", + new String[] { entry.getKey(), mLocale }); + if (freq != null) { + db.insert(AUTODICT_TABLE_NAME, null, + getContentValues(entry.getKey(), freq, mLocale)); + } + } + return null; + } + + private ContentValues getContentValues(String word, int frequency, String locale) { + ContentValues values = new ContentValues(4); + values.put(COLUMN_WORD, word); + values.put(COLUMN_FREQUENCY, frequency); + values.put(COLUMN_LOCALE, locale); + return values; + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/BinaryDictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/BinaryDictionary.java new file mode 100644 index 00000000..63184ad6 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/BinaryDictionary.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import java.io.InputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.Channels; +import java.util.Arrays; + +import android.content.Context; +import android.util.Log; + +/** + * Implements a static, compacted, binary dictionary of standard words. + */ +public class BinaryDictionary extends Dictionary { + + /** + * There is difference between what java and native code can handle. + * This value should only be used in BinaryDictionary.java + * It is necessary to keep it at this value because some languages e.g. German have + * really long words. + */ + protected static final int MAX_WORD_LENGTH = 48; + + private static final String TAG = "BinaryDictionary"; + private static final int MAX_ALTERNATIVES = 16; + private static final int MAX_WORDS = 18; + private static final int MAX_BIGRAMS = 60; + + private static final int TYPED_LETTER_MULTIPLIER = 2; + private static final boolean ENABLE_MISSED_CHARACTERS = true; + + private int mDicTypeId; + private int mNativeDict; + private int mDictLength; + private int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES]; + private char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; + private char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; + private int[] mFrequencies = new int[MAX_WORDS]; + private int[] mFrequencies_bigrams = new int[MAX_BIGRAMS]; + // Keep a reference to the native dict direct buffer in Java to avoid + // unexpected deallocation of the direct buffer. + private ByteBuffer mNativeDictDirectBuffer; + + static { + try { + System.loadLibrary("jni_latinime"); + } catch (UnsatisfiedLinkError ule) { + Log.e("BinaryDictionary", "Could not load native library jni_latinime"); + } + } + + /** + * Create a dictionary from a raw resource file + * @param context application context for reading resources + * @param resId the resource containing the raw binary dictionary + */ + public BinaryDictionary(Context context, int[] resId, int dicTypeId) { + if (resId != null && resId.length > 0 && resId[0] != 0) { + loadDictionary(context, resId); + } + mDicTypeId = dicTypeId; + } + + /** + * Create a dictionary from a byte buffer. This is used for testing. + * @param context application context for reading resources + * @param byteBuffer a ByteBuffer containing the binary dictionary + */ + public BinaryDictionary(Context context, ByteBuffer byteBuffer, int dicTypeId) { + if (byteBuffer != null) { + if (byteBuffer.isDirect()) { + mNativeDictDirectBuffer = byteBuffer; + } else { + mNativeDictDirectBuffer = ByteBuffer.allocateDirect(byteBuffer.capacity()); + byteBuffer.rewind(); + mNativeDictDirectBuffer.put(byteBuffer); + } + mDictLength = byteBuffer.capacity(); + mNativeDict = openNative(mNativeDictDirectBuffer, + TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER); + } + mDicTypeId = dicTypeId; + } + + private native int openNative(ByteBuffer bb, int typedLetterMultiplier, + int fullWordMultiplier); + private native void closeNative(int dict); + private native boolean isValidWordNative(int nativeData, char[] word, int wordLength); + private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize, + char[] outputChars, int[] frequencies, int maxWordLength, int maxWords, + int maxAlternatives, int skipPos, int[] nextLettersFrequencies, int nextLettersSize); + private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength, + int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies, + int maxWordLength, int maxBigrams, int maxAlternatives); + + private final void loadDictionary(Context context, int[] resId) { + InputStream[] is = null; + try { + // merging separated dictionary into one if dictionary is separated + int total = 0; + is = new InputStream[resId.length]; + for (int i = 0; i < resId.length; i++) { + is[i] = context.getResources().openRawResource(resId[i]); + total += is[i].available(); + } + + mNativeDictDirectBuffer = + ByteBuffer.allocateDirect(total).order(ByteOrder.nativeOrder()); + int got = 0; + for (int i = 0; i < resId.length; i++) { + got += Channels.newChannel(is[i]).read(mNativeDictDirectBuffer); + } + if (got != total) { + Log.e(TAG, "Read " + got + " bytes, expected " + total); + } else { + mNativeDict = openNative(mNativeDictDirectBuffer, + TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER); + mDictLength = total; + } + } catch (IOException e) { + Log.w(TAG, "No available memory for binary dictionary"); + } finally { + try { + if (is != null) { + for (int i = 0; i < is.length; i++) { + is[i].close(); + } + } + } catch (IOException e) { + Log.w(TAG, "Failed to close input stream"); + } + } + } + + + @Override + public void getBigrams(final WordComposer codes, final CharSequence previousWord, + final WordCallback callback, int[] nextLettersFrequencies) { + + char[] chars = previousWord.toString().toCharArray(); + Arrays.fill(mOutputChars_bigrams, (char) 0); + Arrays.fill(mFrequencies_bigrams, 0); + + int codesSize = codes.size(); + Arrays.fill(mInputCodes, -1); + int[] alternatives = codes.getCodesAt(0); + System.arraycopy(alternatives, 0, mInputCodes, 0, + Math.min(alternatives.length, MAX_ALTERNATIVES)); + + int count = getBigramsNative(mNativeDict, chars, chars.length, mInputCodes, codesSize, + mOutputChars_bigrams, mFrequencies_bigrams, MAX_WORD_LENGTH, MAX_BIGRAMS, + MAX_ALTERNATIVES); + + for (int j = 0; j < count; j++) { + if (mFrequencies_bigrams[j] < 1) break; + int start = j * MAX_WORD_LENGTH; + int len = 0; + while (mOutputChars_bigrams[start + len] != 0) { + len++; + } + if (len > 0) { + callback.addWord(mOutputChars_bigrams, start, len, mFrequencies_bigrams[j], + mDicTypeId, DataType.BIGRAM); + } + } + } + + @Override + public void getWords(final WordComposer codes, final WordCallback callback, + int[] nextLettersFrequencies) { + final int codesSize = codes.size(); + // Won't deal with really long words. + if (codesSize > MAX_WORD_LENGTH - 1) return; + + Arrays.fill(mInputCodes, -1); + for (int i = 0; i < codesSize; i++) { + int[] alternatives = codes.getCodesAt(i); + System.arraycopy(alternatives, 0, mInputCodes, i * MAX_ALTERNATIVES, + Math.min(alternatives.length, MAX_ALTERNATIVES)); + } + Arrays.fill(mOutputChars, (char) 0); + Arrays.fill(mFrequencies, 0); + + int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, + mOutputChars, mFrequencies, + MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES, -1, + nextLettersFrequencies, + nextLettersFrequencies != null ? nextLettersFrequencies.length : 0); + + // If there aren't sufficient suggestions, search for words by allowing wild cards at + // the different character positions. This feature is not ready for prime-time as we need + // to figure out the best ranking for such words compared to proximity corrections and + // completions. + if (ENABLE_MISSED_CHARACTERS && count < 5) { + for (int skip = 0; skip < codesSize; skip++) { + int tempCount = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, + mOutputChars, mFrequencies, + MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES, skip, + null, 0); + count = Math.max(count, tempCount); + if (tempCount > 0) break; + } + } + + for (int j = 0; j < count; j++) { + if (mFrequencies[j] < 1) break; + int start = j * MAX_WORD_LENGTH; + int len = 0; + while (mOutputChars[start + len] != 0) { + len++; + } + if (len > 0) { + callback.addWord(mOutputChars, start, len, mFrequencies[j], mDicTypeId, + DataType.UNIGRAM); + } + } + } + + @Override + public boolean isValidWord(CharSequence word) { + if (word == null) return false; + char[] chars = word.toString().toCharArray(); + return isValidWordNative(mNativeDict, chars, chars.length); + } + + public int getSize() { + return mDictLength; // This value is initialized on the call to openNative() + } + + @Override + public synchronized void close() { + if (mNativeDict != 0) { + closeNative(mNativeDict); + mNativeDict = 0; + } + } + + @Override + protected void finalize() throws Throwable { + close(); + super.finalize(); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/CandidateView.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/CandidateView.java new file mode 100644 index 00000000..429eaa4c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/CandidateView.java @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.PopupWindow; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CandidateView extends View { + + private static final int OUT_OF_BOUNDS_WORD_INDEX = -1; + private static final int OUT_OF_BOUNDS_X_COORD = -1; + + private KP2AKeyboard mService; + private final ArrayList mSuggestions = new ArrayList(); + private boolean mShowingCompletions; + private CharSequence mSelectedString; + private int mSelectedIndex; + private int mTouchX = OUT_OF_BOUNDS_X_COORD; + private final Drawable mSelectionHighlight; + private boolean mTypedWordValid; + + private boolean mHaveMinimalSuggestion; + + private Rect mBgPadding; + + private final TextView mPreviewText; + private final PopupWindow mPreviewPopup; + private int mCurrentWordIndex; + private Drawable mDivider; + + private static final int MAX_SUGGESTIONS = 32; + private static final int SCROLL_PIXELS = 20; + + private final int[] mWordWidth = new int[MAX_SUGGESTIONS]; + private final int[] mWordX = new int[MAX_SUGGESTIONS]; + private int mPopupPreviewX; + private int mPopupPreviewY; + + private static final int X_GAP = 10; + + private final int mColorNormal; + private final int mColorRecommended; + private final int mColorOther; + private final Paint mPaint; + private final int mDescent; + private boolean mScrolled; + private boolean mShowingAddToDictionary; + private CharSequence mAddToDictionaryHint; + + private int mTargetScrollX; + + private final int mMinTouchableWidth; + + private int mTotalWidth; + + private final GestureDetector mGestureDetector; + + /** + * Construct a CandidateView for showing suggested words for completion. + * @param context + * @param attrs + */ + public CandidateView(Context context, AttributeSet attrs) { + super(context, attrs); + mSelectionHighlight = context.getResources().getDrawable( + R.drawable.list_selector_background_pressed); + + LayoutInflater inflate = + (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + Resources res = context.getResources(); + mPreviewPopup = new PopupWindow(context); + mPreviewText = (TextView) inflate.inflate(R.layout.candidate_preview, null); + mPreviewPopup.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + mPreviewPopup.setContentView(mPreviewText); + mPreviewPopup.setBackgroundDrawable(null); + mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); + mColorNormal = res.getColor(R.color.candidate_normal); + mColorRecommended = res.getColor(R.color.candidate_recommended); + mColorOther = res.getColor(R.color.candidate_other); + mDivider = res.getDrawable(R.drawable.keyboard_suggest_strip_divider); + mAddToDictionaryHint = res.getString(R.string.hint_add_to_dictionary); + + mPaint = new Paint(); + mPaint.setColor(mColorNormal); + mPaint.setAntiAlias(true); + mPaint.setTextSize(mPreviewText.getTextSize()); + mPaint.setStrokeWidth(0); + mPaint.setTextAlign(Align.CENTER); + mDescent = (int) mPaint.descent(); + mMinTouchableWidth = (int)res.getDimension(R.dimen.candidate_min_touchable_width); + + mGestureDetector = new GestureDetector( + new CandidateStripGestureListener(mMinTouchableWidth)); + setWillNotDraw(false); + setHorizontalScrollBarEnabled(false); + setVerticalScrollBarEnabled(false); + scrollTo(0, getScrollY()); + } + + private class CandidateStripGestureListener extends GestureDetector.SimpleOnGestureListener { + private final int mTouchSlopSquare; + + public CandidateStripGestureListener(int touchSlop) { + // Slightly reluctant to scroll to be able to easily choose the suggestion + mTouchSlopSquare = touchSlop * touchSlop; + } + + @Override + public void onLongPress(MotionEvent me) { + if (mSuggestions.size() > 0) { + if (me.getX() + getScrollX() < mWordWidth[0] && getScrollX() < 10) { + longPressFirstWord(); + } + } + } + + @Override + public boolean onDown(MotionEvent e) { + mScrolled = false; + return false; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + if (!mScrolled) { + // This is applied only when we recognize that scrolling is starting. + final int deltaX = (int) (e2.getX() - e1.getX()); + final int deltaY = (int) (e2.getY() - e1.getY()); + final int distance = (deltaX * deltaX) + (deltaY * deltaY); + if (distance < mTouchSlopSquare) { + return true; + } + mScrolled = true; + } + + final int width = getWidth(); + mScrolled = true; + int scrollX = getScrollX(); + scrollX += (int) distanceX; + if (scrollX < 0) { + scrollX = 0; + } + if (distanceX > 0 && scrollX + width > mTotalWidth) { + scrollX -= (int) distanceX; + } + mTargetScrollX = scrollX; + scrollTo(scrollX, getScrollY()); + hidePreview(); + invalidate(); + return true; + } + } + + /** + * A connection back to the service to communicate with the text field + * @param listener + */ + public void setService(KP2AKeyboard listener) { + mService = listener; + } + + @Override + public int computeHorizontalScrollRange() { + return mTotalWidth; + } + + /** + * If the canvas is null, then only touch calculations are performed to pick the target + * candidate. + */ + @Override + protected void onDraw(Canvas canvas) { + if (canvas != null) { + super.onDraw(canvas); + } + mTotalWidth = 0; + + final int height = getHeight(); + if (mBgPadding == null) { + mBgPadding = new Rect(0, 0, 0, 0); + if (getBackground() != null) { + getBackground().getPadding(mBgPadding); + } + mDivider.setBounds(0, 0, mDivider.getIntrinsicWidth(), + mDivider.getIntrinsicHeight()); + } + + final int count = mSuggestions.size(); + final Rect bgPadding = mBgPadding; + final Paint paint = mPaint; + final int touchX = mTouchX; + final int scrollX = getScrollX(); + final boolean scrolled = mScrolled; + final boolean typedWordValid = mTypedWordValid; + final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2; + + boolean existsAutoCompletion = false; + + int x = 0; + for (int i = 0; i < count; i++) { + CharSequence suggestion = mSuggestions.get(i); + if (suggestion == null) continue; + final int wordLength = suggestion.length(); + + paint.setColor(mColorNormal); + if (mHaveMinimalSuggestion + && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) { + paint.setTypeface(Typeface.DEFAULT_BOLD); + paint.setColor(mColorRecommended); + existsAutoCompletion = true; + } else if (i != 0 || (wordLength == 1 && count > 1)) { + // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 and + // there are multiple suggestions, such as the default punctuation list. + paint.setColor(mColorOther); + } + int wordWidth; + if ((wordWidth = mWordWidth[i]) == 0) { + float textWidth = paint.measureText(suggestion, 0, wordLength); + wordWidth = Math.max(mMinTouchableWidth, (int) textWidth + X_GAP * 2); + mWordWidth[i] = wordWidth; + } + + mWordX[i] = x; + + if (touchX != OUT_OF_BOUNDS_X_COORD && !scrolled + && touchX + scrollX >= x && touchX + scrollX < x + wordWidth) { + if (canvas != null && !mShowingAddToDictionary) { + canvas.translate(x, 0); + mSelectionHighlight.setBounds(0, bgPadding.top, wordWidth, height); + mSelectionHighlight.draw(canvas); + canvas.translate(-x, 0); + } + mSelectedString = suggestion; + mSelectedIndex = i; + } + + if (canvas != null) { + canvas.drawText(suggestion, 0, wordLength, x + wordWidth / 2, y, paint); + paint.setColor(mColorOther); + canvas.translate(x + wordWidth, 0); + // Draw a divider unless it's after the hint + if (!(mShowingAddToDictionary && i == 1)) { + mDivider.draw(canvas); + } + canvas.translate(-x - wordWidth, 0); + } + paint.setTypeface(Typeface.DEFAULT); + x += wordWidth; + } + mService.onAutoCompletionStateChanged(existsAutoCompletion); + mTotalWidth = x; + if (mTargetScrollX != scrollX) { + scrollToTarget(); + } + } + + private void scrollToTarget() { + int scrollX = getScrollX(); + if (mTargetScrollX > scrollX) { + scrollX += SCROLL_PIXELS; + if (scrollX >= mTargetScrollX) { + scrollX = mTargetScrollX; + scrollTo(scrollX, getScrollY()); + requestLayout(); + } else { + scrollTo(scrollX, getScrollY()); + } + } else { + scrollX -= SCROLL_PIXELS; + if (scrollX <= mTargetScrollX) { + scrollX = mTargetScrollX; + scrollTo(scrollX, getScrollY()); + requestLayout(); + } else { + scrollTo(scrollX, getScrollY()); + } + } + invalidate(); + } + + public void setSuggestions(List suggestions, boolean completions, + boolean typedWordValid, boolean haveMinimalSuggestion) { + clear(); + if (suggestions != null) { + int insertCount = Math.min(suggestions.size(), MAX_SUGGESTIONS); + for (CharSequence suggestion : suggestions) { + mSuggestions.add(suggestion); + if (--insertCount == 0) + break; + } + } + mShowingCompletions = completions; + mTypedWordValid = typedWordValid; + scrollTo(0, getScrollY()); + mTargetScrollX = 0; + mHaveMinimalSuggestion = haveMinimalSuggestion; + // Compute the total width + onDraw(null); + invalidate(); + requestLayout(); + } + + public boolean isShowingAddToDictionaryHint() { + return mShowingAddToDictionary; + } + + public void showAddToDictionaryHint(CharSequence word) { + ArrayList suggestions = new ArrayList(); + suggestions.add(word); + suggestions.add(mAddToDictionaryHint); + setSuggestions(suggestions, false, false, false); + mShowingAddToDictionary = true; + } + + public boolean dismissAddToDictionaryHint() { + if (!mShowingAddToDictionary) return false; + clear(); + return true; + } + + /* package */ List getSuggestions() { + return mSuggestions; + } + + public void clear() { + // Don't call mSuggestions.clear() because it's being used for logging + // in LatinIME.pickSuggestionManually(). + mSuggestions.clear(); + mTouchX = OUT_OF_BOUNDS_X_COORD; + mSelectedString = null; + mSelectedIndex = -1; + mShowingAddToDictionary = false; + invalidate(); + Arrays.fill(mWordWidth, 0); + Arrays.fill(mWordX, 0); + } + + @Override + public boolean onTouchEvent(MotionEvent me) { + + if (mGestureDetector.onTouchEvent(me)) { + return true; + } + + int action = me.getAction(); + int x = (int) me.getX(); + int y = (int) me.getY(); + mTouchX = x; + + switch (action) { + case MotionEvent.ACTION_DOWN: + invalidate(); + break; + case MotionEvent.ACTION_MOVE: + if (y <= 0) { + // Fling up!? + if (mSelectedString != null) { + // If there are completions from the application, we don't change the state to + // STATE_PICKED_SUGGESTION + if (!mShowingCompletions) { + // This "acceptedSuggestion" will not be counted as a word because + // it will be counted in pickSuggestion instead. + TextEntryState.acceptedSuggestion(mSuggestions.get(0), + mSelectedString); + } + mService.pickSuggestionManually(mSelectedIndex, mSelectedString); + mSelectedString = null; + mSelectedIndex = -1; + } + } + break; + case MotionEvent.ACTION_UP: + if (!mScrolled) { + if (mSelectedString != null) { + if (mShowingAddToDictionary) { + longPressFirstWord(); + clear(); + } else { + if (!mShowingCompletions) { + TextEntryState.acceptedSuggestion(mSuggestions.get(0), + mSelectedString); + } + mService.pickSuggestionManually(mSelectedIndex, mSelectedString); + } + } + } + mSelectedString = null; + mSelectedIndex = -1; + requestLayout(); + hidePreview(); + invalidate(); + break; + } + return true; + } + + private void hidePreview() { + mTouchX = OUT_OF_BOUNDS_X_COORD; + mCurrentWordIndex = OUT_OF_BOUNDS_WORD_INDEX; + mPreviewPopup.dismiss(); + } + + private void showPreview(int wordIndex, String altText) { + int oldWordIndex = mCurrentWordIndex; + mCurrentWordIndex = wordIndex; + // If index changed or changing text + if (oldWordIndex != mCurrentWordIndex || altText != null) { + if (wordIndex == OUT_OF_BOUNDS_WORD_INDEX) { + hidePreview(); + } else { + CharSequence word = altText != null? altText : mSuggestions.get(wordIndex); + mPreviewText.setText(word); + mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + int wordWidth = (int) (mPaint.measureText(word, 0, word.length()) + X_GAP * 2); + final int popupWidth = wordWidth + + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight(); + final int popupHeight = mPreviewText.getMeasuredHeight(); + //mPreviewText.setVisibility(INVISIBLE); + mPopupPreviewX = mWordX[wordIndex] - mPreviewText.getPaddingLeft() - getScrollX() + + (mWordWidth[wordIndex] - wordWidth) / 2; + mPopupPreviewY = - popupHeight; + int [] offsetInWindow = new int[2]; + getLocationInWindow(offsetInWindow); + if (mPreviewPopup.isShowing()) { + mPreviewPopup.update(mPopupPreviewX, mPopupPreviewY + offsetInWindow[1], + popupWidth, popupHeight); + } else { + mPreviewPopup.setWidth(popupWidth); + mPreviewPopup.setHeight(popupHeight); + mPreviewPopup.showAtLocation(this, Gravity.NO_GRAVITY, mPopupPreviewX, + mPopupPreviewY + offsetInWindow[1]); + } + mPreviewText.setVisibility(VISIBLE); + } + } + } + + private void longPressFirstWord() { + CharSequence word = mSuggestions.get(0); + if (word.length() < 2) return; + if (mService.addWordToDictionary(word.toString())) { + showPreview(0, getContext().getResources().getString(R.string.added_word, word)); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + hidePreview(); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ContactsDictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ContactsDictionary.java new file mode 100644 index 00000000..247f8bad --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ContactsDictionary.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.os.SystemClock; +import android.provider.ContactsContract.Contacts; +import android.text.TextUtils; +import android.util.Log; + +public class ContactsDictionary extends ExpandableDictionary { + + private static final String[] PROJECTION = { + Contacts._ID, + Contacts.DISPLAY_NAME, + }; + + private static final String TAG = "ContactsDictionary"; + + /** + * Frequency for contacts information into the dictionary + */ + private static final int FREQUENCY_FOR_CONTACTS = 128; + private static final int FREQUENCY_FOR_CONTACTS_BIGRAM = 90; + + private static final int INDEX_NAME = 1; + + private ContentObserver mObserver; + + private long mLastLoadedContacts; + + public ContactsDictionary(Context context, int dicTypeId) { + super(context, dicTypeId); + // Perform a managed query. The Activity will handle closing and requerying the cursor + // when needed. + ContentResolver cres = context.getContentResolver(); + + cres.registerContentObserver( + Contacts.CONTENT_URI, true,mObserver = new ContentObserver(null) { + @Override + public void onChange(boolean self) { + setRequiresReload(true); + } + }); + loadDictionary(); + } + + @Override + public synchronized void close() { + if (mObserver != null) { + getContext().getContentResolver().unregisterContentObserver(mObserver); + mObserver = null; + } + super.close(); + } + + @Override + public void startDictionaryLoadingTaskLocked() { + long now = SystemClock.uptimeMillis(); + if (mLastLoadedContacts == 0 + || now - mLastLoadedContacts > 30 * 60 * 1000 /* 30 minutes */) { + super.startDictionaryLoadingTaskLocked(); + } + } + + @Override + public void loadDictionaryAsync() { + /*try { + Cursor cursor = getContext().getContentResolver() + .query(Contacts.CONTENT_URI, PROJECTION, null, null, null); + if (cursor != null) { + addWords(cursor); + } + } catch(IllegalStateException e) { + Log.e(TAG, "Contacts DB is having problems"); + } + mLastLoadedContacts = SystemClock.uptimeMillis();*/ + } + + private void addWords(Cursor cursor) { + clearDictionary(); + + final int maxWordLength = getMaxWordLength(); + try { + if (cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + String name = cursor.getString(INDEX_NAME); + + if (name != null) { + int len = name.length(); + String prevWord = null; + + // TODO: Better tokenization for non-Latin writing systems + for (int i = 0; i < len; i++) { + if (Character.isLetter(name.charAt(i))) { + int j; + for (j = i + 1; j < len; j++) { + char c = name.charAt(j); + + if (!(c == '-' || c == '\'' || + Character.isLetter(c))) { + break; + } + } + + String word = name.substring(i, j); + i = j - 1; + + // Safeguard against adding really long words. Stack + // may overflow due to recursion + // Also don't add single letter words, possibly confuses + // capitalization of i. + final int wordLen = word.length(); + if (wordLen < maxWordLength && wordLen > 1) { + super.addWord(word, FREQUENCY_FOR_CONTACTS); + if (!TextUtils.isEmpty(prevWord)) { + // TODO Do not add email address + // Not so critical + super.setBigram(prevWord, word, + FREQUENCY_FOR_CONTACTS_BIGRAM); + } + prevWord = word; + } + } + } + } + cursor.moveToNext(); + } + } + cursor.close(); + } catch(IllegalStateException e) { + Log.e(TAG, "Contacts DB is having problems"); + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Dictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Dictionary.java new file mode 100644 index 00000000..2b93599b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Dictionary.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +/** + * Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key + * strokes. + */ +abstract public class Dictionary { + /** + * Whether or not to replicate the typed word in the suggested list, even if it's valid. + */ + protected static final boolean INCLUDE_TYPED_WORD_IF_VALID = false; + + /** + * The weight to give to a word if it's length is the same as the number of typed characters. + */ + protected static final int FULL_WORD_FREQ_MULTIPLIER = 2; + + public static enum DataType { + UNIGRAM, BIGRAM + } + + /** + * Interface to be implemented by classes requesting words to be fetched from the dictionary. + * @see #getWords(WordComposer, WordCallback) + */ + public interface WordCallback { + /** + * Adds a word to a list of suggestions. The word is expected to be ordered based on + * the provided frequency. + * @param word the character array containing the word + * @param wordOffset starting offset of the word in the character array + * @param wordLength length of valid characters in the character array + * @param frequency the frequency of occurence. This is normalized between 1 and 255, but + * can exceed those limits + * @param dicTypeId of the dictionary where word was from + * @param dataType tells type of this data + * @return true if the word was added, false if no more words are required + */ + boolean addWord(char[] word, int wordOffset, int wordLength, int frequency, int dicTypeId, + DataType dataType); + } + + /** + * Searches for words in the dictionary that match the characters in the composer. Matched + * words are added through the callback object. + * @param composer the key sequence to match + * @param callback the callback object to send matched words to as possible candidates + * @param nextLettersFrequencies array of frequencies of next letters that could follow the + * word so far. For instance, "bracke" can be followed by "t", so array['t'] will have + * a non-zero value on returning from this method. + * Pass in null if you don't want the dictionary to look up next letters. + * @see WordCallback#addWord(char[], int, int) + */ + abstract public void getWords(final WordComposer composer, final WordCallback callback, + int[] nextLettersFrequencies); + + /** + * Searches for pairs in the bigram dictionary that matches the previous word and all the + * possible words following are added through the callback object. + * @param composer the key sequence to match + * @param callback the callback object to send possible word following previous word + * @param nextLettersFrequencies array of frequencies of next letters that could follow the + * word so far. For instance, "bracke" can be followed by "t", so array['t'] will have + * a non-zero value on returning from this method. + * Pass in null if you don't want the dictionary to look up next letters. + */ + public void getBigrams(final WordComposer composer, final CharSequence previousWord, + final WordCallback callback, int[] nextLettersFrequencies) { + // empty base implementation + } + + /** + * Checks if the given word occurs in the dictionary + * @param word the word to search for. The search should be case-insensitive. + * @return true if the word exists, false otherwise + */ + abstract public boolean isValidWord(CharSequence word); + + /** + * Compares the contents of the character array with the typed word and returns true if they + * are the same. + * @param word the array of characters that make up the word + * @param length the number of valid characters in the character array + * @param typedWord the word to compare with + * @return true if they are the same, false otherwise. + */ + protected boolean same(final char[] word, final int length, final CharSequence typedWord) { + if (typedWord.length() != length) { + return false; + } + for (int i = 0; i < length; i++) { + if (word[i] != typedWord.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Override to clean up any resources. + */ + public void close() { + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/EditingUtil.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/EditingUtil.java new file mode 100644 index 00000000..3f3df704 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/EditingUtil.java @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.text.TextUtils; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.regex.Pattern; + +/** + * Utility methods to deal with editing text through an InputConnection. + */ +public class EditingUtil { + /** + * Number of characters we want to look back in order to identify the previous word + */ + private static final int LOOKBACK_CHARACTER_NUM = 15; + + // Cache Method pointers + private static boolean sMethodsInitialized; + private static Method sMethodGetSelectedText; + private static Method sMethodSetComposingRegion; + + private EditingUtil() {}; + + /** + * Append newText to the text field represented by connection. + * The new text becomes selected. + */ + public static void appendText(InputConnection connection, String newText) { + if (connection == null) { + return; + } + + // Commit the composing text + connection.finishComposingText(); + + // Add a space if the field already has text. + CharSequence charBeforeCursor = connection.getTextBeforeCursor(1, 0); + if (charBeforeCursor != null + && !charBeforeCursor.equals(" ") + && (charBeforeCursor.length() > 0)) { + newText = " " + newText; + } + + connection.setComposingText(newText, 1); + } + + private static int getCursorPosition(InputConnection connection) { + ExtractedText extracted = connection.getExtractedText( + new ExtractedTextRequest(), 0); + if (extracted == null) { + return -1; + } + return extracted.startOffset + extracted.selectionStart; + } + + /** + * @param connection connection to the current text field. + * @param sep characters which may separate words + * @param range the range object to store the result into + * @return the word that surrounds the cursor, including up to one trailing + * separator. For example, if the field contains "he|llo world", where | + * represents the cursor, then "hello " will be returned. + */ + public static String getWordAtCursor( + InputConnection connection, String separators, Range range) { + Range r = getWordRangeAtCursor(connection, separators, range); + return (r == null) ? null : r.word; + } + + /** + * Removes the word surrounding the cursor. Parameters are identical to + * getWordAtCursor. + */ + public static void deleteWordAtCursor( + InputConnection connection, String separators) { + + Range range = getWordRangeAtCursor(connection, separators, null); + if (range == null) return; + + connection.finishComposingText(); + // Move cursor to beginning of word, to avoid crash when cursor is outside + // of valid range after deleting text. + int newCursor = getCursorPosition(connection) - range.charsBefore; + connection.setSelection(newCursor, newCursor); + connection.deleteSurroundingText(0, range.charsBefore + range.charsAfter); + } + + /** + * Represents a range of text, relative to the current cursor position. + */ + public static class Range { + /** Characters before selection start */ + public int charsBefore; + + /** + * Characters after selection start, including one trailing word + * separator. + */ + public int charsAfter; + + /** The actual characters that make up a word */ + public String word; + + public Range() {} + + public Range(int charsBefore, int charsAfter, String word) { + if (charsBefore < 0 || charsAfter < 0) { + throw new IndexOutOfBoundsException(); + } + this.charsBefore = charsBefore; + this.charsAfter = charsAfter; + this.word = word; + } + } + + private static Range getWordRangeAtCursor( + InputConnection connection, String sep, Range range) { + if (connection == null || sep == null) { + return null; + } + CharSequence before = connection.getTextBeforeCursor(1000, 0); + CharSequence after = connection.getTextAfterCursor(1000, 0); + if (before == null || after == null) { + return null; + } + + // Find first word separator before the cursor + int start = before.length(); + while (start > 0 && !isWhitespace(before.charAt(start - 1), sep)) start--; + + // Find last word separator after the cursor + int end = -1; + while (++end < after.length() && !isWhitespace(after.charAt(end), sep)); + + int cursor = getCursorPosition(connection); + if (start >= 0 && cursor + end <= after.length() + before.length()) { + String word = before.toString().substring(start, before.length()) + + after.toString().substring(0, end); + + Range returnRange = range != null? range : new Range(); + returnRange.charsBefore = before.length() - start; + returnRange.charsAfter = end; + returnRange.word = word; + return returnRange; + } + + return null; + } + + private static boolean isWhitespace(int code, String whitespace) { + return whitespace.contains(String.valueOf((char) code)); + } + + private static final Pattern spaceRegex = Pattern.compile("\\s+"); + + public static CharSequence getPreviousWord(InputConnection connection, + String sentenceSeperators) { + //TODO: Should fix this. This could be slow! + CharSequence prev = connection.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0); + if (prev == null) { + return null; + } + String[] w = spaceRegex.split(prev); + if (w.length >= 2 && w[w.length-2].length() > 0) { + char lastChar = w[w.length-2].charAt(w[w.length-2].length() -1); + if (sentenceSeperators.contains(String.valueOf(lastChar))) { + return null; + } + return w[w.length-2]; + } else { + return null; + } + } + + public static class SelectedWord { + public int start; + public int end; + public CharSequence word; + } + + /** + * Takes a character sequence with a single character and checks if the character occurs + * in a list of word separators or is empty. + * @param singleChar A CharSequence with null, zero or one character + * @param wordSeparators A String containing the word separators + * @return true if the character is at a word boundary, false otherwise + */ + private static boolean isWordBoundary(CharSequence singleChar, String wordSeparators) { + return TextUtils.isEmpty(singleChar) || wordSeparators.contains(singleChar); + } + + /** + * Checks if the cursor is inside a word or the current selection is a whole word. + * @param ic the InputConnection for accessing the text field + * @param selStart the start position of the selection within the text field + * @param selEnd the end position of the selection within the text field. This could be + * the same as selStart, if there's no selection. + * @param wordSeparators the word separator characters for the current language + * @return an object containing the text and coordinates of the selected/touching word, + * null if the selection/cursor is not marking a whole word. + */ + public static SelectedWord getWordAtCursorOrSelection(final InputConnection ic, + int selStart, int selEnd, String wordSeparators) { + if (selStart == selEnd) { + // There is just a cursor, so get the word at the cursor + EditingUtil.Range range = new EditingUtil.Range(); + CharSequence touching = getWordAtCursor(ic, wordSeparators, range); + if (!TextUtils.isEmpty(touching)) { + SelectedWord selWord = new SelectedWord(); + selWord.word = touching; + selWord.start = selStart - range.charsBefore; + selWord.end = selEnd + range.charsAfter; + return selWord; + } + } else { + // Is the previous character empty or a word separator? If not, return null. + CharSequence charsBefore = ic.getTextBeforeCursor(1, 0); + if (!isWordBoundary(charsBefore, wordSeparators)) { + return null; + } + + // Is the next character empty or a word separator? If not, return null. + CharSequence charsAfter = ic.getTextAfterCursor(1, 0); + if (!isWordBoundary(charsAfter, wordSeparators)) { + return null; + } + + // Extract the selection alone + CharSequence touching = getSelectedText(ic, selStart, selEnd); + if (TextUtils.isEmpty(touching)) return null; + // Is any part of the selection a separator? If so, return null. + final int length = touching.length(); + for (int i = 0; i < length; i++) { + if (wordSeparators.contains(touching.subSequence(i, i + 1))) { + return null; + } + } + // Prepare the selected word + SelectedWord selWord = new SelectedWord(); + selWord.start = selStart; + selWord.end = selEnd; + selWord.word = touching; + return selWord; + } + return null; + } + + /** + * Cache method pointers for performance + */ + private static void initializeMethodsForReflection() { + try { + // These will either both exist or not, so no need for separate try/catch blocks. + // If other methods are added later, use separate try/catch blocks. + sMethodGetSelectedText = InputConnection.class.getMethod("getSelectedText", int.class); + sMethodSetComposingRegion = InputConnection.class.getMethod("setComposingRegion", + int.class, int.class); + } catch (NoSuchMethodException exc) { + // Ignore + } + sMethodsInitialized = true; + } + + /** + * Returns the selected text between the selStart and selEnd positions. + */ + private static CharSequence getSelectedText(InputConnection ic, int selStart, int selEnd) { + // Use reflection, for backward compatibility + CharSequence result = null; + if (!sMethodsInitialized) { + initializeMethodsForReflection(); + } + if (sMethodGetSelectedText != null) { + try { + result = (CharSequence) sMethodGetSelectedText.invoke(ic, 0); + return result; + } catch (InvocationTargetException exc) { + // Ignore + } catch (IllegalArgumentException e) { + // Ignore + } catch (IllegalAccessException e) { + // Ignore + } + } + // Reflection didn't work, try it the poor way, by moving the cursor to the start, + // getting the text after the cursor and moving the text back to selected mode. + // TODO: Verify that this works properly in conjunction with + // LatinIME#onUpdateSelection + ic.setSelection(selStart, selEnd); + result = ic.getTextAfterCursor(selEnd - selStart, 0); + ic.setSelection(selStart, selEnd); + return result; + } + + /** + * Tries to set the text into composition mode if there is support for it in the framework. + */ + public static void underlineWord(InputConnection ic, SelectedWord word) { + // Use reflection, for backward compatibility + // If method not found, there's nothing we can do. It still works but just wont underline + // the word. + if (!sMethodsInitialized) { + initializeMethodsForReflection(); + } + if (sMethodSetComposingRegion != null) { + try { + sMethodSetComposingRegion.invoke(ic, word.start, word.end); + } catch (InvocationTargetException exc) { + // Ignore + } catch (IllegalArgumentException e) { + // Ignore + } catch (IllegalAccessException e) { + // Ignore + } + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ExpandableDictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ExpandableDictionary.java new file mode 100644 index 00000000..95737626 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ExpandableDictionary.java @@ -0,0 +1,691 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import java.util.LinkedList; + +import android.content.Context; +import android.os.AsyncTask; + +/** + * Base class for an in-memory dictionary that can grow dynamically and can + * be searched for suggestions and valid words. + */ +public class ExpandableDictionary extends Dictionary { + /** + * There is difference between what java and native code can handle. + * It uses 32 because Java stack overflows when greater value is used. + */ + protected static final int MAX_WORD_LENGTH = 32; + + private Context mContext; + private char[] mWordBuilder = new char[MAX_WORD_LENGTH]; + private int mDicTypeId; + private int mMaxDepth; + private int mInputLength; + private int[] mNextLettersFrequencies; + private StringBuilder sb = new StringBuilder(MAX_WORD_LENGTH); + + private static final char QUOTE = '\''; + + private boolean mRequiresReload; + + private boolean mUpdatingDictionary; + + // Use this lock before touching mUpdatingDictionary & mRequiresDownload + private Object mUpdatingLock = new Object(); + + static class Node { + char code; + int frequency; + boolean terminal; + Node parent; + NodeArray children; + LinkedList ngrams; // Supports ngram + } + + static class NodeArray { + Node[] data; + int length = 0; + private static final int INCREMENT = 2; + + NodeArray() { + data = new Node[INCREMENT]; + } + + void add(Node n) { + if (length + 1 > data.length) { + Node[] tempData = new Node[length + INCREMENT]; + if (length > 0) { + System.arraycopy(data, 0, tempData, 0, length); + } + data = tempData; + } + data[length++] = n; + } + } + + static class NextWord { + Node word; + NextWord nextWord; + int frequency; + + NextWord(Node word, int frequency) { + this.word = word; + this.frequency = frequency; + } + } + + + private NodeArray mRoots; + + private int[][] mCodes; + + ExpandableDictionary(Context context, int dicTypeId) { + mContext = context; + clearDictionary(); + mCodes = new int[MAX_WORD_LENGTH][]; + mDicTypeId = dicTypeId; + } + + public void loadDictionary() { + synchronized (mUpdatingLock) { + startDictionaryLoadingTaskLocked(); + } + } + + public void startDictionaryLoadingTaskLocked() { + if (!mUpdatingDictionary) { + mUpdatingDictionary = true; + mRequiresReload = false; + new LoadDictionaryTask().execute(); + } + } + + public void setRequiresReload(boolean reload) { + synchronized (mUpdatingLock) { + mRequiresReload = reload; + } + } + + public boolean getRequiresReload() { + return mRequiresReload; + } + + /** Override to load your dictionary here, on a background thread. */ + public void loadDictionaryAsync() { + } + + Context getContext() { + return mContext; + } + + int getMaxWordLength() { + return MAX_WORD_LENGTH; + } + + public void addWord(String word, int frequency) { + addWordRec(mRoots, word, 0, frequency, null); + } + + private void addWordRec(NodeArray children, final String word, final int depth, + final int frequency, Node parentNode) { + final int wordLength = word.length(); + final char c = word.charAt(depth); + // Does children have the current character? + final int childrenLength = children.length; + Node childNode = null; + boolean found = false; + for (int i = 0; i < childrenLength; i++) { + childNode = children.data[i]; + if (childNode.code == c) { + found = true; + break; + } + } + if (!found) { + childNode = new Node(); + childNode.code = c; + childNode.parent = parentNode; + children.add(childNode); + } + if (wordLength == depth + 1) { + // Terminate this word + childNode.terminal = true; + childNode.frequency = Math.max(frequency, childNode.frequency); + if (childNode.frequency > 255) childNode.frequency = 255; + return; + } + if (childNode.children == null) { + childNode.children = new NodeArray(); + } + addWordRec(childNode.children, word, depth + 1, frequency, childNode); + } + + @Override + public void getWords(final WordComposer codes, final WordCallback callback, + int[] nextLettersFrequencies) { + synchronized (mUpdatingLock) { + // If we need to update, start off a background task + if (mRequiresReload) startDictionaryLoadingTaskLocked(); + // Currently updating contacts, don't return any results. + if (mUpdatingDictionary) return; + } + + mInputLength = codes.size(); + mNextLettersFrequencies = nextLettersFrequencies; + if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; + // Cache the codes so that we don't have to lookup an array list + for (int i = 0; i < mInputLength; i++) { + mCodes[i] = codes.getCodesAt(i); + } + mMaxDepth = mInputLength * 3; + getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, callback); + for (int i = 0; i < mInputLength; i++) { + getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, callback); + } + } + + @Override + public synchronized boolean isValidWord(CharSequence word) { + synchronized (mUpdatingLock) { + // If we need to update, start off a background task + if (mRequiresReload) startDictionaryLoadingTaskLocked(); + if (mUpdatingDictionary) return false; + } + final int freq = getWordFrequency(word); + return freq > -1; + } + + /** + * Returns the word's frequency or -1 if not found + */ + public int getWordFrequency(CharSequence word) { + Node node = searchNode(mRoots, word, 0, word.length()); + return (node == null) ? -1 : node.frequency; + } + + /** + * Recursively traverse the tree for words that match the input. Input consists of + * a list of arrays. Each item in the list is one input character position. An input + * character is actually an array of multiple possible candidates. This function is not + * optimized for speed, assuming that the user dictionary will only be a few hundred words in + * size. + * @param roots node whose children have to be search for matches + * @param codes the input character codes + * @param word the word being composed as a possible match + * @param depth the depth of traversal - the length of the word being composed thus far + * @param completion whether the traversal is now in completion mode - meaning that we've + * exhausted the input and we're looking for all possible suffixes. + * @param snr current weight of the word being formed + * @param inputIndex position in the input characters. This can be off from the depth in + * case we skip over some punctuations such as apostrophe in the traversal. That is, if you type + * "wouldve", it could be matching "would've", so the depth will be one more than the + * inputIndex + * @param callback the callback class for adding a word + */ + protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word, + final int depth, boolean completion, int snr, int inputIndex, int skipPos, + WordCallback callback) { + final int count = roots.length; + final int codeSize = mInputLength; + // Optimization: Prune out words that are too long compared to how much was typed. + if (depth > mMaxDepth) { + return; + } + int[] currentChars = null; + if (codeSize <= inputIndex) { + completion = true; + } else { + currentChars = mCodes[inputIndex]; + } + + for (int i = 0; i < count; i++) { + final Node node = roots.data[i]; + final char c = node.code; + final char lowerC = toLowerCase(c); + final boolean terminal = node.terminal; + final NodeArray children = node.children; + final int freq = node.frequency; + if (completion) { + word[depth] = c; + if (terminal) { + if (!callback.addWord(word, 0, depth + 1, freq * snr, mDicTypeId, + DataType.UNIGRAM)) { + return; + } + // Add to frequency of next letters for predictive correction + if (mNextLettersFrequencies != null && depth >= inputIndex && skipPos < 0 + && mNextLettersFrequencies.length > word[inputIndex]) { + mNextLettersFrequencies[word[inputIndex]]++; + } + } + if (children != null) { + getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, + skipPos, callback); + } + } else if ((c == QUOTE && currentChars[0] != QUOTE) || depth == skipPos) { + // Skip the ' and continue deeper + word[depth] = c; + if (children != null) { + getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, + skipPos, callback); + } + } else { + // Don't use alternatives if we're looking for missing characters + final int alternativesSize = skipPos >= 0? 1 : currentChars.length; + for (int j = 0; j < alternativesSize; j++) { + final int addedAttenuation = (j > 0 ? 1 : 2); + final int currentChar = currentChars[j]; + if (currentChar == -1) { + break; + } + if (currentChar == lowerC || currentChar == c) { + word[depth] = c; + + if (codeSize == inputIndex + 1) { + if (terminal) { + if (INCLUDE_TYPED_WORD_IF_VALID + || !same(word, depth + 1, codes.getTypedWord())) { + int finalFreq = freq * snr * addedAttenuation; + if (skipPos < 0) finalFreq *= FULL_WORD_FREQ_MULTIPLIER; + callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, + DataType.UNIGRAM); + } + } + if (children != null) { + getWordsRec(children, codes, word, depth + 1, + true, snr * addedAttenuation, inputIndex + 1, + skipPos, callback); + } + } else if (children != null) { + getWordsRec(children, codes, word, depth + 1, + false, snr * addedAttenuation, inputIndex + 1, + skipPos, callback); + } + } + } + } + } + } + + protected int setBigram(String word1, String word2, int frequency) { + return addOrSetBigram(word1, word2, frequency, false); + } + + protected int addBigram(String word1, String word2, int frequency) { + return addOrSetBigram(word1, word2, frequency, true); + } + + /** + * Adds bigrams to the in-memory trie structure that is being used to retrieve any word + * @param frequency frequency for this bigrams + * @param addFrequency if true, it adds to current frequency + * @return returns the final frequency + */ + private int addOrSetBigram(String word1, String word2, int frequency, boolean addFrequency) { + Node firstWord = searchWord(mRoots, word1, 0, null); + Node secondWord = searchWord(mRoots, word2, 0, null); + LinkedList bigram = firstWord.ngrams; + if (bigram == null || bigram.size() == 0) { + firstWord.ngrams = new LinkedList(); + bigram = firstWord.ngrams; + } else { + for (NextWord nw : bigram) { + if (nw.word == secondWord) { + if (addFrequency) { + nw.frequency += frequency; + } else { + nw.frequency = frequency; + } + return nw.frequency; + } + } + } + NextWord nw = new NextWord(secondWord, frequency); + firstWord.ngrams.add(nw); + return frequency; + } + + /** + * Searches for the word and add the word if it does not exist. + * @return Returns the terminal node of the word we are searching for. + */ + private Node searchWord(NodeArray children, String word, int depth, Node parentNode) { + final int wordLength = word.length(); + final char c = word.charAt(depth); + // Does children have the current character? + final int childrenLength = children.length; + Node childNode = null; + boolean found = false; + for (int i = 0; i < childrenLength; i++) { + childNode = children.data[i]; + if (childNode.code == c) { + found = true; + break; + } + } + if (!found) { + childNode = new Node(); + childNode.code = c; + childNode.parent = parentNode; + children.add(childNode); + } + if (wordLength == depth + 1) { + // Terminate this word + childNode.terminal = true; + return childNode; + } + if (childNode.children == null) { + childNode.children = new NodeArray(); + } + return searchWord(childNode.children, word, depth + 1, childNode); + } + + // @VisibleForTesting + boolean reloadDictionaryIfRequired() { + synchronized (mUpdatingLock) { + // If we need to update, start off a background task + if (mRequiresReload) startDictionaryLoadingTaskLocked(); + // Currently updating contacts, don't return any results. + return mUpdatingDictionary; + } + } + + private void runReverseLookUp(final CharSequence previousWord, final WordCallback callback) { + Node prevWord = searchNode(mRoots, previousWord, 0, previousWord.length()); + if (prevWord != null && prevWord.ngrams != null) { + reverseLookUp(prevWord.ngrams, callback); + } + } + + @Override + public void getBigrams(final WordComposer codes, final CharSequence previousWord, + final WordCallback callback, int[] nextLettersFrequencies) { + if (!reloadDictionaryIfRequired()) { + runReverseLookUp(previousWord, callback); + } + } + + /** + * Used only for testing purposes + * This function will wait for loading from database to be done + */ + void waitForDictionaryLoading() { + while (mUpdatingDictionary) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + } + + /** + * reverseLookUp retrieves the full word given a list of terminal nodes and adds those words + * through callback. + * @param terminalNodes list of terminal nodes we want to add + */ + private void reverseLookUp(LinkedList terminalNodes, + final WordCallback callback) { + Node node; + int freq; + for (NextWord nextWord : terminalNodes) { + node = nextWord.word; + freq = nextWord.frequency; + // TODO Not the best way to limit suggestion threshold + if (freq >= UserBigramDictionary.SUGGEST_THRESHOLD) { + sb.setLength(0); + do { + sb.insert(0, node.code); + node = node.parent; + } while(node != null); + + // TODO better way to feed char array? + callback.addWord(sb.toString().toCharArray(), 0, sb.length(), freq, mDicTypeId, + DataType.BIGRAM); + } + } + } + + /** + * Search for the terminal node of the word + * @return Returns the terminal node of the word if the word exists + */ + private Node searchNode(final NodeArray children, final CharSequence word, final int offset, + final int length) { + // TODO Consider combining with addWordRec + final int count = children.length; + char currentChar = word.charAt(offset); + for (int j = 0; j < count; j++) { + final Node node = children.data[j]; + if (node.code == currentChar) { + if (offset == length - 1) { + if (node.terminal) { + return node; + } + } else { + if (node.children != null) { + Node returnNode = searchNode(node.children, word, offset + 1, length); + if (returnNode != null) return returnNode; + } + } + } + } + return null; + } + + protected void clearDictionary() { + mRoots = new NodeArray(); + } + + private class LoadDictionaryTask extends AsyncTask { + @Override + protected Void doInBackground(Void... v) { + loadDictionaryAsync(); + synchronized (mUpdatingLock) { + mUpdatingDictionary = false; + } + return null; + } + } + + static char toLowerCase(char c) { + if (c < BASE_CHARS.length) { + c = BASE_CHARS[c]; + } + if (c >= 'A' && c <= 'Z') { + c = (char) (c | 32); + } else if (c > 127) { + c = Character.toLowerCase(c); + } + return c; + } + + /** + * Table mapping most combined Latin, Greek, and Cyrillic characters + * to their base characters. If c is in range, BASE_CHARS[c] == c + * if c is not a combined character, or the base character if it + * is combined. + */ + static final char BASE_CHARS[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x0020, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x0020, 0x00a9, 0x0061, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0020, + 0x00b0, 0x00b1, 0x0032, 0x0033, 0x0020, 0x03bc, 0x00b6, 0x00b7, + 0x0020, 0x0031, 0x006f, 0x00bb, 0x0031, 0x0031, 0x0033, 0x00bf, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00c6, 0x0043, + 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, + 0x00d0, 0x004e, 0x004f, 0x004f, 0x004f, 0x004f, 0x004f, 0x00d7, + 0x004f, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00de, 0x0073, // Manually changed d8 to 4f + // Manually changed df to 73 + 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00e6, 0x0063, + 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, + 0x00f0, 0x006e, 0x006f, 0x006f, 0x006f, 0x006f, 0x006f, 0x00f7, + 0x006f, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00fe, 0x0079, // Manually changed f8 to 6f + 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063, + 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064, + 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065, + 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, + 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, + 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, + 0x0049, 0x0131, 0x0049, 0x0069, 0x004a, 0x006a, 0x004b, 0x006b, + 0x0138, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, + 0x006c, 0x0141, 0x0142, 0x004e, 0x006e, 0x004e, 0x006e, 0x004e, + 0x006e, 0x02bc, 0x014a, 0x014b, 0x004f, 0x006f, 0x004f, 0x006f, + 0x004f, 0x006f, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072, + 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073, + 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167, + 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, + 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079, + 0x0059, 0x005a, 0x007a, 0x005a, 0x007a, 0x005a, 0x007a, 0x0073, + 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, + 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e, 0x018f, + 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, + 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f, + 0x004f, 0x006f, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, + 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x0055, + 0x0075, 0x01b1, 0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7, + 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x0044, 0x0044, 0x0064, 0x004c, + 0x004c, 0x006c, 0x004e, 0x004e, 0x006e, 0x0041, 0x0061, 0x0049, + 0x0069, 0x004f, 0x006f, 0x0055, 0x0075, 0x00dc, 0x00fc, 0x00dc, + 0x00fc, 0x00dc, 0x00fc, 0x00dc, 0x00fc, 0x01dd, 0x00c4, 0x00e4, + 0x0226, 0x0227, 0x00c6, 0x00e6, 0x01e4, 0x01e5, 0x0047, 0x0067, + 0x004b, 0x006b, 0x004f, 0x006f, 0x01ea, 0x01eb, 0x01b7, 0x0292, + 0x006a, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01f6, 0x01f7, + 0x004e, 0x006e, 0x00c5, 0x00e5, 0x00c6, 0x00e6, 0x00d8, 0x00f8, + 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065, + 0x0049, 0x0069, 0x0049, 0x0069, 0x004f, 0x006f, 0x004f, 0x006f, + 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075, + 0x0053, 0x0073, 0x0054, 0x0074, 0x021c, 0x021d, 0x0048, 0x0068, + 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061, + 0x0045, 0x0065, 0x00d6, 0x00f6, 0x00d5, 0x00f5, 0x004f, 0x006f, + 0x022e, 0x022f, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, + 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, + 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, + 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, + 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, + 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, + 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, + 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x0068, 0x0266, 0x006a, 0x0072, 0x0279, 0x027b, 0x0281, 0x0077, + 0x0079, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02de, 0x02df, + 0x0263, 0x006c, 0x0073, 0x0078, 0x0295, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, + 0x0370, 0x0371, 0x0372, 0x0373, 0x02b9, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x0020, 0x037b, 0x037c, 0x037d, 0x003b, 0x037f, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00a8, 0x0391, 0x00b7, + 0x0395, 0x0397, 0x0399, 0x038b, 0x039f, 0x038d, 0x03a5, 0x03a9, + 0x03ca, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x0399, 0x03a5, 0x03b1, 0x03b5, 0x03b7, 0x03b9, + 0x03cb, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03b9, 0x03c5, 0x03bf, 0x03c5, 0x03c9, 0x03cf, + 0x03b2, 0x03b8, 0x03a5, 0x03d2, 0x03d2, 0x03c6, 0x03c0, 0x03d7, + 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, + 0x03e0, 0x03e1, 0x03e2, 0x03e3, 0x03e4, 0x03e5, 0x03e6, 0x03e7, + 0x03e8, 0x03e9, 0x03ea, 0x03eb, 0x03ec, 0x03ed, 0x03ee, 0x03ef, + 0x03ba, 0x03c1, 0x03c2, 0x03f3, 0x0398, 0x03b5, 0x03f6, 0x03f7, + 0x03f8, 0x03a3, 0x03fa, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff, + 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, + 0x0408, 0x0409, 0x040a, 0x040b, 0x041a, 0x0418, 0x0423, 0x040f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0418, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0438, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456, + 0x0458, 0x0459, 0x045a, 0x045b, 0x043a, 0x0438, 0x0443, 0x045f, + 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, + 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f, + 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475, + 0x0478, 0x0479, 0x047a, 0x047b, 0x047c, 0x047d, 0x047e, 0x047f, + 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, + 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, + 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x049f, + 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, + 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, + 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, + 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x04be, 0x04bf, + 0x04c0, 0x0416, 0x0436, 0x04c3, 0x04c4, 0x04c5, 0x04c6, 0x04c7, + 0x04c8, 0x04c9, 0x04ca, 0x04cb, 0x04cc, 0x04cd, 0x04ce, 0x04cf, + 0x0410, 0x0430, 0x0410, 0x0430, 0x04d4, 0x04d5, 0x0415, 0x0435, + 0x04d8, 0x04d9, 0x04d8, 0x04d9, 0x0416, 0x0436, 0x0417, 0x0437, + 0x04e0, 0x04e1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041e, 0x043e, + 0x04e8, 0x04e9, 0x04e8, 0x04e9, 0x042d, 0x044d, 0x0423, 0x0443, + 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7, + 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff, + }; + + // generated with: + // cat UnicodeData.txt | perl -e 'while (<>) { @foo = split(/;/); $foo[5] =~ s/<.*> //; $base[hex($foo[0])] = hex($foo[5]);} for ($i = 0; $i < 0x500; $i += 8) { for ($j = $i; $j < $i + 8; $j++) { printf("0x%04x, ", $base[$j] ? $base[$j] : $j)}; print "\n"; }' + +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Hints.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Hints.java new file mode 100644 index 00000000..58c15cd8 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Hints.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.view.inputmethod.InputConnection; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +/** + * Logic to determine when to display hints on usage to the user. + */ +public class Hints { + public interface Display { + public void showHint(int viewResource); + } + + private static final String PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN = + "voice_hint_num_unique_days_shown"; + private static final String PREF_VOICE_HINT_LAST_TIME_SHOWN = + "voice_hint_last_time_shown"; + private static final String PREF_VOICE_INPUT_LAST_TIME_USED = + "voice_input_last_time_used"; + private static final String PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT = + "voice_punctuation_hint_view_count"; + private static final int DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW = 7; + private static final int DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS = 7; + + private Context mContext; + private Display mDisplay; + private boolean mVoiceResultContainedPunctuation; + private int mSwipeHintMaxDaysToShow; + private int mPunctuationHintMaxDisplays; + + // Only show punctuation hint if voice result did not contain punctuation. + static final Map SPEAKABLE_PUNCTUATION + = new HashMap(); + static { + SPEAKABLE_PUNCTUATION.put(",", "comma"); + SPEAKABLE_PUNCTUATION.put(".", "period"); + SPEAKABLE_PUNCTUATION.put("?", "question mark"); + } + + public Hints(Context context, Display display) { + mContext = context; + mDisplay = display; + + ContentResolver cr = mContext.getContentResolver(); + + } + + public boolean showSwipeHintIfNecessary(boolean fieldRecommended) { + if (fieldRecommended && shouldShowSwipeHint()) { + showHint(R.layout.voice_swipe_hint); + return true; + } + + return false; + } + + public boolean showPunctuationHintIfNecessary(InputConnection ic) { + if (!mVoiceResultContainedPunctuation + && ic != null + && getAndIncrementPref(PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT) + < mPunctuationHintMaxDisplays) { + CharSequence charBeforeCursor = ic.getTextBeforeCursor(1, 0); + if (SPEAKABLE_PUNCTUATION.containsKey(charBeforeCursor)) { + showHint(R.layout.voice_punctuation_hint); + return true; + } + } + + return false; + } + + public void registerVoiceResult(String text) { + // Update the current time as the last time voice input was used. + SharedPreferences.Editor editor = + PreferenceManager.getDefaultSharedPreferences(mContext).edit(); + editor.putLong(PREF_VOICE_INPUT_LAST_TIME_USED, System.currentTimeMillis()); + SharedPreferencesCompat.apply(editor); + + mVoiceResultContainedPunctuation = false; + for (CharSequence s : SPEAKABLE_PUNCTUATION.keySet()) { + if (text.indexOf(s.toString()) >= 0) { + mVoiceResultContainedPunctuation = true; + break; + } + } + } + + private boolean shouldShowSwipeHint() { + + + return false; + } + + /** + * Determines whether the provided time is from some time today (i.e., this day, month, + * and year). + */ + private boolean isFromToday(long timeInMillis) { + if (timeInMillis == 0) return false; + + Calendar today = Calendar.getInstance(); + today.setTimeInMillis(System.currentTimeMillis()); + + Calendar timestamp = Calendar.getInstance(); + timestamp.setTimeInMillis(timeInMillis); + + return (today.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR) && + today.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) && + today.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH)); + } + + private void showHint(int hintViewResource) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + + int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0); + long lastTimeHintWasShown = sp.getLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, 0); + + // If this is the first time the hint is being shown today, increase the saved values + // to represent that. We don't need to increase the last time the hint was shown unless + // it is a different day from the current value. + if (!isFromToday(lastTimeHintWasShown)) { + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, numUniqueDaysShown + 1); + editor.putLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, System.currentTimeMillis()); + SharedPreferencesCompat.apply(editor); + } + + if (mDisplay != null) { + mDisplay.showHint(hintViewResource); + } + } + + private int getAndIncrementPref(String pref) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + int value = sp.getInt(pref, 0); + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(pref, value + 1); + SharedPreferencesCompat.apply(editor); + return value; + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/InputLanguageSelection.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/InputLanguageSelection.java new file mode 100644 index 00000000..0d4d00c0 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/InputLanguageSelection.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2008-2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceGroup; +import android.preference.PreferenceManager; +import android.text.TextUtils; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Locale; + +public class InputLanguageSelection extends PreferenceActivity { + + private String mSelectedLanguages; + private ArrayList mAvailableLanguages = new ArrayList(); + + private static final String[] WHITELIST_LANGUAGES = { + "cs", "da", "de", "en_GB", "en_US", "es", "es_US", "fr", "it", "nb", "nl", "pl", "pt", + "ru", "tr", + }; + + private static boolean isWhitelisted(String lang) { + for (String s : WHITELIST_LANGUAGES) { + if (s.equalsIgnoreCase(lang)) { + return true; + } + } + return false; + } + + private static class Loc implements Comparable { + static Collator sCollator = Collator.getInstance(); + + String label; + Locale locale; + + public Loc(String label, Locale locale) { + this.label = label; + this.locale = locale; + } + + @Override + public String toString() { + return this.label; + } + + public int compareTo(Object o) { + return sCollator.compare(this.label, ((Loc) o).label); + } + } + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + addPreferencesFromResource(R.xml.language_prefs); + // Get the settings preferences + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + mSelectedLanguages = sp.getString(KP2AKeyboard.PREF_SELECTED_LANGUAGES, ""); + String[] languageList = mSelectedLanguages.split(","); + mAvailableLanguages = getUniqueLocales(); + PreferenceGroup parent = getPreferenceScreen(); + for (int i = 0; i < mAvailableLanguages.size(); i++) { + CheckBoxPreference pref = new CheckBoxPreference(this); + Locale locale = mAvailableLanguages.get(i).locale; + pref.setTitle(LanguageSwitcher.toTitleCase(locale.getDisplayName(locale), locale)); + boolean checked = isLocaleIn(locale, languageList); + pref.setChecked(checked); + if (hasDictionary(locale)) { + pref.setSummary(R.string.has_dictionary); + } + parent.addPreference(pref); + } + } + + private boolean isLocaleIn(Locale locale, String[] list) { + String lang = get5Code(locale); + for (int i = 0; i < list.length; i++) { + if (lang.equalsIgnoreCase(list[i])) return true; + } + return false; + } + + private boolean hasDictionary(Locale locale) { + Resources res = getResources(); + Configuration conf = res.getConfiguration(); + Locale saveLocale = conf.locale; + boolean haveDictionary = false; + conf.locale = locale; + res.updateConfiguration(conf, res.getDisplayMetrics()); + + int[] dictionaries = KP2AKeyboard.getDictionary(res); + BinaryDictionary bd = new BinaryDictionary(this, dictionaries, Suggest.DIC_MAIN); + + // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of + // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. + if (bd.getSize() > Suggest.LARGE_DICTIONARY_THRESHOLD / 4) { + haveDictionary = true; + } + bd.close(); + conf.locale = saveLocale; + res.updateConfiguration(conf, res.getDisplayMetrics()); + return haveDictionary; + } + + private String get5Code(Locale locale) { + String country = locale.getCountry(); + return locale.getLanguage() + + (TextUtils.isEmpty(country) ? "" : "_" + country); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + // Save the selected languages + String checkedLanguages = ""; + PreferenceGroup parent = getPreferenceScreen(); + int count = parent.getPreferenceCount(); + for (int i = 0; i < count; i++) { + CheckBoxPreference pref = (CheckBoxPreference) parent.getPreference(i); + if (pref.isChecked()) { + Locale locale = mAvailableLanguages.get(i).locale; + checkedLanguages += get5Code(locale) + ","; + } + } + if (checkedLanguages.length() < 1) checkedLanguages = null; // Save null + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + Editor editor = sp.edit(); + editor.putString(KP2AKeyboard.PREF_SELECTED_LANGUAGES, checkedLanguages); + SharedPreferencesCompat.apply(editor); + } + + ArrayList getUniqueLocales() { + String[] locales = getAssets().getLocales(); + Arrays.sort(locales); + ArrayList uniqueLocales = new ArrayList(); + + final int origSize = locales.length; + Loc[] preprocess = new Loc[origSize]; + int finalSize = 0; + for (int i = 0 ; i < origSize; i++ ) { + String s = locales[i]; + int len = s.length(); + final Locale l; + final String language; + if (len == 5) { + language = s.substring(0, 2); + String country = s.substring(3, 5); + l = new Locale(language, country); + } else if (len == 2) { + language = s; + l = new Locale(language); + } else { + continue; + } + // Exclude languages that are not relevant to LatinIME + if (!isWhitelisted(s)) continue; + + if (finalSize == 0) { + preprocess[finalSize++] = + new Loc(LanguageSwitcher.toTitleCase(l.getDisplayName(l), l), l); + } else { + // check previous entry: + // same lang and a country -> upgrade to full name and + // insert ours with full name + // diff lang -> insert ours with lang-only name + if (preprocess[finalSize-1].locale.getLanguage().equals( + language)) { + preprocess[finalSize-1].label = LanguageSwitcher.toTitleCase( + preprocess[finalSize-1].locale.getDisplayName(), + preprocess[finalSize-1].locale); + preprocess[finalSize++] = + new Loc(LanguageSwitcher.toTitleCase(l.getDisplayName(), l), l); + } else { + String displayName; + if (s.equals("zz_ZZ")) { + } else { + displayName = LanguageSwitcher.toTitleCase(l.getDisplayName(l), l); + preprocess[finalSize++] = new Loc(displayName, l); + } + } + } + } + for (int i = 0; i < finalSize ; i++) { + uniqueLocales.add(preprocess[i]); + } + return uniqueLocales; + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KP2AKeyboard.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KP2AKeyboard.java new file mode 100644 index 00000000..163f32c7 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KP2AKeyboard.java @@ -0,0 +1,2166 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.inputmethodservice.InputMethodService; +import android.inputmethodservice.Keyboard; +import android.media.AudioManager; +import android.os.Debug; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.preference.PreferenceActivity; +import android.preference.PreferenceManager; +import android.speech.SpeechRecognizer; +import android.text.ClipboardManager; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.PrintWriterPrinter; +import android.util.Printer; +import android.view.HapticFeedbackConstants; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; +import android.widget.LinearLayout; +import android.widget.Toast; + +import keepass2android.softkeyboard.LatinIMEUtil.RingCharBuffer; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Input method implementation for Qwerty'ish keyboard. + */ +public class KP2AKeyboard extends InputMethodService + implements LatinKeyboardBaseView.OnKeyboardActionListener, + SharedPreferences.OnSharedPreferenceChangeListener { + private static final String TAG = "LatinIME"; + private static final boolean PERF_DEBUG = false; + static final boolean DEBUG = false; + static final boolean TRACE = false; + + private static final String PREF_VIBRATE_ON = "vibrate_on"; + private static final String PREF_SOUND_ON = "sound_on"; + private static final String PREF_POPUP_ON = "popup_on"; + private static final String PREF_AUTO_CAP = "auto_cap"; + private static final String PREF_QUICK_FIXES = "quick_fixes"; + private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions"; + private static final String PREF_AUTO_COMPLETE = "auto_complete"; + //private static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion"; + + + public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; + public static final String PREF_INPUT_LANGUAGE = "input_language"; + private static final String PREF_RECORRECTION_ENABLED = "recorrection_enabled"; + + private static final int MSG_UPDATE_SUGGESTIONS = 0; + private static final int MSG_UPDATE_SHIFT_STATE = 2; + + private static final int MSG_UPDATE_OLD_SUGGESTIONS = 4; + + // How many continuous deletes at which to start deleting at a higher speed. + private static final int DELETE_ACCELERATE_AT = 20; + // Key events coming any faster than this are long-presses. + private static final int QUICK_PRESS = 200; + + static final int KEYCODE_ENTER = '\n'; + static final int KEYCODE_SPACE = ' '; + static final int KEYCODE_PERIOD = '.'; + + // Contextual menu positions + private static final int POS_METHOD = 0; + private static final int POS_SETTINGS = 1; + + //private LatinKeyboardView mInputView; + private LinearLayout mCandidateViewContainer; + private CandidateView mCandidateView; + private Suggest mSuggest; + private CompletionInfo[] mCompletions; + + private AlertDialog mOptionsDialog; + + /* package */ KeyboardSwitcher mKeyboardSwitcher; + + //dictionaries disabled for KP2A to reduce permissions + //private UserDictionary mUserDictionary; + //private UserBigramDictionary mUserBigramDictionary; + //private ContactsDictionary mContactsDictionary; + //private AutoDictionary mAutoDictionary; + + private Resources mResources; + + private String mInputLocale; + private String mSystemLocale; + private LanguageSwitcher mLanguageSwitcher; + + private StringBuilder mComposing = new StringBuilder(); + private WordComposer mWord = new WordComposer(); + private int mCommittedLength; + private boolean mPredicting; + private boolean mRecognizing; + private CharSequence mBestWord; + private boolean mPredictionOn; + private boolean mCompletionOn; + private boolean mHasDictionary; + private boolean mAutoSpace; + private boolean mJustAddedAutoSpace; + private boolean mAutoCorrectEnabled; + private boolean mReCorrectionEnabled; + // Bigram Suggestion is disabled in this version. + private final boolean mBigramSuggestionEnabled = false; + private boolean mAutoCorrectOn; + // TODO move this state variable outside LatinIME + private boolean mCapsLock; + private boolean mPasswordText; + private boolean mVibrateOn; + private boolean mSoundOn; + private boolean mPopupOn; + private boolean mAutoCap; + private boolean mQuickFixes; + private boolean mShowSuggestions; + private boolean mIsShowingHint; + private int mCorrectionMode; + private int mOrientation; + private List mSuggestPuncList; + // Keep track of the last selection range to decide if we need to show word alternatives + private int mLastSelectionStart; + private int mLastSelectionEnd; + + // Input type is such that we should not auto-correct + private boolean mInputTypeNoAutoCorrect; + + // Indicates whether the suggestion strip is to be on in landscape + private boolean mJustAccepted; + private CharSequence mJustRevertedSeparator; + private int mDeleteCount; + private long mLastKeyTime; + + // Modifier keys state + private ModifierKeyState mShiftKeyState = new ModifierKeyState(); + private ModifierKeyState mSymbolKeyState = new ModifierKeyState(); + + + private AudioManager mAudioManager; + // Align sound effect volume on music volume + private final float FX_VOLUME = -1.0f; + private boolean mSilentMode; + + /* package */ String mWordSeparators; + private String mSentenceSeparators; + private String mSuggestPuncs; + private boolean mConfigurationChanging; + + // Keeps track of most recently inserted text (multi-character key) for reverting + private CharSequence mEnteredText; + private boolean mRefreshKeyboardRequired; + + // For each word, a list of potential replacements, usually from voice. + private Map> mWordToSuggestions = + new HashMap>(); + + private ArrayList mWordHistory = new ArrayList(); + + + public abstract static class WordAlternatives { + protected CharSequence mChosenWord; + + public WordAlternatives() { + // Nothing + } + + public WordAlternatives(CharSequence chosenWord) { + mChosenWord = chosenWord; + } + + @Override + public int hashCode() { + return mChosenWord.hashCode(); + } + + public abstract CharSequence getOriginalWord(); + + public CharSequence getChosenWord() { + return mChosenWord; + } + + public abstract List getAlternatives(); + } + + public class TypedWordAlternatives extends WordAlternatives { + private WordComposer word; + + public TypedWordAlternatives() { + // Nothing + } + + public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { + super(chosenWord); + word = wordComposer; + } + + @Override + public CharSequence getOriginalWord() { + return word.getTypedWord(); + } + + @Override + public List getAlternatives() { + return getTypedSuggestions(word); + } + } + + /* package */ Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_SUGGESTIONS: + updateSuggestions(); + break; + case MSG_UPDATE_OLD_SUGGESTIONS: + setOldSuggestions(); + break; + case MSG_UPDATE_SHIFT_STATE: + updateShiftKeyState(getCurrentInputEditorInfo()); + break; + + } + } + }; + + @Override + public void onCreate() { + LatinImeLogger.init(this); + KeyboardSwitcher.init(this); + super.onCreate(); + //setStatusIcon(R.drawable.ime_qwerty); + mResources = getResources(); + final Configuration conf = mResources.getConfiguration(); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + mLanguageSwitcher = new LanguageSwitcher(this); + mLanguageSwitcher.loadLocales(prefs); + mKeyboardSwitcher = KeyboardSwitcher.getInstance(); + mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher); + mSystemLocale = conf.locale.toString(); + mLanguageSwitcher.setSystemLocale(conf.locale); + String inputLanguage = mLanguageSwitcher.getInputLanguage(); + if (inputLanguage == null) { + inputLanguage = conf.locale.toString(); + } + mReCorrectionEnabled = prefs.getBoolean(PREF_RECORRECTION_ENABLED, + getResources().getBoolean(R.bool.default_recorrection_enabled)); + + LatinIMEUtil.GCUtils.getInstance().reset(); + boolean tryGC = true; + for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { + try { + initSuggest(inputLanguage); + tryGC = false; + } catch (OutOfMemoryError e) { + tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(inputLanguage, e); + } + } + + mOrientation = conf.orientation; + initSuggestPuncList(); + + // register to receive ringer mode changes for silent mode + IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); + registerReceiver(mReceiver, filter); + + prefs.registerOnSharedPreferenceChangeListener(this); + } + + /** + * Loads a dictionary or multiple separated dictionary + * @return returns array of dictionary resource ids + */ + /* package */ static int[] getDictionary(Resources res) { + String packageName = KP2AKeyboard.class.getPackage().getName(); + XmlResourceParser xrp = res.getXml(R.xml.dictionary); + ArrayList dictionaries = new ArrayList(); + + try { + int current = xrp.getEventType(); + while (current != XmlResourceParser.END_DOCUMENT) { + if (current == XmlResourceParser.START_TAG) { + String tag = xrp.getName(); + if (tag != null) { + if (tag.equals("part")) { + String dictFileName = xrp.getAttributeValue(null, "name"); + dictionaries.add(res.getIdentifier(dictFileName, "raw", packageName)); + } + } + } + xrp.next(); + current = xrp.getEventType(); + } + } catch (XmlPullParserException e) { + Log.e(TAG, "Dictionary XML parsing failure"); + } catch (IOException e) { + Log.e(TAG, "Dictionary XML IOException"); + } + + int count = dictionaries.size(); + int[] dict = new int[count]; + for (int i = 0; i < count; i++) { + dict[i] = dictionaries.get(i); + } + + return dict; + } + + private void initSuggest(String locale) { + mInputLocale = locale; + + Resources orig = getResources(); + Configuration conf = orig.getConfiguration(); + Locale saveLocale = conf.locale; + conf.locale = new Locale(locale); + orig.updateConfiguration(conf, orig.getDisplayMetrics()); + if (mSuggest != null) { + mSuggest.close(); + } + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true); + + int[] dictionaries = getDictionary(orig); + mSuggest = new Suggest(this, dictionaries); + updateAutoTextEnabled(saveLocale); + //if (mUserDictionary != null) mUserDictionary.close(); + //mUserDictionary = new UserDictionary(this, mInputLocale); + /*if (mContactsDictionary == null) { + mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS); + } + if (mAutoDictionary != null) { + mAutoDictionary.close(); + } + mAutoDictionary = new AutoDictionary(this, this, mInputLocale, Suggest.DIC_AUTO);*/ + //if (mUserBigramDictionary != null) { + // mUserBigramDictionary.close(); + //} + //mUserBigramDictionary = new UserBigramDictionary(this, this, mInputLocale, + // Suggest.DIC_USER); + /*mSuggest.setUserBigramDictionary(mUserBigramDictionary); + mSuggest.setUserDictionary(mUserDictionary); + mSuggest.setContactsDictionary(mContactsDictionary); + mSuggest.setAutoDictionary(mAutoDictionary);*/ + updateCorrectionMode(); + mWordSeparators = mResources.getString(R.string.word_separators); + mSentenceSeparators = mResources.getString(R.string.sentence_separators); + + conf.locale = saveLocale; + orig.updateConfiguration(conf, orig.getDisplayMetrics()); + } + + @Override + public void onDestroy() { + /*if (mUserDictionary != null) { + mUserDictionary.close(); + } + if (mContactsDictionary != null) { + mContactsDictionary.close(); + }*/ + unregisterReceiver(mReceiver); + + LatinImeLogger.commit(); + LatinImeLogger.onDestroy(); + super.onDestroy(); + } + + @Override + public void onConfigurationChanged(Configuration conf) { + // If the system locale changes and is different from the saved + // locale (mSystemLocale), then reload the input locale list from the + // latin ime settings (shared prefs) and reset the input locale + // to the first one. + final String systemLocale = conf.locale.toString(); + if (!TextUtils.equals(systemLocale, mSystemLocale)) { + mSystemLocale = systemLocale; + if (mLanguageSwitcher != null) { + mLanguageSwitcher.loadLocales( + PreferenceManager.getDefaultSharedPreferences(this)); + mLanguageSwitcher.setSystemLocale(conf.locale); + toggleLanguage(true, true); + } else { + reloadKeyboards(); + } + } + // If orientation changed while predicting, commit the change + if (conf.orientation != mOrientation) { + InputConnection ic = getCurrentInputConnection(); + commitTyped(ic); + if (ic != null) ic.finishComposingText(); // For voice input + mOrientation = conf.orientation; + reloadKeyboards(); + } + mConfigurationChanging = true; + super.onConfigurationChanged(conf); + mConfigurationChanging = false; + } + + @Override + public View onCreateInputView() { + mKeyboardSwitcher.recreateInputView(); + mKeyboardSwitcher.makeKeyboards(true); + mKeyboardSwitcher.setKeyboardMode( + KeyboardSwitcher.MODE_TEXT, 0); + return mKeyboardSwitcher.getInputView(); + } + + @Override + public View onCreateCandidatesView() { + mKeyboardSwitcher.makeKeyboards(true); + mCandidateViewContainer = (LinearLayout) getLayoutInflater().inflate( + R.layout.candidates, null); + mCandidateView = (CandidateView) mCandidateViewContainer.findViewById(R.id.candidates); + mCandidateView.setService(this); + setCandidatesViewShown(true); + return mCandidateViewContainer; + } + + @Override + public void onStartInputView(EditorInfo attribute, boolean restarting) { + LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + // In landscape mode, this method gets called without the input view being created. + if (inputView == null) { + return; + } + + if (mRefreshKeyboardRequired) { + mRefreshKeyboardRequired = false; + toggleLanguage(true, true); + } + + mKeyboardSwitcher.makeKeyboards(false); + + TextEntryState.newSession(this); + + // Most such things we decide below in the switch statement, but we need to know + // now whether this is a password text field, because we need to know now (before + // the switch statement) whether we want to enable the voice button. + mPasswordText = false; + int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION; + if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD || + variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) { + mPasswordText = true; + } + + mInputTypeNoAutoCorrect = false; + mPredictionOn = false; + mCompletionOn = false; + mCompletions = null; + mCapsLock = false; + mEnteredText = null; + + switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) { + case EditorInfo.TYPE_CLASS_NUMBER: + case EditorInfo.TYPE_CLASS_DATETIME: + // fall through + // NOTE: For now, we use the phone keyboard for NUMBER and DATETIME until we get + // a dedicated number entry keypad. + // TODO: Use a dedicated number entry keypad here when we get one. + case EditorInfo.TYPE_CLASS_PHONE: + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_PHONE, + attribute.imeOptions); + break; + case EditorInfo.TYPE_CLASS_TEXT: + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT, + attribute.imeOptions); + //startPrediction(); + mPredictionOn = true; + // Make sure that passwords are not displayed in candidate view + if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD || + variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) { + mPredictionOn = false; + } + if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS + || variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) { + mAutoSpace = false; + } else { + mAutoSpace = true; + } + if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) { + mPredictionOn = false; + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_EMAIL, + attribute.imeOptions); + } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) { + mPredictionOn = false; + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_URL, + attribute.imeOptions); + } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) { + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_IM, + attribute.imeOptions); + } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) { + mPredictionOn = false; + } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) { + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_WEB, + attribute.imeOptions); + // If it's a browser edit field and auto correct is not ON explicitly, then + // disable auto correction, but keep suggestions on. + if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) { + mInputTypeNoAutoCorrect = true; + } + } + + // If NO_SUGGESTIONS is set, don't do prediction. + if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) { + mPredictionOn = false; + mInputTypeNoAutoCorrect = true; + } + // If it's not multiline and the autoCorrect flag is not set, then don't correct + if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 && + (attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { + mInputTypeNoAutoCorrect = true; + } + if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { + mPredictionOn = false; + mCompletionOn = isFullscreenMode(); + } + break; + default: + mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT, + attribute.imeOptions); + } + inputView.closing(); + mComposing.setLength(0); + mPredicting = false; + mDeleteCount = 0; + mJustAddedAutoSpace = false; + loadSettings(); + updateShiftKeyState(attribute); + + setCandidatesViewShownInternal(isCandidateStripVisible() || mCompletionOn, + false /* needsInputViewShown */ ); + updateSuggestions(); + + // If the dictionary is not big enough, don't auto correct + mHasDictionary = mSuggest.hasMainDictionary(); + + updateCorrectionMode(); + + inputView.setPreviewEnabled(mPopupOn); + inputView.setProximityCorrectionEnabled(true); + mPredictionOn = mPredictionOn && (mCorrectionMode > 0 || mShowSuggestions); + // If we just entered a text field, maybe it has some old text that requires correction + checkReCorrectionOnStart(); + + if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); + } + + private void checkReCorrectionOnStart() { + if (mReCorrectionEnabled && isPredictionOn()) { + // First get the cursor position. This is required by setOldSuggestions(), so that + // it can pass the correct range to setComposingRegion(). At this point, we don't + // have valid values for mLastSelectionStart/Stop because onUpdateSelection() has + // not been called yet. + InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + ExtractedTextRequest etr = new ExtractedTextRequest(); + etr.token = 0; // anything is fine here + ExtractedText et = ic.getExtractedText(etr, 0); + if (et == null) return; + + mLastSelectionStart = et.startOffset + et.selectionStart; + mLastSelectionEnd = et.startOffset + et.selectionEnd; + + // Then look for possible corrections in a delayed fashion + if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) { + postUpdateOldSuggestions(); + } + } + } + + @Override + public void onFinishInput() { + super.onFinishInput(); + + LatinImeLogger.commit(); + onAutoCompletionStateChanged(false); + + + if (mKeyboardSwitcher.getInputView() != null) { + mKeyboardSwitcher.getInputView().closing(); + } + //if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites(); + //if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites(); + } + + @Override + public void onFinishInputView(boolean finishingInput) { + super.onFinishInputView(finishingInput); + // Remove penging messages related to update suggestions + mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS); + mHandler.removeMessages(MSG_UPDATE_OLD_SUGGESTIONS); + } + + @Override + public void onUpdateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd, + int candidatesStart, int candidatesEnd) { + super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, + candidatesStart, candidatesEnd); + + if (DEBUG) { + Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart + + ", ose=" + oldSelEnd + + ", nss=" + newSelStart + + ", nse=" + newSelEnd + + ", cs=" + candidatesStart + + ", ce=" + candidatesEnd); + } + + // If the current selection in the text view changes, we should + // clear whatever candidate text we have. + if ((((mComposing.length() > 0 && mPredicting)) + && (newSelStart != candidatesEnd + || newSelEnd != candidatesEnd) + && mLastSelectionStart != newSelStart)) { + mComposing.setLength(0); + mPredicting = false; + postUpdateSuggestions(); + TextEntryState.reset(); + InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + ic.finishComposingText(); + } + } else if (!mPredicting && !mJustAccepted) { + switch (TextEntryState.getState()) { + case ACCEPTED_DEFAULT: + TextEntryState.reset(); + // fall through + case SPACE_AFTER_PICKED: + mJustAddedAutoSpace = false; // The user moved the cursor. + break; + } + } + mJustAccepted = false; + postUpdateShiftKeyState(); + + // Make a note of the cursor position + mLastSelectionStart = newSelStart; + mLastSelectionEnd = newSelEnd; + + if (mReCorrectionEnabled) { + // Don't look for corrections if the keyboard is not visible + if (mKeyboardSwitcher != null && mKeyboardSwitcher.getInputView() != null + && mKeyboardSwitcher.getInputView().isShown()) { + // Check if we should go in or out of correction mode. + if (isPredictionOn() + && mJustRevertedSeparator == null + && (candidatesStart == candidatesEnd || newSelStart != oldSelStart + || TextEntryState.isCorrecting()) + && (newSelStart < newSelEnd - 1 || (!mPredicting)) + ) { + if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) { + postUpdateOldSuggestions(); + } else { + abortCorrection(false); + // Show the punctuation suggestions list if the current one is not + // and if not showing "Touch again to save". + if (mCandidateView != null + && !mSuggestPuncList.equals(mCandidateView.getSuggestions()) + && !mCandidateView.isShowingAddToDictionaryHint()) { + setNextSuggestions(); + } + } + } + } + } + } + + /** + * This is called when the user has clicked on the extracted text view, + * when running in fullscreen mode. The default implementation hides + * the candidates view when this happens, but only if the extracted text + * editor has a vertical scroll bar because its text doesn't fit. + * Here we override the behavior due to the possibility that a re-correction could + * cause the candidate strip to disappear and re-appear. + */ + @Override + public void onExtractedTextClicked() { + if (mReCorrectionEnabled && isPredictionOn()) return; + + super.onExtractedTextClicked(); + } + + /** + * This is called when the user has performed a cursor movement in the + * extracted text view, when it is running in fullscreen mode. The default + * implementation hides the candidates view when a vertical movement + * happens, but only if the extracted text editor has a vertical scroll bar + * because its text doesn't fit. + * Here we override the behavior due to the possibility that a re-correction could + * cause the candidate strip to disappear and re-appear. + */ + @Override + public void onExtractedCursorMovement(int dx, int dy) { + if (mReCorrectionEnabled && isPredictionOn()) return; + + super.onExtractedCursorMovement(dx, dy); + } + + @Override + public void hideWindow() { + LatinImeLogger.commit(); + onAutoCompletionStateChanged(false); + + if (TRACE) Debug.stopMethodTracing(); + if (mOptionsDialog != null && mOptionsDialog.isShowing()) { + mOptionsDialog.dismiss(); + mOptionsDialog = null; + } + mWordToSuggestions.clear(); + mWordHistory.clear(); + super.hideWindow(); + TextEntryState.endSession(); + } + + @Override + public void onDisplayCompletions(CompletionInfo[] completions) { + if (DEBUG) { + Log.i("foo", "Received completions:"); + for (int i=0; i<(completions != null ? completions.length : 0); i++) { + Log.i("foo", " #" + i + ": " + completions[i]); + } + } + if (mCompletionOn) { + mCompletions = completions; + if (completions == null) { + clearSuggestions(); + return; + } + + List stringList = new ArrayList(); + for (int i=0; i<(completions != null ? completions.length : 0); i++) { + CompletionInfo ci = completions[i]; + if (ci != null) stringList.add(ci.getText()); + } + // When in fullscreen mode, show completions generated by the application + setSuggestions(stringList, true, true, true); + mBestWord = null; + setCandidatesViewShown(true); + } + } + + private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) { + // TODO: Remove this if we support candidates with hard keyboard + if (onEvaluateInputViewShown()) { + super.setCandidatesViewShown(shown && mKeyboardSwitcher.getInputView() != null + && (needsInputViewShown ? mKeyboardSwitcher.getInputView().isShown() : true)); + } + } + + @Override + public void setCandidatesViewShown(boolean shown) { + setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ ); + } + + @Override + public void onComputeInsets(InputMethodService.Insets outInsets) { + super.onComputeInsets(outInsets); + if (!isFullscreenMode()) { + outInsets.contentTopInsets = outInsets.visibleTopInsets; + } + } + + @Override + public boolean onEvaluateFullscreenMode() { + DisplayMetrics dm = getResources().getDisplayMetrics(); + float displayHeight = dm.heightPixels; + // If the display is more than X inches high, don't go to fullscreen mode + float dimen = getResources().getDimension(R.dimen.max_height_for_fullscreen); + if (displayHeight > dimen) { + return false; + } else { + return super.onEvaluateFullscreenMode(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: + if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) { + if (mKeyboardSwitcher.getInputView().handleBack()) { + return true; + } + } + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + break; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + // Enable shift key and DPAD to do selections + if (inputView != null && inputView.isShown() + && inputView.isShifted()) { + event = new KeyEvent(event.getDownTime(), event.getEventTime(), + event.getAction(), event.getKeyCode(), event.getRepeatCount(), + event.getDeviceId(), event.getScanCode(), + KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON); + InputConnection ic = getCurrentInputConnection(); + if (ic != null) ic.sendKeyEvent(event); + return true; + } + break; + } + return super.onKeyUp(keyCode, event); + } + + private void revertVoiceInput() { + InputConnection ic = getCurrentInputConnection(); + if (ic != null) ic.commitText("", 1); + updateSuggestions(); + } + + private void commitVoiceInput() { + InputConnection ic = getCurrentInputConnection(); + if (ic != null) ic.finishComposingText(); + updateSuggestions(); + } + + private void reloadKeyboards() { + mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher); + mKeyboardSwitcher.makeKeyboards(true); + } + + private void commitTyped(InputConnection inputConnection) { + if (mPredicting) { + mPredicting = false; + if (mComposing.length() > 0) { + if (inputConnection != null) { + inputConnection.commitText(mComposing, 1); + } + mCommittedLength = mComposing.length(); + TextEntryState.acceptedTyped(mComposing); + addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED); + } + updateSuggestions(); + } + } + + private void postUpdateShiftKeyState() { + mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); + // TODO: Should remove this 300ms delay? + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SHIFT_STATE), 300); + } + + public void updateShiftKeyState(EditorInfo attr) { + InputConnection ic = getCurrentInputConnection(); + if (ic != null && attr != null && mKeyboardSwitcher.isAlphabetMode()) { + mKeyboardSwitcher.setShifted(mShiftKeyState.isMomentary() || mCapsLock + || getCursorCapsMode(ic, attr) != 0); + } + } + + private int getCursorCapsMode(InputConnection ic, EditorInfo attr) { + int caps = 0; + EditorInfo ei = getCurrentInputEditorInfo(); + if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) { + caps = ic.getCursorCapsMode(attr.inputType); + } + return caps; + } + + private void swapPunctuationAndSpace() { + final InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + CharSequence lastTwo = ic.getTextBeforeCursor(2, 0); + if (lastTwo != null && lastTwo.length() == 2 + && lastTwo.charAt(0) == KEYCODE_SPACE && isSentenceSeparator(lastTwo.charAt(1))) { + ic.beginBatchEdit(); + ic.deleteSurroundingText(2, 0); + ic.commitText(lastTwo.charAt(1) + " ", 1); + ic.endBatchEdit(); + updateShiftKeyState(getCurrentInputEditorInfo()); + mJustAddedAutoSpace = true; + } + } + + private void reswapPeriodAndSpace() { + final InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + CharSequence lastThree = ic.getTextBeforeCursor(3, 0); + if (lastThree != null && lastThree.length() == 3 + && lastThree.charAt(0) == KEYCODE_PERIOD + && lastThree.charAt(1) == KEYCODE_SPACE + && lastThree.charAt(2) == KEYCODE_PERIOD) { + ic.beginBatchEdit(); + ic.deleteSurroundingText(3, 0); + ic.commitText(" ..", 1); + ic.endBatchEdit(); + updateShiftKeyState(getCurrentInputEditorInfo()); + } + } + + private void doubleSpace() { + //if (!mAutoPunctuate) return; + if (mCorrectionMode == Suggest.CORRECTION_NONE) return; + final InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + CharSequence lastThree = ic.getTextBeforeCursor(3, 0); + if (lastThree != null && lastThree.length() == 3 + && Character.isLetterOrDigit(lastThree.charAt(0)) + && lastThree.charAt(1) == KEYCODE_SPACE && lastThree.charAt(2) == KEYCODE_SPACE) { + ic.beginBatchEdit(); + ic.deleteSurroundingText(2, 0); + ic.commitText(". ", 1); + ic.endBatchEdit(); + updateShiftKeyState(getCurrentInputEditorInfo()); + mJustAddedAutoSpace = true; + } + } + + private void maybeRemovePreviousPeriod(CharSequence text) { + final InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + + // When the text's first character is '.', remove the previous period + // if there is one. + CharSequence lastOne = ic.getTextBeforeCursor(1, 0); + if (lastOne != null && lastOne.length() == 1 + && lastOne.charAt(0) == KEYCODE_PERIOD + && text.charAt(0) == KEYCODE_PERIOD) { + ic.deleteSurroundingText(1, 0); + } + } + + private void removeTrailingSpace() { + final InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + + CharSequence lastOne = ic.getTextBeforeCursor(1, 0); + if (lastOne != null && lastOne.length() == 1 + && lastOne.charAt(0) == KEYCODE_SPACE) { + ic.deleteSurroundingText(1, 0); + } + } + + public boolean addWordToDictionary(String word) { + //mUserDictionary.addWord(word, 128); + // Suggestion strip should be updated after the operation of adding word to the + // user dictionary + postUpdateSuggestions(); + return true; + } + + private boolean isAlphabet(int code) { + if (Character.isLetter(code)) { + return true; + } else { + return false; + } + } + + private void showInputMethodPicker() { + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) + .showInputMethodPicker(); + } + + private void onOptionKeyPressed() { + if (!isShowingOptionDialog()) { + if (LatinIMEUtil.hasMultipleEnabledIMEs(this)) { + showOptionsMenu(); + } else { + launchSettings(); + } + } + } + + private void onOptionKeyLongPressed() { + if (!isShowingOptionDialog()) { + if (LatinIMEUtil.hasMultipleEnabledIMEs(this)) { + showInputMethodPicker(); + } else { + launchSettings(); + } + } + } + + private boolean isShowingOptionDialog() { + return mOptionsDialog != null && mOptionsDialog.isShowing(); + } + + // Implementation of KeyboardViewListener + + public void onKey(int primaryCode, int[] keyCodes, int x, int y) { + long when = SystemClock.uptimeMillis(); + if (primaryCode != Keyboard.KEYCODE_DELETE || + when > mLastKeyTime + QUICK_PRESS) { + mDeleteCount = 0; + } + mLastKeyTime = when; + final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch(); + switch (primaryCode) { + case Keyboard.KEYCODE_DELETE: + handleBackspace(); + mDeleteCount++; + LatinImeLogger.logOnDelete(); + break; + case Keyboard.KEYCODE_SHIFT: + // Shift key is handled in onPress() when device has distinct multi-touch panel. + if (!distinctMultiTouch) + handleShift(); + break; + case Keyboard.KEYCODE_MODE_CHANGE: + // Symbol key is handled in onPress() when device has distinct multi-touch panel. + if (!distinctMultiTouch) + changeKeyboardMode(); + break; + case Keyboard.KEYCODE_CANCEL: + if (!isShowingOptionDialog()) { + handleClose(); + } + break; + case LatinKeyboardView.KEYCODE_OPTIONS: + onOptionKeyPressed(); + break; + case LatinKeyboardView.KEYCODE_KP2A: + onKp2aKeyPressed(); + break; + case LatinKeyboardView.KEYCODE_OPTIONS_LONGPRESS: + onOptionKeyLongPressed(); + break; + case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE: + toggleLanguage(false, true); + break; + case LatinKeyboardView.KEYCODE_PREV_LANGUAGE: + toggleLanguage(false, false); + break; + case 9 /*Tab*/: + sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); + break; + default: + if (primaryCode != KEYCODE_ENTER) { + mJustAddedAutoSpace = false; + } + RingCharBuffer.getInstance().push((char)primaryCode, x, y); + LatinImeLogger.logOnInputChar(); + if (isWordSeparator(primaryCode)) { + handleSeparator(primaryCode); + } else { + handleCharacter(primaryCode, keyCodes); + } + // Cancel the just reverted state + mJustRevertedSeparator = null; + } + mKeyboardSwitcher.onKey(primaryCode); + // Reset after any single keystroke + mEnteredText = null; + } + + private void onKp2aKeyPressed() { + Toast.makeText(getApplicationContext(), "KP2A", Toast.LENGTH_LONG).show(); + + } + + public void onText(CharSequence text) { + InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + abortCorrection(false); + ic.beginBatchEdit(); + if (mPredicting) { + commitTyped(ic); + } + maybeRemovePreviousPeriod(text); + ic.commitText(text, 1); + ic.endBatchEdit(); + updateShiftKeyState(getCurrentInputEditorInfo()); + mKeyboardSwitcher.onKey(0); // dummy key code. + mJustRevertedSeparator = null; + mJustAddedAutoSpace = false; + mEnteredText = text; + } + + public void onCancel() { + // User released a finger outside any key + mKeyboardSwitcher.onCancelInput(); + } + + private void handleBackspace() { + boolean deleteChar = false; + InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + + ic.beginBatchEdit(); + + + if (mPredicting) { + final int length = mComposing.length(); + if (length > 0) { + mComposing.delete(length - 1, length); + mWord.deleteLast(); + ic.setComposingText(mComposing, 1); + if (mComposing.length() == 0) { + mPredicting = false; + } + postUpdateSuggestions(); + } else { + ic.deleteSurroundingText(1, 0); + } + } else { + deleteChar = true; + } + postUpdateShiftKeyState(); + TextEntryState.backspace(); + if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) { + revertLastWord(deleteChar); + ic.endBatchEdit(); + return; + } else if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { + ic.deleteSurroundingText(mEnteredText.length(), 0); + } else if (deleteChar) { + if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) { + // Go back to the suggestion mode if the user canceled the + // "Touch again to save". + // NOTE: In gerenal, we don't revert the word when backspacing + // from a manual suggestion pick. We deliberately chose a + // different behavior only in the case of picking the first + // suggestion (typed word). It's intentional to have made this + // inconsistent with backspacing after selecting other suggestions. + revertLastWord(deleteChar); + } else { + sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + if (mDeleteCount > DELETE_ACCELERATE_AT) { + sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + } + } + } + mJustRevertedSeparator = null; + ic.endBatchEdit(); + } + + private void resetShift() { + handleShiftInternal(true); + } + + private void handleShift() { + handleShiftInternal(false); + } + + private void handleShiftInternal(boolean forceNormal) { + mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); + KeyboardSwitcher switcher = mKeyboardSwitcher; + LatinKeyboardView inputView = switcher.getInputView(); + if (switcher.isAlphabetMode()) { + if (mCapsLock || forceNormal) { + mCapsLock = false; + switcher.setShifted(false); + } else if (inputView != null) { + if (inputView.isShifted()) { + mCapsLock = true; + switcher.setShiftLocked(true); + } else { + switcher.setShifted(true); + } + } + } else { + switcher.toggleShift(); + } + } + + private void abortCorrection(boolean force) { + if (force || TextEntryState.isCorrecting()) { + getCurrentInputConnection().finishComposingText(); + clearSuggestions(); + } + } + + private void handleCharacter(int primaryCode, int[] keyCodes) { + + if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) { + abortCorrection(false); + } + + if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) { + if (!mPredicting) { + mPredicting = true; + mComposing.setLength(0); + saveWordInHistory(mBestWord); + mWord.reset(); + } + } + if (mKeyboardSwitcher.getInputView().isShifted()) { + if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT + || keyCodes[0] > Character.MAX_CODE_POINT) { + return; + } + primaryCode = keyCodes[0]; + if (mKeyboardSwitcher.isAlphabetMode() && Character.isLowerCase(primaryCode)) { + // In some locales, such as Turkish, Character.toUpperCase() may return a wrong + // character because it doesn't take care of locale. + final String upperCaseString = new String(new int[] {primaryCode}, 0, 1) + .toUpperCase(mLanguageSwitcher.getInputLocale()); + if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) { + primaryCode = upperCaseString.codePointAt(0); + } else { + // Some keys, such as [eszett], have upper case as multi-characters. + onText(upperCaseString); + return; + } + } + } + if (mPredicting) { + if (mKeyboardSwitcher.getInputView().isShifted() + && mKeyboardSwitcher.isAlphabetMode() + && mComposing.length() == 0) { + mWord.setFirstCharCapitalized(true); + } + mComposing.append((char) primaryCode); + mWord.add(primaryCode, keyCodes); + InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + // If it's the first letter, make note of auto-caps state + if (mWord.size() == 1) { + mWord.setAutoCapitalized( + getCursorCapsMode(ic, getCurrentInputEditorInfo()) != 0); + } + ic.setComposingText(mComposing, 1); + } + postUpdateSuggestions(); + } else { + sendKeyChar((char)primaryCode); + } + updateShiftKeyState(getCurrentInputEditorInfo()); + if (KP2AKeyboard.PERF_DEBUG) measureCps(); + TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode)); + } + + private void handleSeparator(int primaryCode) { + // Should dismiss the "Touch again to save" message when handling separator + if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) { + postUpdateSuggestions(); + } + + boolean pickedDefault = false; + // Handle separator + InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + ic.beginBatchEdit(); + abortCorrection(false); + } + if (mPredicting) { + // In certain languages where single quote is a separator, it's better + // not to auto correct, but accept the typed word. For instance, + // in Italian dov' should not be expanded to dove' because the elision + // requires the last vowel to be removed. + if (mAutoCorrectOn && primaryCode != '\'' && + (mJustRevertedSeparator == null + || mJustRevertedSeparator.length() == 0 + || mJustRevertedSeparator.charAt(0) != primaryCode)) { + pickedDefault = pickDefaultSuggestion(); + // Picked the suggestion by the space key. We consider this + // as "added an auto space". + if (primaryCode == KEYCODE_SPACE) { + mJustAddedAutoSpace = true; + } + } else { + commitTyped(ic); + } + } + if (mJustAddedAutoSpace && primaryCode == KEYCODE_ENTER) { + removeTrailingSpace(); + mJustAddedAutoSpace = false; + } + sendKeyChar((char)primaryCode); + + // Handle the case of ". ." -> " .." with auto-space if necessary + // before changing the TextEntryState. + if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED + && primaryCode == KEYCODE_PERIOD) { + reswapPeriodAndSpace(); + } + + TextEntryState.typedCharacter((char) primaryCode, true); + if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED + && primaryCode != KEYCODE_ENTER) { + swapPunctuationAndSpace(); + } else if (isPredictionOn() && primaryCode == KEYCODE_SPACE) { + doubleSpace(); + } + if (pickedDefault) { + TextEntryState.backToAcceptedDefault(mWord.getTypedWord()); + } + updateShiftKeyState(getCurrentInputEditorInfo()); + if (ic != null) { + ic.endBatchEdit(); + } + } + + private void handleClose() { + commitTyped(getCurrentInputConnection()); + requestHideSelf(0); + if (mKeyboardSwitcher != null) { + LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + if (inputView != null) { + inputView.closing(); + } + } + TextEntryState.endSession(); + } + + private void saveWordInHistory(CharSequence result) { + if (mWord.size() <= 1) { + mWord.reset(); + return; + } + // Skip if result is null. It happens in some edge case. + if (TextUtils.isEmpty(result)) { + return; + } + + // Make a copy of the CharSequence, since it is/could be a mutable CharSequence + final String resultCopy = result.toString(); + TypedWordAlternatives entry = new TypedWordAlternatives(resultCopy, + new WordComposer(mWord)); + mWordHistory.add(entry); + } + + private void postUpdateSuggestions() { + mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100); + } + + private void postUpdateOldSuggestions() { + mHandler.removeMessages(MSG_UPDATE_OLD_SUGGESTIONS); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS), 300); + } + + private boolean isPredictionOn() { + return mPredictionOn; + } + + private boolean isCandidateStripVisible() { + return isPredictionOn() && mShowSuggestions; + } + + public void onCancelVoice() { + if (mRecognizing) { + switchToKeyboardView(); + } + } + + private void switchToKeyboardView() { + mHandler.post(new Runnable() { + public void run() { + mRecognizing = false; + if (mKeyboardSwitcher.getInputView() != null) { + setInputView(mKeyboardSwitcher.getInputView()); + } + setCandidatesViewShown(true); + updateInputViewShown(); + postUpdateSuggestions(); + }}); + } + + private void clearSuggestions() { + setSuggestions(null, false, false, false); + } + + private void setSuggestions( + List suggestions, + boolean completions, + boolean typedWordValid, + boolean haveMinimalSuggestion) { + + if (mIsShowingHint) { + setCandidatesView(mCandidateViewContainer); + mIsShowingHint = false; + } + + if (mCandidateView != null) { + mCandidateView.setSuggestions( + suggestions, completions, typedWordValid, haveMinimalSuggestion); + } + } + + private void updateSuggestions() { + LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null); + + // Check if we have a suggestion engine attached. + if ((mSuggest == null || !isPredictionOn())) { + return; + } + + if (!mPredicting) { + setNextSuggestions(); + return; + } + showSuggestions(mWord); + } + + private List getTypedSuggestions(WordComposer word) { + List stringList = mSuggest.getSuggestions( + mKeyboardSwitcher.getInputView(), word, false, null); + return stringList; + } + + private void showCorrections(WordAlternatives alternatives) { + List stringList = alternatives.getAlternatives(); + ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).setPreferredLetters(null); + showSuggestions(stringList, alternatives.getOriginalWord(), false, false); + } + + private void showSuggestions(WordComposer word) { + // long startTime = System.currentTimeMillis(); // TIME MEASUREMENT! + // TODO Maybe need better way of retrieving previous word + CharSequence prevWord = EditingUtil.getPreviousWord(getCurrentInputConnection(), + mWordSeparators); + List stringList = mSuggest.getSuggestions( + mKeyboardSwitcher.getInputView(), word, false, prevWord); + // long stopTime = System.currentTimeMillis(); // TIME MEASUREMENT! + // Log.d("LatinIME","Suggest Total Time - " + (stopTime - startTime)); + + int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies(); + + ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).setPreferredLetters( + nextLettersFrequencies); + + boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasMinimalCorrection(); + //|| mCorrectionMode == mSuggest.CORRECTION_FULL; + CharSequence typedWord = word.getTypedWord(); + // If we're in basic correct + boolean typedWordValid = mSuggest.isValidWord(typedWord) || + (preferCapitalization() + && mSuggest.isValidWord(typedWord.toString().toLowerCase())); + if (mCorrectionMode == Suggest.CORRECTION_FULL + || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { + correctionAvailable |= typedWordValid; + } + // Don't auto-correct words with multiple capital letter + correctionAvailable &= !word.isMostlyCaps(); + correctionAvailable &= !TextEntryState.isCorrecting(); + + showSuggestions(stringList, typedWord, typedWordValid, correctionAvailable); + } + + private void showSuggestions(List stringList, CharSequence typedWord, + boolean typedWordValid, boolean correctionAvailable) { + setSuggestions(stringList, false, typedWordValid, correctionAvailable); + if (stringList.size() > 0) { + if (correctionAvailable && !typedWordValid && stringList.size() > 1) { + mBestWord = stringList.get(1); + } else { + mBestWord = typedWord; + } + } else { + mBestWord = null; + } + setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn); + } + + private boolean pickDefaultSuggestion() { + // Complete any pending candidate query first + if (mHandler.hasMessages(MSG_UPDATE_SUGGESTIONS)) { + mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS); + updateSuggestions(); + } + if (mBestWord != null && mBestWord.length() > 0) { + TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord); + mJustAccepted = true; + pickSuggestion(mBestWord, false); + // Add the word to the auto dictionary if it's not a known word + addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED); + return true; + + } + return false; + } + + public void pickSuggestionManually(int index, CharSequence suggestion) { + List suggestions = mCandidateView.getSuggestions(); + + + + final boolean correcting = TextEntryState.isCorrecting(); + InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + ic.beginBatchEdit(); + } + if (mCompletionOn && mCompletions != null && index >= 0 + && index < mCompletions.length) { + CompletionInfo ci = mCompletions[index]; + if (ic != null) { + ic.commitCompletion(ci); + } + mCommittedLength = suggestion.length(); + if (mCandidateView != null) { + mCandidateView.clear(); + } + updateShiftKeyState(getCurrentInputEditorInfo()); + if (ic != null) { + ic.endBatchEdit(); + } + return; + } + + // If this is a punctuation, apply it through the normal key press + if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0)) + || isSuggestedPunctuation(suggestion.charAt(0)))) { + // Word separators are suggested before the user inputs something. + // So, LatinImeLogger logs "" as a user's input. + LatinImeLogger.logOnManualSuggestion( + "", suggestion.toString(), index, suggestions); + final char primaryCode = suggestion.charAt(0); + onKey(primaryCode, new int[]{primaryCode}, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, + LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); + if (ic != null) { + ic.endBatchEdit(); + } + return; + } + mJustAccepted = true; + pickSuggestion(suggestion, correcting); + // Add the word to the auto dictionary if it's not a known word + if (index == 0) { + addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED); + } else { + addToBigramDictionary(suggestion, 1); + } + LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(), + index, suggestions); + TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion); + // Follow it with a space + if (mAutoSpace && !correcting) { + sendSpace(); + mJustAddedAutoSpace = true; + } + + final boolean showingAddToDictionaryHint = index == 0 && mCorrectionMode > 0 + && !mSuggest.isValidWord(suggestion) + && !mSuggest.isValidWord(suggestion.toString().toLowerCase()); + + if (!correcting) { + // Fool the state watcher so that a subsequent backspace will not do a revert, unless + // we just did a correction, in which case we need to stay in + // TextEntryState.State.PICKED_SUGGESTION state. + TextEntryState.typedCharacter((char) KEYCODE_SPACE, true); + setNextSuggestions(); + } else if (!showingAddToDictionaryHint) { + // If we're not showing the "Touch again to save", then show corrections again. + // In case the cursor position doesn't change, make sure we show the suggestions again. + clearSuggestions(); + postUpdateOldSuggestions(); + } + if (showingAddToDictionaryHint) { + mCandidateView.showAddToDictionaryHint(suggestion); + } + if (ic != null) { + ic.endBatchEdit(); + } + } + + private void rememberReplacedWord(CharSequence suggestion) { + + } + + /** + * Commits the chosen word to the text field and saves it for later + * retrieval. + * @param suggestion the suggestion picked by the user to be committed to + * the text field + * @param correcting whether this is due to a correction of an existing + * word. + */ + private void pickSuggestion(CharSequence suggestion, boolean correcting) { + final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + final Locale inputLocale = mLanguageSwitcher.getInputLocale(); + if (mCapsLock) { + suggestion = suggestion.toString().toUpperCase(inputLocale); + } else if (preferCapitalization() + || (mKeyboardSwitcher.isAlphabetMode() + && inputView.isShifted())) { + suggestion = suggestion.toString().toUpperCase(inputLocale).charAt(0) + + suggestion.subSequence(1, suggestion.length()).toString(); + } + InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + rememberReplacedWord(suggestion); + ic.commitText(suggestion, 1); + } + saveWordInHistory(suggestion); + mPredicting = false; + mCommittedLength = suggestion.length(); + ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null); + // If we just corrected a word, then don't show punctuations + if (!correcting) { + setNextSuggestions(); + } + updateShiftKeyState(getCurrentInputEditorInfo()); + } + + /** + * Tries to apply any typed alternatives for the word if we have any cached alternatives, + * otherwise tries to find new corrections and completions for the word. + * @param touching The word that the cursor is touching, with position information + * @return true if an alternative was found, false otherwise. + */ + private boolean applyTypedAlternatives(EditingUtil.SelectedWord touching) { + // If we didn't find a match, search for result in typed word history + WordComposer foundWord = null; + WordAlternatives alternatives = null; + for (WordAlternatives entry : mWordHistory) { + if (TextUtils.equals(entry.getChosenWord(), touching.word)) { + if (entry instanceof TypedWordAlternatives) { + foundWord = ((TypedWordAlternatives) entry).word; + } + alternatives = entry; + break; + } + } + // If we didn't find a match, at least suggest completions + if (foundWord == null + && (mSuggest.isValidWord(touching.word) + || mSuggest.isValidWord(touching.word.toString().toLowerCase()))) { + foundWord = new WordComposer(); + for (int i = 0; i < touching.word.length(); i++) { + foundWord.add(touching.word.charAt(i), new int[] { + touching.word.charAt(i) + }); + } + foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.word.charAt(0))); + } + // Found a match, show suggestions + if (foundWord != null || alternatives != null) { + if (alternatives == null) { + alternatives = new TypedWordAlternatives(touching.word, foundWord); + } + showCorrections(alternatives); + if (foundWord != null) { + mWord = new WordComposer(foundWord); + } else { + mWord.reset(); + } + return true; + } + return false; + } + + private void setOldSuggestions() { + + if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) { + return; + } + InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + if (!mPredicting) { + // Extract the selected or touching text + EditingUtil.SelectedWord touching = EditingUtil.getWordAtCursorOrSelection(ic, + mLastSelectionStart, mLastSelectionEnd, mWordSeparators); + + if (touching != null && touching.word.length() > 1) { + ic.beginBatchEdit(); + + if (!applyTypedAlternatives(touching)) { + abortCorrection(true); + } else { + TextEntryState.selectedForCorrection(); + EditingUtil.underlineWord(ic, touching); + } + + ic.endBatchEdit(); + } else { + abortCorrection(true); + setNextSuggestions(); // Show the punctuation suggestions list + } + } else { + abortCorrection(true); + } + } + + private void setNextSuggestions() { + setSuggestions(mSuggestPuncList, false, false, false); + } + + private void addToDictionaries(CharSequence suggestion, int frequencyDelta) { + checkAddToDictionary(suggestion, frequencyDelta, false); + } + + private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) { + checkAddToDictionary(suggestion, frequencyDelta, true); + } + + /** + * Adds to the UserBigramDictionary and/or AutoDictionary + * @param addToBigramDictionary true if it should be added to bigram dictionary if possible + */ + private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta, + boolean addToBigramDictionary) { + if (suggestion == null || suggestion.length() < 1) return; + // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be + // adding words in situations where the user or application really didn't + // want corrections enabled or learned. + if (!(mCorrectionMode == Suggest.CORRECTION_FULL + || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) { + return; + } + if (suggestion != null) { + /*if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion) + || (!mSuggest.isValidWord(suggestion.toString()) + && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) { + mAutoDictionary.addWord(suggestion.toString(), frequencyDelta); + } + + if (mUserBigramDictionary != null) { + CharSequence prevWord = EditingUtil.getPreviousWord(getCurrentInputConnection(), + mSentenceSeparators); + if (!TextUtils.isEmpty(prevWord)) { + mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString()); + } + }*/ + } + } + + private boolean isCursorTouchingWord() { + InputConnection ic = getCurrentInputConnection(); + if (ic == null) return false; + CharSequence toLeft = ic.getTextBeforeCursor(1, 0); + CharSequence toRight = ic.getTextAfterCursor(1, 0); + if (!TextUtils.isEmpty(toLeft) + && !isWordSeparator(toLeft.charAt(0)) + && !isSuggestedPunctuation(toLeft.charAt(0))) { + return true; + } + if (!TextUtils.isEmpty(toRight) + && !isWordSeparator(toRight.charAt(0)) + && !isSuggestedPunctuation(toRight.charAt(0))) { + return true; + } + return false; + } + + private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) { + CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); + return TextUtils.equals(text, beforeText); + } + + public void revertLastWord(boolean deleteChar) { + final int length = mComposing.length(); + if (!mPredicting && length > 0) { + final InputConnection ic = getCurrentInputConnection(); + mPredicting = true; + mJustRevertedSeparator = ic.getTextBeforeCursor(1, 0); + if (deleteChar) ic.deleteSurroundingText(1, 0); + int toDelete = mCommittedLength; + CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); + if (toTheLeft != null && toTheLeft.length() > 0 + && isWordSeparator(toTheLeft.charAt(0))) { + toDelete--; + } + ic.deleteSurroundingText(toDelete, 0); + ic.setComposingText(mComposing, 1); + TextEntryState.backspace(); + postUpdateSuggestions(); + } else { + sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + mJustRevertedSeparator = null; + } + } + + protected String getWordSeparators() { + return mWordSeparators; + } + + public boolean isWordSeparator(int code) { + String separators = getWordSeparators(); + return separators.contains(String.valueOf((char)code)); + } + + private boolean isSentenceSeparator(int code) { + return mSentenceSeparators.contains(String.valueOf((char)code)); + } + + private void sendSpace() { + sendKeyChar((char)KEYCODE_SPACE); + updateShiftKeyState(getCurrentInputEditorInfo()); + //onKey(KEY_SPACE[0], KEY_SPACE); + } + + public boolean preferCapitalization() { + return mWord.isFirstCharCapitalized(); + } + + private void toggleLanguage(boolean reset, boolean next) { + if (reset) { + mLanguageSwitcher.reset(); + } else { + if (next) { + mLanguageSwitcher.next(); + } else { + mLanguageSwitcher.prev(); + } + } + int currentKeyboardMode = mKeyboardSwitcher.getKeyboardMode(); + reloadKeyboards(); + mKeyboardSwitcher.makeKeyboards(true); + mKeyboardSwitcher.setKeyboardMode(currentKeyboardMode, 0); + initSuggest(mLanguageSwitcher.getInputLanguage()); + mLanguageSwitcher.persist(); + updateShiftKeyState(getCurrentInputEditorInfo()); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (PREF_SELECTED_LANGUAGES.equals(key)) { + mLanguageSwitcher.loadLocales(sharedPreferences); + mRefreshKeyboardRequired = true; + } else if (PREF_RECORRECTION_ENABLED.equals(key)) { + mReCorrectionEnabled = sharedPreferences.getBoolean(PREF_RECORRECTION_ENABLED, + getResources().getBoolean(R.bool.default_recorrection_enabled)); + } + } + + public void swipeRight() { + if (LatinKeyboardView.DEBUG_AUTO_PLAY) { + ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE)); + CharSequence text = cm.getText(); + if (!TextUtils.isEmpty(text)) { + mKeyboardSwitcher.getInputView().startPlaying(text.toString()); + } + } + } + + public void swipeLeft() { + } + + public void swipeDown() { + handleClose(); + } + + public void swipeUp() { + //launchSettings(); + } + + public void onPress(int primaryCode) { + if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) { + vibrate(); + playKeyClick(primaryCode); + } + final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch(); + if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) { + mShiftKeyState.onPress(); + handleShift(); + } else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) { + changeKeyboardMode(); + mSymbolKeyState.onPress(); + mKeyboardSwitcher.setAutoModeSwitchStateMomentary(); + } else { + mShiftKeyState.onOtherKeyPressed(); + mSymbolKeyState.onOtherKeyPressed(); + } + } + + public void onRelease(int primaryCode) { + // Reset any drag flags in the keyboard + ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased(); + //vibrate(); + final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch(); + if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) { + if (mShiftKeyState.isMomentary()) + resetShift(); + mShiftKeyState.onRelease(); + } else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) { + // Snap back to the previous keyboard mode if the user chords the mode change key and + // other key, then released the mode change key. + if (mKeyboardSwitcher.isInChordingAutoModeSwitchState()) + changeKeyboardMode(); + mSymbolKeyState.onRelease(); + } + } + + + + // receive ringer mode changes to detect silent mode + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateRingerMode(); + } + }; + + // update flags for silent mode + private void updateRingerMode() { + if (mAudioManager == null) { + mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + } + if (mAudioManager != null) { + mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL); + } + } + + private void playKeyClick(int primaryCode) { + // if mAudioManager is null, we don't have the ringer state yet + // mAudioManager will be set by updateRingerMode + if (mAudioManager == null) { + if (mKeyboardSwitcher.getInputView() != null) { + updateRingerMode(); + } + } + if (mSoundOn && !mSilentMode) { + // FIXME: Volume and enable should come from UI settings + // FIXME: These should be triggered after auto-repeat logic + int sound = AudioManager.FX_KEYPRESS_STANDARD; + switch (primaryCode) { + case Keyboard.KEYCODE_DELETE: + sound = AudioManager.FX_KEYPRESS_DELETE; + break; + case KEYCODE_ENTER: + sound = AudioManager.FX_KEYPRESS_RETURN; + break; + case KEYCODE_SPACE: + sound = AudioManager.FX_KEYPRESS_SPACEBAR; + break; + } + mAudioManager.playSoundEffect(sound, FX_VOLUME); + } + } + + private void vibrate() { + if (!mVibrateOn) { + return; + } + if (mKeyboardSwitcher.getInputView() != null) { + mKeyboardSwitcher.getInputView().performHapticFeedback( + HapticFeedbackConstants.KEYBOARD_TAP, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + + /* package */ void promoteToUserDictionary(String word, int frequency) { + //if (mUserDictionary.isValidWord(word)) return; + //mUserDictionary.addWord(word, frequency); + } + + /* package */ WordComposer getCurrentWord() { + return mWord; + } + + /* package */ boolean getPopupOn() { + return mPopupOn; + } + + private void updateCorrectionMode() { + mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false; + mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes) + && !mInputTypeNoAutoCorrect && mHasDictionary; + mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled) + ? Suggest.CORRECTION_FULL + : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE); + mCorrectionMode = (mBigramSuggestionEnabled && mAutoCorrectOn && mAutoCorrectEnabled) + ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode; + if (mSuggest != null) { + mSuggest.setCorrectionMode(mCorrectionMode); + } + } + + private void updateAutoTextEnabled(Locale systemLocale) { + if (mSuggest == null) return; + boolean different = + !systemLocale.getLanguage().equalsIgnoreCase(mInputLocale.substring(0, 2)); + mSuggest.setAutoTextEnabled(!different && mQuickFixes); + } + + protected void launchSettings() { + launchSettings(LatinIMESettings.class); + } + + public void launchDebugSettings() { + launchSettings(LatinIMEDebugSettings.class); + } + + protected void launchSettings (Class settingsClass) { + handleClose(); + Intent intent = new Intent(); + intent.setClass(KP2AKeyboard.this, settingsClass); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + + private void loadSettings() { + // Get the settings preferences + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, false); + mSoundOn = sp.getBoolean(PREF_SOUND_ON, false); + mPopupOn = sp.getBoolean(PREF_POPUP_ON, + mResources.getBoolean(R.bool.default_popup_preview)); + mAutoCap = sp.getBoolean(PREF_AUTO_CAP, true); + mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true); + + + mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true); + + mAutoCorrectEnabled = sp.getBoolean(PREF_AUTO_COMPLETE, + mResources.getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions; + //mBigramSuggestionEnabled = sp.getBoolean( + // PREF_BIGRAM_SUGGESTIONS, true) & mShowSuggestions; + updateCorrectionMode(); + updateAutoTextEnabled(mResources.getConfiguration().locale); + mLanguageSwitcher.loadLocales(sp); + } + + private void initSuggestPuncList() { + mSuggestPuncList = new ArrayList(); + mSuggestPuncs = mResources.getString(R.string.suggested_punctuations); + if (mSuggestPuncs != null) { + for (int i = 0; i < mSuggestPuncs.length(); i++) { + mSuggestPuncList.add(mSuggestPuncs.subSequence(i, i + 1)); + } + } + } + + private boolean isSuggestedPunctuation(int code) { + return mSuggestPuncs.contains(String.valueOf((char)code)); + } + + private void showOptionsMenu() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setCancelable(true); + builder.setIcon(R.drawable.ic_dialog_keyboard); + builder.setNegativeButton(android.R.string.cancel, null); + CharSequence itemSettings = getString(R.string.english_ime_settings); + CharSequence itemInputMethod = getString(R.string.selectInputMethod); + builder.setItems(new CharSequence[] { + itemInputMethod, itemSettings}, + new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface di, int position) { + di.dismiss(); + switch (position) { + case POS_SETTINGS: + launchSettings(); + break; + case POS_METHOD: + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) + .showInputMethodPicker(); + break; + } + } + }); + builder.setTitle(mResources.getString(R.string.english_ime_input_options)); + mOptionsDialog = builder.create(); + Window window = mOptionsDialog.getWindow(); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.token = mKeyboardSwitcher.getInputView().getWindowToken(); + lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; + window.setAttributes(lp); + window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + mOptionsDialog.show(); + } + + public void changeKeyboardMode() { + mKeyboardSwitcher.toggleSymbols(); + if (mCapsLock && mKeyboardSwitcher.isAlphabetMode()) { + mKeyboardSwitcher.setShiftLocked(mCapsLock); + } + + updateShiftKeyState(getCurrentInputEditorInfo()); + } + + public static ArrayList newArrayList(E... elements) { + int capacity = (elements.length * 110) / 100 + 5; + ArrayList list = new ArrayList(capacity); + Collections.addAll(list, elements); + return list; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { + super.dump(fd, fout, args); + + final Printer p = new PrintWriterPrinter(fout); + p.println("LatinIME state :"); + p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode()); + p.println(" mCapsLock=" + mCapsLock); + p.println(" mComposing=" + mComposing.toString()); + p.println(" mPredictionOn=" + mPredictionOn); + p.println(" mCorrectionMode=" + mCorrectionMode); + p.println(" mPredicting=" + mPredicting); + p.println(" mAutoCorrectOn=" + mAutoCorrectOn); + p.println(" mAutoSpace=" + mAutoSpace); + p.println(" mCompletionOn=" + mCompletionOn); + p.println(" TextEntryState.state=" + TextEntryState.getState()); + p.println(" mSoundOn=" + mSoundOn); + p.println(" mVibrateOn=" + mVibrateOn); + p.println(" mPopupOn=" + mPopupOn); + } + + // Characters per second measurement + + private long mLastCpsTime; + private static final int CPS_BUFFER_SIZE = 16; + private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE]; + private int mCpsIndex; + + private void measureCps() { + long now = System.currentTimeMillis(); + if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial + mCpsIntervals[mCpsIndex] = now - mLastCpsTime; + mLastCpsTime = now; + mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE; + long total = 0; + for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i]; + System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total)); + } + + public void onAutoCompletionStateChanged(boolean isAutoCompletion) { + mKeyboardSwitcher.onAutoCompletionStateChanged(isAutoCompletion); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KeyDetector.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KeyDetector.java new file mode 100644 index 00000000..d43e685b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KeyDetector.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; + +import java.util.Arrays; +import java.util.List; + +abstract class KeyDetector { + protected Keyboard mKeyboard; + + private Key[] mKeys; + + protected int mCorrectionX; + + protected int mCorrectionY; + + protected boolean mProximityCorrectOn; + + protected int mProximityThresholdSquare; + + public Key[] setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { + if (keyboard == null) + throw new NullPointerException(); + mCorrectionX = (int)correctionX; + mCorrectionY = (int)correctionY; + mKeyboard = keyboard; + List keys = mKeyboard.getKeys(); + Key[] array = keys.toArray(new Key[keys.size()]); + mKeys = array; + return array; + } + + protected int getTouchX(int x) { + return x + mCorrectionX; + } + + protected int getTouchY(int y) { + return y + mCorrectionY; + } + + protected Key[] getKeys() { + if (mKeys == null) + throw new IllegalStateException("keyboard isn't set"); + // mKeyboard is guaranteed not to be null at setKeybaord() method if mKeys is not null + return mKeys; + } + + public void setProximityCorrectionEnabled(boolean enabled) { + mProximityCorrectOn = enabled; + } + + public boolean isProximityCorrectionEnabled() { + return mProximityCorrectOn; + } + + public void setProximityThreshold(int threshold) { + mProximityThresholdSquare = threshold * threshold; + } + + /** + * Allocates array that can hold all key indices returned by {@link #getKeyIndexAndNearbyCodes} + * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. + * + * @return Allocates and returns an array that can hold all key indices returned by + * {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are + * initialized by {@link keepass2android.softkeyboard.LatinKeyboardView.NOT_A_KEY} + * value. + */ + public int[] newCodeArray() { + int[] codes = new int[getMaxNearbyKeys()]; + Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY); + return codes; + } + + /** + * Computes maximum size of the array that can contain all nearby key indices returned by + * {@link #getKeyIndexAndNearbyCodes}. + * + * @return Returns maximum size of the array that can contain all nearby key indices returned + * by {@link #getKeyIndexAndNearbyCodes}. + */ + abstract protected int getMaxNearbyKeys(); + + /** + * Finds all possible nearby key indices around a touch event point and returns the nearest key + * index. The algorithm to determine the nearby keys depends on the threshold set by + * {@link #setProximityThreshold(int)} and the mode set by + * {@link #setProximityCorrectionEnabled(boolean)}. + * + * @param x The x-coordinate of a touch point + * @param y The y-coordinate of a touch point + * @param allKeys All nearby key indices are returned in this array + * @return The nearest key index + */ + abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys); +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KeyboardSwitcher.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KeyboardSwitcher.java new file mode 100644 index 00000000..8a8cf510 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/KeyboardSwitcher.java @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.preference.PreferenceManager; +import android.view.InflateException; + +import java.lang.ref.SoftReference; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; + +public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener { + + public static final int MODE_NONE = 0; + public static final int MODE_TEXT = 1; + public static final int MODE_SYMBOLS = 2; + public static final int MODE_PHONE = 3; + public static final int MODE_URL = 4; + public static final int MODE_EMAIL = 5; + public static final int MODE_IM = 6; + public static final int MODE_WEB = 7; + + // Main keyboard layouts without the settings key + public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal; + public static final int KEYBOARDMODE_URL = R.id.mode_url; + public static final int KEYBOARDMODE_EMAIL = R.id.mode_email; + public static final int KEYBOARDMODE_IM = R.id.mode_im; + public static final int KEYBOARDMODE_WEB = R.id.mode_webentry; + // Main keyboard layouts with the settings key + public static final int KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY = + R.id.mode_normal_with_settings_key; + public static final int KEYBOARDMODE_URL_WITH_SETTINGS_KEY = + R.id.mode_url_with_settings_key; + public static final int KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY = + R.id.mode_email_with_settings_key; + public static final int KEYBOARDMODE_IM_WITH_SETTINGS_KEY = + R.id.mode_im_with_settings_key; + public static final int KEYBOARDMODE_WEB_WITH_SETTINGS_KEY = + R.id.mode_webentry_with_settings_key; + + // Symbols keyboard layout without the settings key + public static final int KEYBOARDMODE_SYMBOLS = R.id.mode_symbols; + // Symbols keyboard layout with the settings key + public static final int KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY = + R.id.mode_symbols_with_settings_key; + + public static final String DEFAULT_LAYOUT_ID = "4"; + public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; + private static final int[] THEMES = new int [] { + R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal, + R.layout.input_stone_bold, R.layout.input_gingerbread}; + + // Ids for each characters' color in the keyboard + private static final int CHAR_THEME_COLOR_WHITE = 0; + private static final int CHAR_THEME_COLOR_BLACK = 1; + + // Tables which contains resource ids for each character theme color + private static final int[] KBD_PHONE = new int[] {R.xml.kbd_phone, R.xml.kbd_phone_black}; + private static final int[] KBD_PHONE_SYMBOLS = new int[] { + R.xml.kbd_phone_symbols, R.xml.kbd_phone_symbols_black}; + private static final int[] KBD_SYMBOLS = new int[] { + R.xml.kbd_symbols, R.xml.kbd_symbols_black}; + private static final int[] KBD_SYMBOLS_SHIFT = new int[] { + R.xml.kbd_symbols_shift, R.xml.kbd_symbols_shift_black}; + private static final int[] KBD_QWERTY = new int[] {R.xml.kbd_qwerty, R.xml.kbd_qwerty_black}; + + private LatinKeyboardView mInputView; + private static final int[] ALPHABET_MODES = { + KEYBOARDMODE_NORMAL, + KEYBOARDMODE_URL, + KEYBOARDMODE_EMAIL, + KEYBOARDMODE_IM, + KEYBOARDMODE_WEB, + KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY, + KEYBOARDMODE_URL_WITH_SETTINGS_KEY, + KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY, + KEYBOARDMODE_IM_WITH_SETTINGS_KEY, + KEYBOARDMODE_WEB_WITH_SETTINGS_KEY }; + + private KP2AKeyboard mInputMethodService; + + private KeyboardId mSymbolsId; + private KeyboardId mSymbolsShiftedId; + + private KeyboardId mCurrentId; + private final HashMap> mKeyboards = + new HashMap>(); + + private int mMode = MODE_NONE; /** One of the MODE_XXX values */ + private int mImeOptions; + private boolean mIsSymbols; + /** mIsAutoCompletionActive indicates that auto completed word will be input instead of + * what user actually typed. */ + private boolean mIsAutoCompletionActive; + private boolean mPreferSymbols; + + private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0; + private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1; + private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2; + // The following states are used only on the distinct multi-touch panel devices. + private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3; + private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4; + private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + + // Indicates whether or not we have the settings key + private boolean mHasSettingsKey; + private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto; + private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW = R.string.settings_key_mode_always_show; + // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to + // in the source code now. + // Default is SETTINGS_KEY_MODE_AUTO. + private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO; + + private int mLastDisplayWidth; + private LanguageSwitcher mLanguageSwitcher; + private Locale mInputLocale; + + private int mLayoutId; + + private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); + + public static KeyboardSwitcher getInstance() { + return sInstance; + } + + private KeyboardSwitcher() { + // Intentional empty constructor for singleton. + } + + public static void init(KP2AKeyboard ims) { + sInstance.mInputMethodService = ims; + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims); + sInstance.mLayoutId = Integer.valueOf( + prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID)); + sInstance.updateSettingsKeyState(prefs); + prefs.registerOnSharedPreferenceChangeListener(sInstance); + + sInstance.mSymbolsId = sInstance.makeSymbolsId(); + sInstance.mSymbolsShiftedId = sInstance.makeSymbolsShiftedId(); + } + + /** + * Sets the input locale, when there are multiple locales for input. + * If no locale switching is required, then the locale should be set to null. + * @param locale the current input locale, or null for default locale with no locale + * button. + */ + public void setLanguageSwitcher(LanguageSwitcher languageSwitcher) { + mLanguageSwitcher = languageSwitcher; + mInputLocale = mLanguageSwitcher.getInputLocale(); + } + + private KeyboardId makeSymbolsId() { + return new KeyboardId(KBD_SYMBOLS[getCharColorId()], mHasSettingsKey ? + KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, + false); + } + + private KeyboardId makeSymbolsShiftedId() { + return new KeyboardId(KBD_SYMBOLS_SHIFT[getCharColorId()], mHasSettingsKey ? + KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, + false); + } + + public void makeKeyboards(boolean forceCreate) { + mSymbolsId = makeSymbolsId(); + mSymbolsShiftedId = makeSymbolsShiftedId(); + + if (forceCreate) mKeyboards.clear(); + // Configuration change is coming after the keyboard gets recreated. So don't rely on that. + // If keyboards have already been made, check if we have a screen width change and + // create the keyboard layouts again at the correct orientation + int displayWidth = mInputMethodService.getMaxWidth(); + if (displayWidth == mLastDisplayWidth) return; + mLastDisplayWidth = displayWidth; + if (!forceCreate) mKeyboards.clear(); + } + + /** + * Represents the parameters necessary to construct a new LatinKeyboard, + * which also serve as a unique identifier for each keyboard type. + */ + private static class KeyboardId { + // TODO: should have locale and portrait/landscape orientation? + public final int mXml; + public final int mKeyboardMode; /** A KEYBOARDMODE_XXX value */ + public final boolean mEnableShiftLock; + + private final int mHashCode; + + public KeyboardId(int xml, int mode, boolean enableShiftLock) { + this.mXml = xml; + this.mKeyboardMode = mode; + this.mEnableShiftLock = enableShiftLock; + + this.mHashCode = Arrays.hashCode(new Object[] { + xml, mode, enableShiftLock + }); + } + + public KeyboardId(int xml) { + this(xml, 0, false); + } + + @Override + public boolean equals(Object other) { + return other instanceof KeyboardId && equals((KeyboardId) other); + } + + private boolean equals(KeyboardId other) { + return other.mXml == this.mXml + && other.mKeyboardMode == this.mKeyboardMode + && other.mEnableShiftLock == this.mEnableShiftLock + ; + } + + @Override + public int hashCode() { + return mHashCode; + } + } + + + public void setKeyboardMode(int mode, int imeOptions) { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + mPreferSymbols = mode == MODE_SYMBOLS; + if (mode == MODE_SYMBOLS) { + mode = MODE_TEXT; + } + try { + setKeyboardMode(mode, imeOptions, mPreferSymbols); + } catch (RuntimeException e) { + LatinImeLogger.logOnException(mode + "," + imeOptions + "," + mPreferSymbols, e); + } + } + + private void setKeyboardMode(int mode, int imeOptions, boolean isSymbols) { + if (mInputView == null) return; + mMode = mode; + mImeOptions = imeOptions; + mIsSymbols = isSymbols; + + mInputView.setPreviewEnabled(mInputMethodService.getPopupOn()); + KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols); + LatinKeyboard keyboard = null; + keyboard = getKeyboard(id); + + if (mode == MODE_PHONE) { + mInputView.setPhoneKeyboard(keyboard); + } + + mCurrentId = id; + mInputView.setKeyboard(keyboard); + keyboard.setShifted(false); + keyboard.setShiftLocked(keyboard.isShiftLocked()); + keyboard.setImeOptions(mInputMethodService.getResources(), mMode, imeOptions); + keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym()); + // Update the settings key state because number of enabled IMEs could have been changed + updateSettingsKeyState(PreferenceManager.getDefaultSharedPreferences(mInputMethodService)); + } + + private LatinKeyboard getKeyboard(KeyboardId id) { + SoftReference ref = mKeyboards.get(id); + LatinKeyboard keyboard = (ref == null) ? null : ref.get(); + if (keyboard == null) { + Resources orig = mInputMethodService.getResources(); + Configuration conf = orig.getConfiguration(); + Locale saveLocale = conf.locale; + conf.locale = mInputLocale; + orig.updateConfiguration(conf, null); + keyboard = new LatinKeyboard(mInputMethodService, id.mXml, id.mKeyboardMode); + keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym()); + + if (id.mEnableShiftLock) { + keyboard.enableShiftLock(); + } + mKeyboards.put(id, new SoftReference(keyboard)); + + conf.locale = saveLocale; + orig.updateConfiguration(conf, null); + } + return keyboard; + } + + private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) { + int charColorId = getCharColorId(); + // TODO: generalize for any KeyboardId + int keyboardRowsResId = KBD_QWERTY[charColorId]; + if (isSymbols) { + if (mode == MODE_PHONE) { + return new KeyboardId(KBD_PHONE_SYMBOLS[charColorId]); + } else { + return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ? + KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, + false); + } + } + switch (mode) { + case MODE_NONE: + LatinImeLogger.logOnWarning( + "getKeyboardId:" + mode + "," + imeOptions + "," + isSymbols); + /* fall through */ + case MODE_TEXT: + return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? + KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY : KEYBOARDMODE_NORMAL, + true); + case MODE_SYMBOLS: + return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ? + KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, + false); + case MODE_PHONE: + return new KeyboardId(KBD_PHONE[charColorId]); + case MODE_URL: + return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? + KEYBOARDMODE_URL_WITH_SETTINGS_KEY : KEYBOARDMODE_URL, true); + case MODE_EMAIL: + return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? + KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY : KEYBOARDMODE_EMAIL, true); + case MODE_IM: + return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? + KEYBOARDMODE_IM_WITH_SETTINGS_KEY : KEYBOARDMODE_IM, true); + case MODE_WEB: + return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? + KEYBOARDMODE_WEB_WITH_SETTINGS_KEY : KEYBOARDMODE_WEB, true); + } + return null; + } + + public int getKeyboardMode() { + return mMode; + } + + public boolean isAlphabetMode() { + if (mCurrentId == null) { + return false; + } + int currentMode = mCurrentId.mKeyboardMode; + for (Integer mode : ALPHABET_MODES) { + if (currentMode == mode) { + return true; + } + } + return false; + } + + public void setShifted(boolean shifted) { + if (mInputView != null) { + mInputView.setShifted(shifted); + } + } + + public void setShiftLocked(boolean shiftLocked) { + if (mInputView != null) { + mInputView.setShiftLocked(shiftLocked); + } + } + + public void toggleShift() { + if (isAlphabetMode()) + return; + if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) { + LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId); + mCurrentId = mSymbolsShiftedId; + mInputView.setKeyboard(symbolsShiftedKeyboard); + // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To + // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true). + // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is + // called. + symbolsShiftedKeyboard.enableShiftLock(); + symbolsShiftedKeyboard.setShiftLocked(true); + symbolsShiftedKeyboard.setImeOptions(mInputMethodService.getResources(), + mMode, mImeOptions); + } else { + LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId); + mCurrentId = mSymbolsId; + mInputView.setKeyboard(symbolsKeyboard); + // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the + // indicator, we need to call enableShiftLock() and setShiftLocked(false). + symbolsKeyboard.enableShiftLock(); + symbolsKeyboard.setShifted(false); + symbolsKeyboard.setImeOptions(mInputMethodService.getResources(), mMode, mImeOptions); + } + } + + public void onCancelInput() { + // Snap back to the previous keyboard mode if the user cancels sliding input. + if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1) + mInputMethodService.changeKeyboardMode(); + } + + public void toggleSymbols() { + setKeyboardMode(mMode, mImeOptions, !mIsSymbols); + if (mIsSymbols && !mPreferSymbols) { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; + } else { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + } + } + + public boolean hasDistinctMultitouch() { + return mInputView != null && mInputView.hasDistinctMultitouch(); + } + + public void setAutoModeSwitchStateMomentary() { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY; + } + + public boolean isInMomentaryAutoModeSwitchState() { + return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY; + } + + public boolean isInChordingAutoModeSwitchState() { + return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING; + } + + public boolean isVibrateAndSoundFeedbackRequired() { + return mInputView != null && !mInputView.isInSlidingKeyInput(); + } + + private int getPointerCount() { + return mInputView == null ? 0 : mInputView.getPointerCount(); + } + + /** + * Updates state machine to figure out when to automatically snap back to the previous mode. + */ + public void onKey(int key) { + // Switch back to alpha mode if user types one or more non-space/enter characters + // followed by a space/enter + switch (mAutoModeSwitchState) { + case AUTO_MODE_SWITCH_STATE_MOMENTARY: + // Only distinct multi touch devices can be in this state. + // On non-distinct multi touch devices, mode change key is handled by {@link onKey}, + // not by {@link onPress} and {@link onRelease}. So, on such devices, + // {@link mAutoModeSwitchState} starts from {@link AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, + // or {@link AUTO_MODE_SWITCH_STATE_ALPHA}, not from + // {@link AUTO_MODE_SWITCH_STATE_MOMENTARY}. + if (key == LatinKeyboard.KEYCODE_MODE_CHANGE) { + // Detected only the mode change key has been pressed, and then released. + if (mIsSymbols) { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; + } else { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + } + } else if (getPointerCount() == 1) { + // Snap back to the previous keyboard mode if the user pressed the mode change key + // and slid to other key, then released the finger. + // If the user cancels the sliding input, snapping back to the previous keyboard + // mode is handled by {@link #onCancelInput}. + mInputMethodService.changeKeyboardMode(); + } else { + // Chording input is being started. The keyboard mode will be snapped back to the + // previous mode in {@link onReleaseSymbol} when the mode change key is released. + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING; + } + break; + case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN: + if (key != KP2AKeyboard.KEYCODE_SPACE && key != KP2AKeyboard.KEYCODE_ENTER && key >= 0) { + mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL; + } + break; + case AUTO_MODE_SWITCH_STATE_SYMBOL: + // Snap back to alpha keyboard mode if user types one or more non-space/enter + // characters followed by a space/enter. + if (key == KP2AKeyboard.KEYCODE_ENTER || key == KP2AKeyboard.KEYCODE_SPACE) { + mInputMethodService.changeKeyboardMode(); + } + break; + } + } + + public LatinKeyboardView getInputView() { + return mInputView; + } + + public void recreateInputView() { + changeLatinKeyboardView(mLayoutId, true); + } + + private void changeLatinKeyboardView(int newLayout, boolean forceReset) { + if (mLayoutId != newLayout || mInputView == null || forceReset) { + if (mInputView != null) { + mInputView.closing(); + } + if (THEMES.length <= newLayout) { + newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID); + } + + LatinIMEUtil.GCUtils.getInstance().reset(); + boolean tryGC = true; + for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { + try { + mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater( + ).inflate(THEMES[newLayout], null); + tryGC = false; + } catch (OutOfMemoryError e) { + tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait( + mLayoutId + "," + newLayout, e); + } catch (InflateException e) { + tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait( + mLayoutId + "," + newLayout, e); + } + } + mInputView.setOnKeyboardActionListener(mInputMethodService); + mLayoutId = newLayout; + } + mInputMethodService.mHandler.post(new Runnable() { + public void run() { + if (mInputView != null) { + mInputMethodService.setInputView(mInputView); + } + mInputMethodService.updateInputViewShown(); + }}); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (PREF_KEYBOARD_LAYOUT.equals(key)) { + changeLatinKeyboardView( + Integer.valueOf(sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)), false); + } else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) { + updateSettingsKeyState(sharedPreferences); + recreateInputView(); + } + } + + public boolean isBlackSym () { + if (mInputView != null && mInputView.getSymbolColorScheme() == 1) { + return true; + } + return false; + } + + private int getCharColorId () { + if (isBlackSym()) { + return CHAR_THEME_COLOR_BLACK; + } else { + return CHAR_THEME_COLOR_WHITE; + } + } + + public void onAutoCompletionStateChanged(boolean isAutoCompletion) { + if (isAutoCompletion != mIsAutoCompletionActive) { + LatinKeyboardView keyboardView = getInputView(); + mIsAutoCompletionActive = isAutoCompletion; + keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard()) + .onAutoCompletionStateChanged(isAutoCompletion)); + } + } + + private void updateSettingsKeyState(SharedPreferences prefs) { + Resources resources = mInputMethodService.getResources(); + final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY, + resources.getString(DEFAULT_SETTINGS_KEY_MODE)); + // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or + // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system + if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW)) + || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO)) + && LatinIMEUtil.hasMultipleEnabledIMEs(mInputMethodService))) { + mHasSettingsKey = true; + } else { + mHasSettingsKey = false; + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LanguageSwitcher.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LanguageSwitcher.java new file mode 100644 index 00000000..844b7c4c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LanguageSwitcher.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.preference.PreferenceManager; +import android.text.TextUtils; + +import java.util.Locale; + +/** + * Keeps track of list of selected input languages and the current + * input language that the user has selected. + */ +public class LanguageSwitcher { + + private Locale[] mLocales; + private KP2AKeyboard mIme; + private String[] mSelectedLanguageArray; + private String mSelectedLanguages; + private int mCurrentIndex = 0; + private String mDefaultInputLanguage; + private Locale mDefaultInputLocale; + private Locale mSystemLocale; + + public LanguageSwitcher(KP2AKeyboard ime) { + mIme = ime; + mLocales = new Locale[0]; + } + + public Locale[] getLocales() { + return mLocales; + } + + public int getLocaleCount() { + return mLocales.length; + } + + /** + * Loads the currently selected input languages from shared preferences. + * @param sp + * @return whether there was any change + */ + public boolean loadLocales(SharedPreferences sp) { + String selectedLanguages = sp.getString(KP2AKeyboard.PREF_SELECTED_LANGUAGES, null); + String currentLanguage = sp.getString(KP2AKeyboard.PREF_INPUT_LANGUAGE, null); + if (selectedLanguages == null || selectedLanguages.length() < 1) { + loadDefaults(); + if (mLocales.length == 0) { + return false; + } + mLocales = new Locale[0]; + return true; + } + if (selectedLanguages.equals(mSelectedLanguages)) { + return false; + } + mSelectedLanguageArray = selectedLanguages.split(","); + mSelectedLanguages = selectedLanguages; // Cache it for comparison later + constructLocales(); + mCurrentIndex = 0; + if (currentLanguage != null) { + // Find the index + mCurrentIndex = 0; + for (int i = 0; i < mLocales.length; i++) { + if (mSelectedLanguageArray[i].equals(currentLanguage)) { + mCurrentIndex = i; + break; + } + } + // If we didn't find the index, use the first one + } + return true; + } + + private void loadDefaults() { + mDefaultInputLocale = mIme.getResources().getConfiguration().locale; + String country = mDefaultInputLocale.getCountry(); + mDefaultInputLanguage = mDefaultInputLocale.getLanguage() + + (TextUtils.isEmpty(country) ? "" : "_" + country); + } + + private void constructLocales() { + mLocales = new Locale[mSelectedLanguageArray.length]; + for (int i = 0; i < mLocales.length; i++) { + final String lang = mSelectedLanguageArray[i]; + mLocales[i] = new Locale(lang.substring(0, 2), + lang.length() > 4 ? lang.substring(3, 5) : ""); + } + } + + /** + * Returns the currently selected input language code, or the display language code if + * no specific locale was selected for input. + */ + public String getInputLanguage() { + if (getLocaleCount() == 0) return mDefaultInputLanguage; + + return mSelectedLanguageArray[mCurrentIndex]; + } + + /** + * Returns the list of enabled language codes. + */ + public String[] getEnabledLanguages() { + return mSelectedLanguageArray; + } + + /** + * Returns the currently selected input locale, or the display locale if no specific + * locale was selected for input. + * @return + */ + public Locale getInputLocale() { + if (getLocaleCount() == 0) return mDefaultInputLocale; + + return mLocales[mCurrentIndex]; + } + + /** + * Returns the next input locale in the list. Wraps around to the beginning of the + * list if we're at the end of the list. + * @return + */ + public Locale getNextInputLocale() { + if (getLocaleCount() == 0) return mDefaultInputLocale; + + return mLocales[(mCurrentIndex + 1) % mLocales.length]; + } + + /** + * Sets the system locale (display UI) used for comparing with the input language. + * @param locale the locale of the system + */ + public void setSystemLocale(Locale locale) { + mSystemLocale = locale; + } + + /** + * Returns the system locale. + * @return the system locale + */ + public Locale getSystemLocale() { + return mSystemLocale; + } + + /** + * Returns the previous input locale in the list. Wraps around to the end of the + * list if we're at the beginning of the list. + * @return + */ + public Locale getPrevInputLocale() { + if (getLocaleCount() == 0) return mDefaultInputLocale; + + return mLocales[(mCurrentIndex - 1 + mLocales.length) % mLocales.length]; + } + + public void reset() { + mCurrentIndex = 0; + } + + public void next() { + mCurrentIndex++; + if (mCurrentIndex >= mLocales.length) mCurrentIndex = 0; // Wrap around + } + + public void prev() { + mCurrentIndex--; + if (mCurrentIndex < 0) mCurrentIndex = mLocales.length - 1; // Wrap around + } + + public void persist() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mIme); + Editor editor = sp.edit(); + editor.putString(KP2AKeyboard.PREF_INPUT_LANGUAGE, getInputLanguage()); + SharedPreferencesCompat.apply(editor); + } + + static String toTitleCase(String s, Locale locale) { + if (s.length() == 0) { + return s; + } + + return s.toUpperCase(locale).charAt(0) + s.substring(1); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEBackupAgent.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEBackupAgent.java new file mode 100644 index 00000000..58618cef --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEBackupAgent.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.app.backup.BackupAgentHelper; +import android.app.backup.SharedPreferencesBackupHelper; + +/** + * Backs up the Latin IME shared preferences. + */ +public class LatinIMEBackupAgent extends BackupAgentHelper { + + @Override + public void onCreate() { + addHelper("shared_pref", new SharedPreferencesBackupHelper(this, + getPackageName() + "_preferences")); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEDebugSettings.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEDebugSettings.java new file mode 100644 index 00000000..789030e7 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEDebugSettings.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.PreferenceActivity; +import android.util.Log; + +public class LatinIMEDebugSettings extends PreferenceActivity + implements SharedPreferences.OnSharedPreferenceChangeListener { + + private static final String TAG = "LatinIMEDebugSettings"; + private static final String DEBUG_MODE_KEY = "debug_mode"; + + private CheckBoxPreference mDebugMode; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + addPreferencesFromResource(R.xml.prefs_for_debug); + SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + prefs.registerOnSharedPreferenceChangeListener(this); + + mDebugMode = (CheckBoxPreference) findPreference(DEBUG_MODE_KEY); + updateDebugMode(); + } + + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if (key.equals(DEBUG_MODE_KEY)) { + if (mDebugMode != null) { + mDebugMode.setChecked(prefs.getBoolean(DEBUG_MODE_KEY, false)); + updateDebugMode(); + } + } + } + + private void updateDebugMode() { + if (mDebugMode == null) { + return; + } + boolean isDebugMode = mDebugMode.isChecked(); + String version = ""; + try { + PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0); + version = "Version " + info.versionName; + } catch (NameNotFoundException e) { + Log.e(TAG, "Could not find version info."); + } + if (!isDebugMode) { + mDebugMode.setTitle(version); + mDebugMode.setSummary(""); + } else { + mDebugMode.setTitle(getResources().getString(R.string.prefs_debug_mode)); + mDebugMode.setSummary(version); + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMESettings.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMESettings.java new file mode 100644 index 00000000..4dac5311 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMESettings.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import java.util.ArrayList; +import java.util.Locale; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.backup.BackupManager; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.ListPreference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceGroup; +import android.speech.SpeechRecognizer; +import android.text.AutoText; +import android.util.Log; + +public class LatinIMESettings extends PreferenceActivity + implements SharedPreferences.OnSharedPreferenceChangeListener, + DialogInterface.OnDismissListener { + + private static final String QUICK_FIXES_KEY = "quick_fixes"; + private static final String PREDICTION_SETTINGS_KEY = "prediction_settings"; + + /* package */ static final String PREF_SETTINGS_KEY = "settings_key"; + + private static final String TAG = "LatinIMESettings"; + + + private CheckBoxPreference mQuickFixes; + private ListPreference mSettingsKeyPreference; + + private boolean mOkClicked = false; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + addPreferencesFromResource(R.xml.prefs); + mQuickFixes = (CheckBoxPreference) findPreference(QUICK_FIXES_KEY); + mSettingsKeyPreference = (ListPreference) findPreference(PREF_SETTINGS_KEY); + SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + prefs.registerOnSharedPreferenceChangeListener(this); + + + } + + @Override + protected void onResume() { + super.onResume(); + int autoTextSize = AutoText.getSize(getListView()); + if (autoTextSize < 1) { + ((PreferenceGroup) findPreference(PREDICTION_SETTINGS_KEY)) + .removePreference(mQuickFixes); + } + + updateSettingsKeySummary(); + } + + @Override + protected void onDestroy() { + getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( + this); + super.onDestroy(); + } + + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + (new BackupManager(this)).dataChanged(); + // If turning on voice input, show dialog + updateSettingsKeySummary(); + } + + private void updateSettingsKeySummary() { + mSettingsKeyPreference.setSummary( + getResources().getStringArray(R.array.settings_key_modes) + [mSettingsKeyPreference.findIndexOfValue(mSettingsKeyPreference.getValue())]); + } + + + @Override + protected Dialog onCreateDialog(int id) { + switch (id) { + + default: + Log.e(TAG, "unknown dialog " + id); + return null; + } + } + + public void onDismiss(DialogInterface dialog) { + + } + +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEUtil.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEUtil.java new file mode 100644 index 00000000..070ff43b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinIMEUtil.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import android.view.inputmethod.InputMethodManager; + +import android.content.Context; +import android.os.AsyncTask; +import android.text.format.DateUtils; +import android.util.Log; + +public class LatinIMEUtil { + + /** + * Cancel an {@link AsyncTask}. + * + * @param mayInterruptIfRunning true if the thread executing this + * task should be interrupted; otherwise, in-progress tasks are allowed + * to complete. + */ + public static void cancelTask(AsyncTask task, boolean mayInterruptIfRunning) { + if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) { + task.cancel(mayInterruptIfRunning); + } + } + + public static class GCUtils { + private static final String TAG = "GCUtils"; + public static final int GC_TRY_COUNT = 2; + // GC_TRY_LOOP_MAX is used for the hard limit of GC wait, + // GC_TRY_LOOP_MAX should be greater than GC_TRY_COUNT. + public static final int GC_TRY_LOOP_MAX = 5; + private static final long GC_INTERVAL = DateUtils.SECOND_IN_MILLIS; + private static GCUtils sInstance = new GCUtils(); + private int mGCTryCount = 0; + + public static GCUtils getInstance() { + return sInstance; + } + + public void reset() { + mGCTryCount = 0; + } + + public boolean tryGCOrWait(String metaData, Throwable t) { + if (mGCTryCount == 0) { + System.gc(); + } + if (++mGCTryCount > GC_TRY_COUNT) { + LatinImeLogger.logOnException(metaData, t); + return false; + } else { + try { + Thread.sleep(GC_INTERVAL); + return true; + } catch (InterruptedException e) { + Log.e(TAG, "Sleep was interrupted."); + LatinImeLogger.logOnException(metaData, t); + return false; + } + } + } + } + + public static boolean hasMultipleEnabledIMEs(Context context) { + return ((InputMethodManager) context.getSystemService( + Context.INPUT_METHOD_SERVICE)).getEnabledInputMethodList().size() > 1; + } + + /* package */ static class RingCharBuffer { + private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); + private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; + private static final int INVALID_COORDINATE = -2; + /* package */ static final int BUFSIZE = 20; + private Context mContext; + private boolean mEnabled = false; + private int mEnd = 0; + /* package */ int mLength = 0; + private char[] mCharBuf = new char[BUFSIZE]; + private int[] mXBuf = new int[BUFSIZE]; + private int[] mYBuf = new int[BUFSIZE]; + + private RingCharBuffer() { + } + public static RingCharBuffer getInstance() { + return sRingCharBuffer; + } + public static RingCharBuffer init(Context context, boolean enabled) { + sRingCharBuffer.mContext = context; + sRingCharBuffer.mEnabled = enabled; + return sRingCharBuffer; + } + private int normalize(int in) { + int ret = in % BUFSIZE; + return ret < 0 ? ret + BUFSIZE : ret; + } + public void push(char c, int x, int y) { + if (!mEnabled) return; + mCharBuf[mEnd] = c; + mXBuf[mEnd] = x; + mYBuf[mEnd] = y; + mEnd = normalize(mEnd + 1); + if (mLength < BUFSIZE) { + ++mLength; + } + } + public char pop() { + if (mLength < 1) { + return PLACEHOLDER_DELIMITER_CHAR; + } else { + mEnd = normalize(mEnd - 1); + --mLength; + return mCharBuf[mEnd]; + } + } + public char getLastChar() { + if (mLength < 1) { + return PLACEHOLDER_DELIMITER_CHAR; + } else { + return mCharBuf[normalize(mEnd - 1)]; + } + } + public int getPreviousX(char c, int back) { + int index = normalize(mEnd - 2 - back); + if (mLength <= back + || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) { + return INVALID_COORDINATE; + } else { + return mXBuf[index]; + } + } + public int getPreviousY(char c, int back) { + int index = normalize(mEnd - 2 - back); + if (mLength <= back + || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) { + return INVALID_COORDINATE; + } else { + return mYBuf[index]; + } + } + public String getLastString() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < mLength; ++i) { + char c = mCharBuf[normalize(mEnd - 1 - i)]; + if (!((KP2AKeyboard)mContext).isWordSeparator(c)) { + sb.append(c); + } else { + break; + } + } + return sb.reverse().toString(); + } + public void reset() { + mLength = 0; + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinImeLogger.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinImeLogger.java new file mode 100644 index 00000000..1e347369 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinImeLogger.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import keepass2android.softkeyboard.Dictionary.DataType; + +import android.content.Context; +import android.content.SharedPreferences; +import android.inputmethodservice.Keyboard; +import java.util.List; + +public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener { + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + } + + public static void init(Context context) { + } + + public static void commit() { + } + + public static void onDestroy() { + } + + public static void logOnManualSuggestion( + String before, String after, int position, List suggestions) { + } + + public static void logOnAutoSuggestion(String before, String after) { + } + + public static void logOnAutoSuggestionCanceled() { + } + + public static void logOnDelete() { + } + + public static void logOnInputChar() { + } + + public static void logOnException(String metaData, Throwable e) { + } + + public static void logOnWarning(String warning) { + } + + public static void onStartSuggestion(CharSequence previousWords) { + } + + public static void onAddSuggestedWord(String word, int typeId, DataType dataType) { + } + + public static void onSetKeyboard(Keyboard kb) { + } + +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboard.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboard.java new file mode 100644 index 00000000..5750d93c --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboard.java @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard; +import android.text.TextPaint; +import android.util.Log; +import android.view.ViewConfiguration; +import android.view.inputmethod.EditorInfo; + +import java.util.List; +import java.util.Locale; + +public class LatinKeyboard extends Keyboard { + + private static final boolean DEBUG_PREFERRED_LETTER = false; + private static final String TAG = "LatinKeyboard"; + private static final int OPACITY_FULLY_OPAQUE = 255; + private static final int SPACE_LED_LENGTH_PERCENT = 80; + + private Drawable mShiftLockIcon; + private Drawable mShiftLockPreviewIcon; + private Drawable mOldShiftIcon; + private Drawable mSpaceIcon; + private Drawable mSpaceAutoCompletionIndicator; + private Drawable mSpacePreviewIcon; + private Drawable mMicIcon; + private Drawable mMicPreviewIcon; + private Drawable m123MicIcon; + private Drawable m123MicPreviewIcon; + private final Drawable mButtonArrowLeftIcon; + private final Drawable mButtonArrowRightIcon; + private Key mShiftKey; + private Key mEnterKey; + private Key mF1Key; + private final Drawable mHintIcon; + private Key mSpaceKey; + private Key m123Key; + private final int NUMBER_HINT_COUNT = 10; + private Key[] mNumberHintKeys; + private Drawable[] mNumberHintIcons = new Drawable[NUMBER_HINT_COUNT]; + private final int[] mSpaceKeyIndexArray; + private int mSpaceDragStartX; + private int mSpaceDragLastDiff; + private Locale mLocale; + private LanguageSwitcher mLanguageSwitcher; + private final Resources mRes; + private final Context mContext; + private int mMode; + // Whether this keyboard has voice icon on it + private boolean mHasVoiceButton; + // Whether voice icon is enabled at all + + private final boolean mIsAlphaKeyboard; + private CharSequence m123Label; + private boolean mCurrentlyInSpace; + private SlidingLocaleDrawable mSlidingLocaleIcon; + private int[] mPrefLetterFrequencies; + private int mPrefLetter; + private int mPrefLetterX; + private int mPrefLetterY; + private int mPrefDistance; + + // TODO: generalize for any keyboardId + private boolean mIsBlackSym; + + // TODO: remove this attribute when either Keyboard.mDefaultVerticalGap or Key.parent becomes + // non-private. + private final int mVerticalGap; + + private static final int SHIFT_OFF = 0; + private static final int SHIFT_ON = 1; + private static final int SHIFT_LOCKED = 2; + + private int mShiftState = SHIFT_OFF; + + private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f; + private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f; + private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f; + // Minimum width of space key preview (proportional to keyboard width) + private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f; + // Height in space key the language name will be drawn. (proportional to space key height) + private static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f; + // If the full language name needs to be smaller than this value to be drawn on space key, + // its short language name will be used instead. + private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f; + + private static int sSpacebarVerticalCorrection; + + public LatinKeyboard(Context context, int xmlLayoutResId) { + this(context, xmlLayoutResId, 0); + } + + public LatinKeyboard(Context context, int xmlLayoutResId, int mode) { + super(context, xmlLayoutResId, mode); + final Resources res = context.getResources(); + mContext = context; + mMode = mode; + mRes = res; + mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked); + mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked); + setDefaultBounds(mShiftLockPreviewIcon); + mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space); + mSpaceAutoCompletionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led); + mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space); + mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic); + mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic); + setDefaultBounds(mMicPreviewIcon); + mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left); + mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right); + m123MicIcon = res.getDrawable(R.drawable.sym_keyboard_123_mic); + m123MicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_123_mic); + mHintIcon = res.getDrawable(R.drawable.hint_popup); + setDefaultBounds(m123MicPreviewIcon); + sSpacebarVerticalCorrection = res.getDimensionPixelOffset( + R.dimen.spacebar_vertical_correction); + mIsAlphaKeyboard = xmlLayoutResId == R.xml.kbd_qwerty + || xmlLayoutResId == R.xml.kbd_qwerty_black; + // The index of space key is available only after Keyboard constructor has finished. + mSpaceKeyIndexArray = new int[] { indexOf(KP2AKeyboard.KEYCODE_SPACE) }; + initializeNumberHintResources(context); + // TODO remove this initialization after cleanup + mVerticalGap = super.getVerticalGap(); + } + + private void initializeNumberHintResources(Context context) { + final Resources res = context.getResources(); + mNumberHintIcons[0] = res.getDrawable(R.drawable.keyboard_hint_0); + mNumberHintIcons[1] = res.getDrawable(R.drawable.keyboard_hint_1); + mNumberHintIcons[2] = res.getDrawable(R.drawable.keyboard_hint_2); + mNumberHintIcons[3] = res.getDrawable(R.drawable.keyboard_hint_3); + mNumberHintIcons[4] = res.getDrawable(R.drawable.keyboard_hint_4); + mNumberHintIcons[5] = res.getDrawable(R.drawable.keyboard_hint_5); + mNumberHintIcons[6] = res.getDrawable(R.drawable.keyboard_hint_6); + mNumberHintIcons[7] = res.getDrawable(R.drawable.keyboard_hint_7); + mNumberHintIcons[8] = res.getDrawable(R.drawable.keyboard_hint_8); + mNumberHintIcons[9] = res.getDrawable(R.drawable.keyboard_hint_9); + } + + @Override + protected Key createKeyFromXml(Resources res, Row parent, int x, int y, + XmlResourceParser parser) { + Key key = new LatinKey(res, parent, x, y, parser); + switch (key.codes[0]) { + case KP2AKeyboard.KEYCODE_ENTER: + mEnterKey = key; + break; + case LatinKeyboardView.KEYCODE_F1: + mF1Key = key; + break; + case KP2AKeyboard.KEYCODE_SPACE: + mSpaceKey = key; + break; + case KEYCODE_MODE_CHANGE: + m123Key = key; + m123Label = key.label; + break; + } + + // For number hints on the upper-right corner of key + if (mNumberHintKeys == null) { + // NOTE: This protected method is being called from the base class constructor before + // mNumberHintKeys gets initialized. + mNumberHintKeys = new Key[NUMBER_HINT_COUNT]; + } + int hintNumber = -1; + if (LatinKeyboardBaseView.isNumberAtLeftmostPopupChar(key)) { + hintNumber = key.popupCharacters.charAt(0) - '0'; + } else if (LatinKeyboardBaseView.isNumberAtRightmostPopupChar(key)) { + hintNumber = key.popupCharacters.charAt(key.popupCharacters.length() - 1) - '0'; + } + if (hintNumber >= 0 && hintNumber <= 9) { + mNumberHintKeys[hintNumber] = key; + } + + return key; + } + + void setImeOptions(Resources res, int mode, int options) { + mMode = mode; + // TODO should clean up this method + if (mEnterKey != null) { + // Reset some of the rarely used attributes. + mEnterKey.popupCharacters = null; + mEnterKey.popupResId = 0; + mEnterKey.text = null; + switch (options&(EditorInfo.IME_MASK_ACTION|EditorInfo.IME_FLAG_NO_ENTER_ACTION)) { + case EditorInfo.IME_ACTION_GO: + mEnterKey.iconPreview = null; + mEnterKey.icon = null; + mEnterKey.label = res.getText(R.string.label_go_key); + break; + case EditorInfo.IME_ACTION_NEXT: + mEnterKey.iconPreview = null; + mEnterKey.icon = null; + mEnterKey.label = res.getText(R.string.label_next_key); + break; + case EditorInfo.IME_ACTION_DONE: + mEnterKey.iconPreview = null; + mEnterKey.icon = null; + mEnterKey.label = res.getText(R.string.label_done_key); + break; + case EditorInfo.IME_ACTION_SEARCH: + mEnterKey.iconPreview = res.getDrawable( + R.drawable.sym_keyboard_feedback_search); + mEnterKey.icon = res.getDrawable(mIsBlackSym ? + R.drawable.sym_bkeyboard_search : R.drawable.sym_keyboard_search); + mEnterKey.label = null; + break; + case EditorInfo.IME_ACTION_SEND: + mEnterKey.iconPreview = null; + mEnterKey.icon = null; + mEnterKey.label = res.getText(R.string.label_send_key); + break; + default: + if (mode == KeyboardSwitcher.MODE_IM) { + mEnterKey.icon = mHintIcon; + mEnterKey.iconPreview = null; + mEnterKey.label = ":-)"; + mEnterKey.text = ":-) "; + mEnterKey.popupResId = R.xml.popup_smileys; + } else { + mEnterKey.iconPreview = res.getDrawable( + R.drawable.sym_keyboard_feedback_return); + mEnterKey.icon = res.getDrawable(mIsBlackSym ? + R.drawable.sym_bkeyboard_return : R.drawable.sym_keyboard_return); + mEnterKey.label = null; + } + break; + } + // Set the initial size of the preview icon + if (mEnterKey.iconPreview != null) { + setDefaultBounds(mEnterKey.iconPreview); + } + } + } + + void enableShiftLock() { + int index = getShiftKeyIndex(); + if (index >= 0) { + mShiftKey = getKeys().get(index); + if (mShiftKey instanceof LatinKey) { + ((LatinKey)mShiftKey).enableShiftLock(); + } + mOldShiftIcon = mShiftKey.icon; + } + } + + void setShiftLocked(boolean shiftLocked) { + if (mShiftKey != null) { + if (shiftLocked) { + mShiftKey.on = true; + mShiftKey.icon = mShiftLockIcon; + mShiftState = SHIFT_LOCKED; + } else { + mShiftKey.on = false; + mShiftKey.icon = mShiftLockIcon; + mShiftState = SHIFT_ON; + } + } + } + + boolean isShiftLocked() { + return mShiftState == SHIFT_LOCKED; + } + + @Override + public boolean setShifted(boolean shiftState) { + boolean shiftChanged = false; + if (mShiftKey != null) { + if (shiftState == false) { + shiftChanged = mShiftState != SHIFT_OFF; + mShiftState = SHIFT_OFF; + mShiftKey.on = false; + mShiftKey.icon = mOldShiftIcon; + } else { + if (mShiftState == SHIFT_OFF) { + shiftChanged = mShiftState == SHIFT_OFF; + mShiftState = SHIFT_ON; + mShiftKey.icon = mShiftLockIcon; + } + } + } else { + return super.setShifted(shiftState); + } + return shiftChanged; + } + + @Override + public boolean isShifted() { + if (mShiftKey != null) { + return mShiftState != SHIFT_OFF; + } else { + return super.isShifted(); + } + } + + /* package */ boolean isAlphaKeyboard() { + return mIsAlphaKeyboard; + } + + public void setColorOfSymbolIcons(boolean isAutoCompletion, boolean isBlack) { + mIsBlackSym = isBlack; + if (isBlack) { + mShiftLockIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_shift_locked); + mSpaceIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_space); + mMicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_mic); + m123MicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_123_mic); + } else { + mShiftLockIcon = mRes.getDrawable(R.drawable.sym_keyboard_shift_locked); + mSpaceIcon = mRes.getDrawable(R.drawable.sym_keyboard_space); + mMicIcon = mRes.getDrawable(R.drawable.sym_keyboard_mic); + m123MicIcon = mRes.getDrawable(R.drawable.sym_keyboard_123_mic); + } + updateDynamicKeys(); + if (mSpaceKey != null) { + updateSpaceBarForLocale(isAutoCompletion, isBlack); + } + updateNumberHintKeys(); + } + + private void setDefaultBounds(Drawable drawable) { + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + } + + + private void updateDynamicKeys() { + update123Key(); + updateF1Key(); + } + + private void update123Key() { + // Update KEYCODE_MODE_CHANGE key only on alphabet mode, not on symbol mode. + if (m123Key != null && mIsAlphaKeyboard) { + + m123Key.icon = null; + m123Key.iconPreview = null; + m123Key.label = m123Label; + + } + } + + private void updateF1Key() { + // Update KEYCODE_F1 key. Please note that some keyboard layouts have no F1 key. + if (mF1Key == null) + return; + + if (mIsAlphaKeyboard) { + if (mMode == KeyboardSwitcher.MODE_URL) { + setNonMicF1Key(mF1Key, "/", R.xml.popup_slash); + } else if (mMode == KeyboardSwitcher.MODE_EMAIL) { + setNonMicF1Key(mF1Key, "@", R.xml.popup_at); + } else { + setNonMicF1Key(mF1Key, ",", R.xml.popup_comma); + + } + } else { // Symbols keyboard + setNonMicF1Key(mF1Key, ",", R.xml.popup_comma); + } + } + private void setNonMicF1Key(Key key, String label, int popupResId) { + key.label = label; + key.codes = new int[] { label.charAt(0) }; + key.popupResId = popupResId; + key.icon = mHintIcon; + key.iconPreview = null; + } + + public boolean isF1Key(Key key) { + return key == mF1Key; + } + + public static boolean hasPuncOrSmileysPopup(Key key) { + return key.popupResId == R.xml.popup_punctuation || key.popupResId == R.xml.popup_smileys; + } + + /** + * @return a key which should be invalidated. + */ + public Key onAutoCompletionStateChanged(boolean isAutoCompletion) { + updateSpaceBarForLocale(isAutoCompletion, mIsBlackSym); + return mSpaceKey; + } + + private void updateNumberHintKeys() { + for (int i = 0; i < mNumberHintKeys.length; ++i) { + if (mNumberHintKeys[i] != null) { + mNumberHintKeys[i].icon = mNumberHintIcons[i]; + } + } + } + + public boolean isLanguageSwitchEnabled() { + return mLocale != null; + } + + private void updateSpaceBarForLocale(boolean isAutoCompletion, boolean isBlack) { + // If application locales are explicitly selected. + if (mLocale != null) { + mSpaceKey.icon = new BitmapDrawable(mRes, + drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack)); + } else { + // sym_keyboard_space_led can be shared with Black and White symbol themes. + if (isAutoCompletion) { + mSpaceKey.icon = new BitmapDrawable(mRes, + drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack)); + } else { + mSpaceKey.icon = isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space) + : mRes.getDrawable(R.drawable.sym_keyboard_space); + } + } + } + + // Compute width of text with specified text size using paint. + private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) { + paint.setTextSize(textSize); + paint.getTextBounds(text, 0, text.length(), bounds); + return bounds.width(); + } + + // Overlay two images: mainIcon and hintIcon. + private Bitmap drawSynthesizedSettingsHintImage( + int width, int height, Drawable mainIcon, Drawable hintIcon) { + if (mainIcon == null || hintIcon == null) + return null; + Rect hintIconPadding = new Rect(0, 0, 0, 0); + hintIcon.getPadding(hintIconPadding); + final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(buffer); + canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR); + + // Draw main icon at the center of the key visual + // Assuming the hintIcon shares the same padding with the key's background drawable + final int drawableX = (width + hintIconPadding.left - hintIconPadding.right + - mainIcon.getIntrinsicWidth()) / 2; + final int drawableY = (height + hintIconPadding.top - hintIconPadding.bottom + - mainIcon.getIntrinsicHeight()) / 2; + setDefaultBounds(mainIcon); + canvas.translate(drawableX, drawableY); + mainIcon.draw(canvas); + canvas.translate(-drawableX, -drawableY); + + // Draw hint icon fully in the key + hintIcon.setBounds(0, 0, width, height); + hintIcon.draw(canvas); + return buffer; + } + + // Layout local language name and left and right arrow on space bar. + private static String layoutSpaceBar(Paint paint, Locale locale, Drawable lArrow, + Drawable rArrow, int width, int height, float origTextSize, + boolean allowVariableTextSize) { + final float arrowWidth = lArrow.getIntrinsicWidth(); + final float arrowHeight = lArrow.getIntrinsicHeight(); + final float maxTextWidth = width - (arrowWidth + arrowWidth); + final Rect bounds = new Rect(); + + // Estimate appropriate language name text size to fit in maxTextWidth. + String language = LanguageSwitcher.toTitleCase(locale.getDisplayLanguage(locale), locale); + int textWidth = getTextWidth(paint, language, origTextSize, bounds); + // Assuming text width and text size are proportional to each other. + float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f); + + final boolean useShortName; + if (allowVariableTextSize) { + textWidth = getTextWidth(paint, language, textSize, bounds); + // If text size goes too small or text does not fit, use short name + useShortName = textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME + || textWidth > maxTextWidth; + } else { + useShortName = textWidth > maxTextWidth; + textSize = origTextSize; + } + if (useShortName) { + language = LanguageSwitcher.toTitleCase(locale.getLanguage(), locale); + textWidth = getTextWidth(paint, language, origTextSize, bounds); + textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f); + } + paint.setTextSize(textSize); + + // Place left and right arrow just before and after language text. + final float baseline = height * SPACEBAR_LANGUAGE_BASELINE; + final int top = (int)(baseline - arrowHeight); + final float remains = (width - textWidth) / 2; + lArrow.setBounds((int)(remains - arrowWidth), top, (int)remains, (int)baseline); + rArrow.setBounds((int)(remains + textWidth), top, (int)(remains + textWidth + arrowWidth), + (int)baseline); + + return language; + } + + private Bitmap drawSpaceBar(int opacity, boolean isAutoCompletion, boolean isBlack) { + final int width = mSpaceKey.width; + final int height = mSpaceIcon.getIntrinsicHeight(); + final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(buffer); + canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR); + + // If application locales are explicitly selected. + if (mLocale != null) { + final Paint paint = new Paint(); + paint.setAlpha(opacity); + paint.setAntiAlias(true); + paint.setTextAlign(Align.CENTER); + + final boolean allowVariableTextSize = true; + final String language = layoutSpaceBar(paint, mLanguageSwitcher.getInputLocale(), + mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height, + getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14), + allowVariableTextSize); + + // Draw language text with shadow + final int shadowColor = mRes.getColor(isBlack + ? R.color.latinkeyboard_bar_language_shadow_black + : R.color.latinkeyboard_bar_language_shadow_white); + final float baseline = height * SPACEBAR_LANGUAGE_BASELINE; + final float descent = paint.descent(); + paint.setColor(shadowColor); + canvas.drawText(language, width / 2, baseline - descent - 1, paint); + paint.setColor(mRes.getColor(R.color.latinkeyboard_bar_language_text)); + canvas.drawText(language, width / 2, baseline - descent, paint); + + // Put arrows that are already layed out on either side of the text + if (mLanguageSwitcher.getLocaleCount() > 1) { + mButtonArrowLeftIcon.draw(canvas); + mButtonArrowRightIcon.draw(canvas); + } + } + + // Draw the spacebar icon at the bottom + if (isAutoCompletion) { + final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; + final int iconHeight = mSpaceAutoCompletionIndicator.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + mSpaceAutoCompletionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight); + mSpaceAutoCompletionIndicator.draw(canvas); + } else { + final int iconWidth = mSpaceIcon.getIntrinsicWidth(); + final int iconHeight = mSpaceIcon.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight); + mSpaceIcon.draw(canvas); + } + return buffer; + } + + private void updateLocaleDrag(int diff) { + if (mSlidingLocaleIcon == null) { + final int width = Math.max(mSpaceKey.width, + (int)(getMinWidth() * SPACEBAR_POPUP_MIN_RATIO)); + final int height = mSpacePreviewIcon.getIntrinsicHeight(); + mSlidingLocaleIcon = new SlidingLocaleDrawable(mSpacePreviewIcon, width, height); + mSlidingLocaleIcon.setBounds(0, 0, width, height); + mSpaceKey.iconPreview = mSlidingLocaleIcon; + } + mSlidingLocaleIcon.setDiff(diff); + if (Math.abs(diff) == Integer.MAX_VALUE) { + mSpaceKey.iconPreview = mSpacePreviewIcon; + } else { + mSpaceKey.iconPreview = mSlidingLocaleIcon; + } + mSpaceKey.iconPreview.invalidateSelf(); + } + + public int getLanguageChangeDirection() { + if (mSpaceKey == null || mLanguageSwitcher.getLocaleCount() < 2 + || Math.abs(mSpaceDragLastDiff) < mSpaceKey.width * SPACEBAR_DRAG_THRESHOLD ) { + return 0; // No change + } + return mSpaceDragLastDiff > 0 ? 1 : -1; + } + + public void setLanguageSwitcher(LanguageSwitcher switcher, boolean isAutoCompletion, + boolean isBlackSym) { + mLanguageSwitcher = switcher; + Locale locale = mLanguageSwitcher.getLocaleCount() > 0 + ? mLanguageSwitcher.getInputLocale() + : null; + // If the language count is 1 and is the same as the system language, don't show it. + if (locale != null + && mLanguageSwitcher.getLocaleCount() == 1 + && mLanguageSwitcher.getSystemLocale().getLanguage() + .equalsIgnoreCase(locale.getLanguage())) { + locale = null; + } + mLocale = locale; + setColorOfSymbolIcons(isAutoCompletion, isBlackSym); + } + + public Locale getInputLocale() { + return (mLocale != null) ? mLocale : mLanguageSwitcher.getSystemLocale(); + } + + boolean isCurrentlyInSpace() { + return mCurrentlyInSpace; + } + + void setPreferredLetters(int[] frequencies) { + mPrefLetterFrequencies = frequencies; + mPrefLetter = 0; + } + + void keyReleased() { + mCurrentlyInSpace = false; + mSpaceDragLastDiff = 0; + mPrefLetter = 0; + mPrefLetterX = 0; + mPrefLetterY = 0; + mPrefDistance = Integer.MAX_VALUE; + if (mSpaceKey != null) { + updateLocaleDrag(Integer.MAX_VALUE); + } + } + + /** + * Does the magic of locking the touch gesture into the spacebar when + * switching input languages. + */ + boolean isInside(LatinKey key, int x, int y) { + final int code = key.codes[0]; + if (code == KEYCODE_SHIFT || + code == KEYCODE_DELETE) { + y -= key.height / 10; + if (code == KEYCODE_SHIFT) x += key.width / 6; + if (code == KEYCODE_DELETE) x -= key.width / 6; + } else if (code == KP2AKeyboard.KEYCODE_SPACE) { + y += LatinKeyboard.sSpacebarVerticalCorrection; + if (mLanguageSwitcher.getLocaleCount() > 1) { + if (mCurrentlyInSpace) { + int diff = x - mSpaceDragStartX; + if (Math.abs(diff - mSpaceDragLastDiff) > 0) { + updateLocaleDrag(diff); + } + mSpaceDragLastDiff = diff; + return true; + } else { + boolean insideSpace = key.isInsideSuper(x, y); + if (insideSpace) { + mCurrentlyInSpace = true; + mSpaceDragStartX = x; + updateLocaleDrag(0); + } + return insideSpace; + } + } + } else if (mPrefLetterFrequencies != null) { + // New coordinate? Reset + if (mPrefLetterX != x || mPrefLetterY != y) { + mPrefLetter = 0; + mPrefDistance = Integer.MAX_VALUE; + } + // Handle preferred next letter + final int[] pref = mPrefLetterFrequencies; + if (mPrefLetter > 0) { + if (DEBUG_PREFERRED_LETTER) { + if (mPrefLetter == code && !key.isInsideSuper(x, y)) { + Log.d(TAG, "CORRECTED !!!!!!"); + } + } + return mPrefLetter == code; + } else { + final boolean inside = key.isInsideSuper(x, y); + int[] nearby = getNearestKeys(x, y); + List nearbyKeys = getKeys(); + if (inside) { + // If it's a preferred letter + if (inPrefList(code, pref)) { + // Check if its frequency is much lower than a nearby key + mPrefLetter = code; + mPrefLetterX = x; + mPrefLetterY = y; + for (int i = 0; i < nearby.length; i++) { + Key k = nearbyKeys.get(nearby[i]); + if (k != key && inPrefList(k.codes[0], pref)) { + final int dist = distanceFrom(k, x, y); + if (dist < (int) (k.width * OVERLAP_PERCENTAGE_LOW_PROB) && + (pref[k.codes[0]] > pref[mPrefLetter] * 3)) { + mPrefLetter = k.codes[0]; + mPrefDistance = dist; + if (DEBUG_PREFERRED_LETTER) { + Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!"); + } + break; + } + } + } + + return mPrefLetter == code; + } + } + + // Get the surrounding keys and intersect with the preferred list + // For all in the intersection + // if distance from touch point is within a reasonable distance + // make this the pref letter + // If no pref letter + // return inside; + // else return thiskey == prefletter; + + for (int i = 0; i < nearby.length; i++) { + Key k = nearbyKeys.get(nearby[i]); + if (inPrefList(k.codes[0], pref)) { + final int dist = distanceFrom(k, x, y); + if (dist < (int) (k.width * OVERLAP_PERCENTAGE_HIGH_PROB) + && dist < mPrefDistance) { + mPrefLetter = k.codes[0]; + mPrefLetterX = x; + mPrefLetterY = y; + mPrefDistance = dist; + } + } + } + // Didn't find any + if (mPrefLetter == 0) { + return inside; + } else { + return mPrefLetter == code; + } + } + } + + // Lock into the spacebar + if (mCurrentlyInSpace) return false; + + return key.isInsideSuper(x, y); + } + + private boolean inPrefList(int code, int[] pref) { + if (code < pref.length && code >= 0) return pref[code] > 0; + return false; + } + + private int distanceFrom(Key k, int x, int y) { + if (y > k.y && y < k.y + k.height) { + return Math.abs(k.x + k.width / 2 - x); + } else { + return Integer.MAX_VALUE; + } + } + + @Override + public int[] getNearestKeys(int x, int y) { + if (mCurrentlyInSpace) { + return mSpaceKeyIndexArray; + } else { + // Avoid dead pixels at edges of the keyboard + return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)), + Math.max(0, Math.min(y, getHeight() - 1))); + } + } + + private int indexOf(int code) { + List keys = getKeys(); + int count = keys.size(); + for (int i = 0; i < count; i++) { + if (keys.get(i).codes[0] == code) return i; + } + return -1; + } + + private int getTextSizeFromTheme(int style, int defValue) { + TypedArray array = mContext.getTheme().obtainStyledAttributes( + style, new int[] { android.R.attr.textSize }); + int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue); + return textSize; + } + + // TODO LatinKey could be static class + class LatinKey extends Keyboard.Key { + + // functional normal state (with properties) + private final int[] KEY_STATE_FUNCTIONAL_NORMAL = { + android.R.attr.state_single + }; + + // functional pressed state (with properties) + private final int[] KEY_STATE_FUNCTIONAL_PRESSED = { + android.R.attr.state_single, + android.R.attr.state_pressed + }; + + private boolean mShiftLockEnabled; + + public LatinKey(Resources res, Keyboard.Row parent, int x, int y, + XmlResourceParser parser) { + super(res, parent, x, y, parser); + if (popupCharacters != null && popupCharacters.length() == 0) { + // If there is a keyboard with no keys specified in popupCharacters + popupResId = 0; + } + } + + private void enableShiftLock() { + mShiftLockEnabled = true; + } + + // sticky is used for shift key. If a key is not sticky and is modifier, + // the key will be treated as functional. + private boolean isFunctionalKey() { + return !sticky && modifier; + } + + @Override + public void onReleased(boolean inside) { + if (!mShiftLockEnabled) { + super.onReleased(inside); + } else { + pressed = !pressed; + } + } + + /** + * Overriding this method so that we can reduce the target area for certain keys. + */ + @Override + public boolean isInside(int x, int y) { + // TODO This should be done by parent.isInside(this, x, y) + // if Key.parent were protected. + boolean result = LatinKeyboard.this.isInside(this, x, y); + return result; + } + + boolean isInsideSuper(int x, int y) { + return super.isInside(x, y); + } + + @Override + public int[] getCurrentDrawableState() { + if (isFunctionalKey()) { + if (pressed) { + return KEY_STATE_FUNCTIONAL_PRESSED; + } else { + return KEY_STATE_FUNCTIONAL_NORMAL; + } + } + return super.getCurrentDrawableState(); + } + + @Override + public int squaredDistanceFrom(int x, int y) { + // We should count vertical gap between rows to calculate the center of this Key. + final int verticalGap = LatinKeyboard.this.mVerticalGap; + final int xDist = this.x + width / 2 - x; + final int yDist = this.y + (height + verticalGap) / 2 - y; + return xDist * xDist + yDist * yDist; + } + } + + /** + * Animation to be displayed on the spacebar preview popup when switching + * languages by swiping the spacebar. It draws the current, previous and + * next languages and moves them by the delta of touch movement on the spacebar. + */ + class SlidingLocaleDrawable extends Drawable { + + private final int mWidth; + private final int mHeight; + private final Drawable mBackground; + private final TextPaint mTextPaint; + private final int mMiddleX; + private final Drawable mLeftDrawable; + private final Drawable mRightDrawable; + private final int mThreshold; + private int mDiff; + private boolean mHitThreshold; + private String mCurrentLanguage; + private String mNextLanguage; + private String mPrevLanguage; + + @SuppressLint("ResourceAsColor") + public SlidingLocaleDrawable(Drawable background, int width, int height) { + mBackground = background; + setDefaultBounds(mBackground); + mWidth = width; + mHeight = height; + mTextPaint = new TextPaint(); + mTextPaint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18)); + + mTextPaint.setColor(R.color.latinkeyboard_transparent); + mTextPaint.setTextAlign(Align.CENTER); + mTextPaint.setAlpha(OPACITY_FULLY_OPAQUE); + mTextPaint.setAntiAlias(true); + mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2; + mLeftDrawable = + mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_left); + mRightDrawable = + mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_right); + mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop(); + } + + private void setDiff(int diff) { + if (diff == Integer.MAX_VALUE) { + mHitThreshold = false; + mCurrentLanguage = null; + return; + } + mDiff = diff; + if (mDiff > mWidth) mDiff = mWidth; + if (mDiff < -mWidth) mDiff = -mWidth; + if (Math.abs(mDiff) > mThreshold) mHitThreshold = true; + invalidateSelf(); + } + + private String getLanguageName(Locale locale) { + return LanguageSwitcher.toTitleCase(locale.getDisplayLanguage(locale), locale); + } + + @Override + public void draw(Canvas canvas) { + canvas.save(); + if (mHitThreshold) { + Paint paint = mTextPaint; + final int width = mWidth; + final int height = mHeight; + final int diff = mDiff; + final Drawable lArrow = mLeftDrawable; + final Drawable rArrow = mRightDrawable; + canvas.clipRect(0, 0, width, height); + if (mCurrentLanguage == null) { + final LanguageSwitcher languageSwitcher = mLanguageSwitcher; + mCurrentLanguage = getLanguageName(languageSwitcher.getInputLocale()); + mNextLanguage = getLanguageName(languageSwitcher.getNextInputLocale()); + mPrevLanguage = getLanguageName(languageSwitcher.getPrevInputLocale()); + } + // Draw language text with shadow + final float baseline = mHeight * SPACEBAR_LANGUAGE_BASELINE - paint.descent(); + paint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text)); + canvas.drawText(mCurrentLanguage, width / 2 + diff, baseline, paint); + canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint); + canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint); + + setDefaultBounds(lArrow); + rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width, + rArrow.getIntrinsicHeight()); + lArrow.draw(canvas); + rArrow.draw(canvas); + } + if (mBackground != null) { + canvas.translate(mMiddleX, 0); + mBackground.draw(canvas); + } + canvas.restore(); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + // Ignore + } + + @Override + public void setColorFilter(ColorFilter cf) { + // Ignore + } + + @Override + public int getIntrinsicWidth() { + return mWidth; + } + + @Override + public int getIntrinsicHeight() { + return mHeight; + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboardBaseView.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboardBaseView.java new file mode 100644 index 00000000..0761aae2 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboardBaseView.java @@ -0,0 +1,1517 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.Region.Op; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.PopupWindow; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.WeakHashMap; + +/** + * A view that renders a virtual {@link LatinKeyboard}. It handles rendering of keys and + * detecting key presses and touch movements. + * + * TODO: References to LatinKeyboard in this class should be replaced with ones to its base class. + * + * @attr ref R.styleable#LatinKeyboardBaseView_keyBackground + * @attr ref R.styleable#LatinKeyboardBaseView_keyPreviewLayout + * @attr ref R.styleable#LatinKeyboardBaseView_keyPreviewOffset + * @attr ref R.styleable#LatinKeyboardBaseView_labelTextSize + * @attr ref R.styleable#LatinKeyboardBaseView_keyTextSize + * @attr ref R.styleable#LatinKeyboardBaseView_keyTextColor + * @attr ref R.styleable#LatinKeyboardBaseView_verticalCorrection + * @attr ref R.styleable#LatinKeyboardBaseView_popupLayout + */ +public class LatinKeyboardBaseView extends View implements PointerTracker.UIProxy { + private static final String TAG = "LatinKeyboardBaseView"; + private static final boolean DEBUG = false; + + public static final int NOT_A_TOUCH_COORDINATE = -1; + + public interface OnKeyboardActionListener { + + /** + * Called when the user presses a key. This is sent before the + * {@link #onKey} is called. For keys that repeat, this is only + * called once. + * + * @param primaryCode + * the unicode of the key being pressed. If the touch is + * not on a valid key, the value will be zero. + */ + void onPress(int primaryCode); + + /** + * Called when the user releases a key. This is sent after the + * {@link #onKey} is called. For keys that repeat, this is only + * called once. + * + * @param primaryCode + * the code of the key that was released + */ + void onRelease(int primaryCode); + + /** + * Send a key press to the listener. + * + * @param primaryCode + * this is the key that was pressed + * @param keyCodes + * the codes for all the possible alternative keys with + * the primary code being the first. If the primary key + * code is a single character such as an alphabet or + * number or symbol, the alternatives will include other + * characters that may be on the same key or adjacent + * keys. These codes are useful to correct for + * accidental presses of a key adjacent to the intended + * key. + * @param x + * x-coordinate pixel of touched event. If onKey is not called by onTouchEvent, + * the value should be NOT_A_TOUCH_COORDINATE. + * @param y + * y-coordinate pixel of touched event. If onKey is not called by onTouchEvent, + * the value should be NOT_A_TOUCH_COORDINATE. + */ + void onKey(int primaryCode, int[] keyCodes, int x, int y); + + /** + * Sends a sequence of characters to the listener. + * + * @param text + * the sequence of characters to be displayed. + */ + void onText(CharSequence text); + + /** + * Called when user released a finger outside any key. + */ + void onCancel(); + + /** + * Called when the user quickly moves the finger from right to + * left. + */ + void swipeLeft(); + + /** + * Called when the user quickly moves the finger from left to + * right. + */ + void swipeRight(); + + /** + * Called when the user quickly moves the finger from up to down. + */ + void swipeDown(); + + /** + * Called when the user quickly moves the finger from down to up. + */ + void swipeUp(); + } + + // Timing constants + private final int mKeyRepeatInterval; + + // Miscellaneous constants + /* package */ static final int NOT_A_KEY = -1; + private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable }; + private static final int NUMBER_HINT_VERTICAL_ADJUSTMENT_PIXEL = -1; + + // XML attribute + private int mKeyTextSize; + private int mKeyTextColor; + private Typeface mKeyTextStyle = Typeface.DEFAULT; + private int mLabelTextSize; + private int mSymbolColorScheme = 0; + private int mShadowColor; + private float mShadowRadius; + private Drawable mKeyBackground; + private float mBackgroundDimAmount; + private float mKeyHysteresisDistance; + private float mVerticalCorrection; + private int mPreviewOffset; + private int mPreviewHeight; + private int mPopupLayout; + + // Main keyboard + private Keyboard mKeyboard; + private Key[] mKeys; + // TODO this attribute should be gotten from Keyboard. + private int mKeyboardVerticalGap; + + // Key preview popup + private TextView mPreviewText; + private PopupWindow mPreviewPopup; + private int mPreviewTextSizeLarge; + private int[] mOffsetInWindow; + private int mOldPreviewKeyIndex = NOT_A_KEY; + private boolean mShowPreview = true; + private boolean mShowTouchPoints = true; + private int mPopupPreviewOffsetX; + private int mPopupPreviewOffsetY; + private int mWindowY; + private int mPopupPreviewDisplayedY; + private final int mDelayBeforePreview; + private final int mDelayAfterPreview; + + // Popup mini keyboard + private PopupWindow mMiniKeyboardPopup; + private LatinKeyboardBaseView mMiniKeyboard; + private View mMiniKeyboardParent; + private final WeakHashMap mMiniKeyboardCache = new WeakHashMap(); + private int mMiniKeyboardOriginX; + private int mMiniKeyboardOriginY; + private long mMiniKeyboardPopupTime; + private int[] mWindowOffset; + private final float mMiniKeyboardSlideAllowance; + private int mMiniKeyboardTrackerId; + + /** Listener for {@link OnKeyboardActionListener}. */ + private OnKeyboardActionListener mKeyboardActionListener; + + private final ArrayList mPointerTrackers = new ArrayList(); + + // TODO: Let the PointerTracker class manage this pointer queue + private final PointerQueue mPointerQueue = new PointerQueue(); + + private final boolean mHasDistinctMultitouch; + private int mOldPointerCount = 1; + + protected KeyDetector mKeyDetector = new ProximityKeyDetector(); + + // Swipe gesture detector + private GestureDetector mGestureDetector; + private final SwipeTracker mSwipeTracker = new SwipeTracker(); + private final int mSwipeThreshold; + private final boolean mDisambiguateSwipe; + + // Drawing + /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ + private boolean mDrawPending; + /** The dirty region in the keyboard bitmap */ + private final Rect mDirtyRect = new Rect(); + /** The keyboard bitmap for faster updates */ + private Bitmap mBuffer; + /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ + private boolean mKeyboardChanged; + private Key mInvalidatedKey; + /** The canvas for the above mutable keyboard bitmap */ + private Canvas mCanvas; + private final Paint mPaint; + private final Rect mPadding; + private final Rect mClipRegion = new Rect(0, 0, 0, 0); + // This map caches key label text height in pixel as value and key label text size as map key. + private final HashMap mTextHeightCache = new HashMap(); + // Distance from horizontal center of the key, proportional to key label text height. + private final float KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR = 0.55f; + private final String KEY_LABEL_HEIGHT_REFERENCE_CHAR = "H"; + + private final UIHandler mHandler = new UIHandler(); + + class UIHandler extends Handler { + private static final int MSG_POPUP_PREVIEW = 1; + private static final int MSG_DISMISS_PREVIEW = 2; + private static final int MSG_REPEAT_KEY = 3; + private static final int MSG_LONGPRESS_KEY = 4; + + private boolean mInKeyRepeat; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_POPUP_PREVIEW: + showKey(msg.arg1, (PointerTracker)msg.obj); + break; + case MSG_DISMISS_PREVIEW: + mPreviewPopup.dismiss(); + break; + case MSG_REPEAT_KEY: { + final PointerTracker tracker = (PointerTracker)msg.obj; + tracker.repeatKey(msg.arg1); + startKeyRepeatTimer(mKeyRepeatInterval, msg.arg1, tracker); + break; + } + case MSG_LONGPRESS_KEY: { + final PointerTracker tracker = (PointerTracker)msg.obj; + openPopupIfRequired(msg.arg1, tracker); + break; + } + } + } + + public void popupPreview(long delay, int keyIndex, PointerTracker tracker) { + removeMessages(MSG_POPUP_PREVIEW); + if (mPreviewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { + // Show right away, if it's already visible and finger is moving around + showKey(keyIndex, tracker); + } else { + sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), + delay); + } + } + + public void cancelPopupPreview() { + removeMessages(MSG_POPUP_PREVIEW); + } + + public void dismissPreview(long delay) { + if (mPreviewPopup.isShowing()) { + sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); + } + } + + public void cancelDismissPreview() { + removeMessages(MSG_DISMISS_PREVIEW); + } + + public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { + mInKeyRepeat = true; + sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); + } + + public void cancelKeyRepeatTimer() { + mInKeyRepeat = false; + removeMessages(MSG_REPEAT_KEY); + } + + public boolean isInKeyRepeat() { + return mInKeyRepeat; + } + + public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { + removeMessages(MSG_LONGPRESS_KEY); + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); + } + + public void cancelLongPressTimer() { + removeMessages(MSG_LONGPRESS_KEY); + } + + public void cancelKeyTimers() { + cancelKeyRepeatTimer(); + cancelLongPressTimer(); + } + + public void cancelAllMessages() { + cancelKeyTimers(); + cancelPopupPreview(); + cancelDismissPreview(); + } + } + + static class PointerQueue { + private LinkedList mQueue = new LinkedList(); + + public void add(PointerTracker tracker) { + mQueue.add(tracker); + } + + public int lastIndexOf(PointerTracker tracker) { + LinkedList queue = mQueue; + for (int index = queue.size() - 1; index >= 0; index--) { + PointerTracker t = queue.get(index); + if (t == tracker) + return index; + } + return -1; + } + + public void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) { + LinkedList queue = mQueue; + int oldestPos = 0; + for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) { + if (t.isModifier()) { + oldestPos++; + } else { + t.onUpEvent(t.getLastX(), t.getLastY(), eventTime); + t.setAlreadyProcessed(); + queue.remove(oldestPos); + } + } + } + + public void releaseAllPointersExcept(PointerTracker tracker, long eventTime) { + for (PointerTracker t : mQueue) { + if (t == tracker) + continue; + t.onUpEvent(t.getLastX(), t.getLastY(), eventTime); + t.setAlreadyProcessed(); + } + mQueue.clear(); + if (tracker != null) + mQueue.add(tracker); + } + + public void remove(PointerTracker tracker) { + mQueue.remove(tracker); + } + + public boolean isInSlidingKeyInput() { + for (final PointerTracker tracker : mQueue) { + if (tracker.isInSlidingKeyInput()) + return true; + } + return false; + } + } + + public LatinKeyboardBaseView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.keyboardViewStyle); + } + + public LatinKeyboardBaseView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.LatinKeyboardBaseView, defStyle, R.style.LatinKeyboardBaseView); + LayoutInflater inflate = + (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + int previewLayout = 0; + int keyTextSize = 0; + + int n = a.getIndexCount(); + + for (int i = 0; i < n; i++) { + int attr = a.getIndex(i); + + switch (attr) { + case R.styleable.LatinKeyboardBaseView_keyBackground: + mKeyBackground = a.getDrawable(attr); + break; + case R.styleable.LatinKeyboardBaseView_keyHysteresisDistance: + mKeyHysteresisDistance = a.getDimensionPixelOffset(attr, 0); + break; + case R.styleable.LatinKeyboardBaseView_verticalCorrection: + mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); + break; + case R.styleable.LatinKeyboardBaseView_keyPreviewLayout: + previewLayout = a.getResourceId(attr, 0); + break; + case R.styleable.LatinKeyboardBaseView_keyPreviewOffset: + mPreviewOffset = a.getDimensionPixelOffset(attr, 0); + break; + case R.styleable.LatinKeyboardBaseView_keyPreviewHeight: + mPreviewHeight = a.getDimensionPixelSize(attr, 80); + break; + case R.styleable.LatinKeyboardBaseView_keyTextSize: + mKeyTextSize = a.getDimensionPixelSize(attr, 18); + break; + case R.styleable.LatinKeyboardBaseView_keyTextColor: + mKeyTextColor = a.getColor(attr, 0xFF000000); + break; + case R.styleable.LatinKeyboardBaseView_labelTextSize: + mLabelTextSize = a.getDimensionPixelSize(attr, 14); + break; + case R.styleable.LatinKeyboardBaseView_popupLayout: + mPopupLayout = a.getResourceId(attr, 0); + break; + case R.styleable.LatinKeyboardBaseView_shadowColor: + mShadowColor = a.getColor(attr, 0); + break; + case R.styleable.LatinKeyboardBaseView_shadowRadius: + mShadowRadius = a.getFloat(attr, 0f); + break; + // TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount) + case R.styleable.LatinKeyboardBaseView_backgroundDimAmount: + mBackgroundDimAmount = a.getFloat(attr, 0.5f); + break; + //case android.R.styleable. + case R.styleable.LatinKeyboardBaseView_keyTextStyle: + int textStyle = a.getInt(attr, 0); + switch (textStyle) { + case 0: + mKeyTextStyle = Typeface.DEFAULT; + break; + case 1: + mKeyTextStyle = Typeface.DEFAULT_BOLD; + break; + default: + mKeyTextStyle = Typeface.defaultFromStyle(textStyle); + break; + } + break; + case R.styleable.LatinKeyboardBaseView_symbolColorScheme: + mSymbolColorScheme = a.getInt(attr, 0); + break; + } + } + + final Resources res = getResources(); + + mPreviewPopup = new PopupWindow(context); + if (previewLayout != 0) { + mPreviewText = (TextView) inflate.inflate(previewLayout, null); + mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large); + mPreviewPopup.setContentView(mPreviewText); + mPreviewPopup.setBackgroundDrawable(null); + } else { + mShowPreview = false; + } + mPreviewPopup.setTouchable(false); + mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); + mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview); + mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview); + + mMiniKeyboardParent = this; + mMiniKeyboardPopup = new PopupWindow(context); + mMiniKeyboardPopup.setBackgroundDrawable(null); + mMiniKeyboardPopup.setAnimationStyle(R.style.MiniKeyboardAnimation); + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(keyTextSize); + mPaint.setTextAlign(Align.CENTER); + mPaint.setAlpha(255); + + mPadding = new Rect(0, 0, 0, 0); + mKeyBackground.getPadding(mPadding); + + mSwipeThreshold = (int) (500 * res.getDisplayMetrics().density); + // TODO: Refer frameworks/base/core/res/res/values/config.xml + mDisambiguateSwipe = res.getBoolean(R.bool.config_swipeDisambiguation); + mMiniKeyboardSlideAllowance = res.getDimension(R.dimen.mini_keyboard_slide_allowance); + + GestureDetector.SimpleOnGestureListener listener = + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent me1, MotionEvent me2, float velocityX, + float velocityY) { + final float absX = Math.abs(velocityX); + final float absY = Math.abs(velocityY); + float deltaX = me2.getX() - me1.getX(); + float deltaY = me2.getY() - me1.getY(); + int travelX = getWidth() / 2; // Half the keyboard width + int travelY = getHeight() / 2; // Half the keyboard height + mSwipeTracker.computeCurrentVelocity(1000); + final float endingVelocityX = mSwipeTracker.getXVelocity(); + final float endingVelocityY = mSwipeTracker.getYVelocity(); + if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) { + if (mDisambiguateSwipe && endingVelocityX >= velocityX / 4) { + swipeRight(); + return true; + } + } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) { + if (mDisambiguateSwipe && endingVelocityX <= velocityX / 4) { + swipeLeft(); + return true; + } + } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) { + if (mDisambiguateSwipe && endingVelocityY <= velocityY / 4) { + swipeUp(); + return true; + } + } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) { + if (mDisambiguateSwipe && endingVelocityY >= velocityY / 4) { + swipeDown(); + return true; + } + } + return false; + } + }; + + final boolean ignoreMultitouch = true; + mGestureDetector = new GestureDetector(getContext(), listener, null, ignoreMultitouch); + mGestureDetector.setIsLongpressEnabled(false); + + mHasDistinctMultitouch = context.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); + mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); + } + + public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { + mKeyboardActionListener = listener; + for (PointerTracker tracker : mPointerTrackers) { + tracker.setOnKeyboardActionListener(listener); + } + } + + /** + * Returns the {@link OnKeyboardActionListener} object. + * @return the listener attached to this keyboard + */ + protected OnKeyboardActionListener getOnKeyboardActionListener() { + return mKeyboardActionListener; + } + + /** + * Attaches a keyboard to this view. The keyboard can be switched at any time and the + * view will re-layout itself to accommodate the keyboard. + * @see Keyboard + * @see #getKeyboard() + * @param keyboard the keyboard to display in this view + */ + public void setKeyboard(Keyboard keyboard) { + if (mKeyboard != null) { + dismissKeyPreview(); + } + // Remove any pending messages, except dismissing preview + mHandler.cancelKeyTimers(); + mHandler.cancelPopupPreview(); + mKeyboard = keyboard; + LatinImeLogger.onSetKeyboard(keyboard); + mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), + -getPaddingTop() + mVerticalCorrection); + mKeyboardVerticalGap = (int)getResources().getDimension(R.dimen.key_bottom_gap); + for (PointerTracker tracker : mPointerTrackers) { + tracker.setKeyboard(mKeys, mKeyHysteresisDistance); + } + requestLayout(); + // Hint to reallocate the buffer if the size changed + mKeyboardChanged = true; + invalidateAllKeys(); + computeProximityThreshold(keyboard); + mMiniKeyboardCache.clear(); + } + + /** + * Returns the current keyboard being displayed by this view. + * @return the currently attached keyboard + * @see #setKeyboard(Keyboard) + */ + public Keyboard getKeyboard() { + return mKeyboard; + } + + /** + * Return whether the device has distinct multi-touch panel. + * @return true if the device has distinct multi-touch panel. + */ + public boolean hasDistinctMultitouch() { + return mHasDistinctMultitouch; + } + + /** + * Sets the state of the shift key of the keyboard, if any. + * @param shifted whether or not to enable the state of the shift key + * @return true if the shift key state changed, false if there was no change + */ + public boolean setShifted(boolean shifted) { + if (mKeyboard != null) { + if (mKeyboard.setShifted(shifted)) { + // The whole keyboard probably needs to be redrawn + invalidateAllKeys(); + return true; + } + } + return false; + } + + /** + * Returns the state of the shift key of the keyboard, if any. + * @return true if the shift is in a pressed state, false otherwise. If there is + * no shift key on the keyboard or there is no keyboard attached, it returns false. + */ + public boolean isShifted() { + if (mKeyboard != null) { + return mKeyboard.isShifted(); + } + return false; + } + + /** + * Enables or disables the key feedback popup. This is a popup that shows a magnified + * version of the depressed key. By default the preview is enabled. + * @param previewEnabled whether or not to enable the key feedback popup + * @see #isPreviewEnabled() + */ + public void setPreviewEnabled(boolean previewEnabled) { + mShowPreview = previewEnabled; + } + + /** + * Returns the enabled state of the key feedback popup. + * @return whether or not the key feedback popup is enabled + * @see #setPreviewEnabled(boolean) + */ + public boolean isPreviewEnabled() { + return mShowPreview; + } + + public int getSymbolColorScheme() { + return mSymbolColorScheme; + } + + public void setPopupParent(View v) { + mMiniKeyboardParent = v; + } + + public void setPopupOffset(int x, int y) { + mPopupPreviewOffsetX = x; + mPopupPreviewOffsetY = y; + mPreviewPopup.dismiss(); + } + + /** + * When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key + * codes for adjacent keys. When disabled, only the primary key code will be + * reported. + * @param enabled whether or not the proximity correction is enabled + */ + public void setProximityCorrectionEnabled(boolean enabled) { + mKeyDetector.setProximityCorrectionEnabled(enabled); + } + + /** + * Returns true if proximity correction is enabled. + */ + public boolean isProximityCorrectionEnabled() { + return mKeyDetector.isProximityCorrectionEnabled(); + } + + protected Locale getKeyboardLocale() { + if (mKeyboard instanceof LatinKeyboard) { + return ((LatinKeyboard)mKeyboard).getInputLocale(); + } else { + return getContext().getResources().getConfiguration().locale; + } + } + + protected CharSequence adjustCase(CharSequence label) { + if (mKeyboard.isShifted() && label != null && label.length() < 3 + && Character.isLowerCase(label.charAt(0))) { + return label.toString().toUpperCase(getKeyboardLocale()); + } + return label; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Round up a little + if (mKeyboard == null) { + setMeasuredDimension( + getPaddingLeft() + getPaddingRight(), getPaddingTop() + getPaddingBottom()); + } else { + int width = mKeyboard.getMinWidth() + getPaddingLeft() + getPaddingRight(); + if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { + width = MeasureSpec.getSize(widthMeasureSpec); + } + setMeasuredDimension( + width, mKeyboard.getHeight() + getPaddingTop() + getPaddingBottom()); + } + } + + /** + * Compute the average distance between adjacent keys (horizontally and vertically) + * and square it to get the proximity threshold. We use a square here and in computing + * the touch distance from a key's center to avoid taking a square root. + * @param keyboard + */ + private void computeProximityThreshold(Keyboard keyboard) { + if (keyboard == null) return; + final Key[] keys = mKeys; + if (keys == null) return; + int length = keys.length; + int dimensionSum = 0; + for (int i = 0; i < length; i++) { + Key key = keys[i]; + dimensionSum += Math.min(key.width, key.height + mKeyboardVerticalGap) + key.gap; + } + if (dimensionSum < 0 || length == 0) return; + mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length)); + } + + @Override + public void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + // Release the buffer, if any and it will be reallocated on the next draw + mBuffer = null; + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mDrawPending || mBuffer == null || mKeyboardChanged) { + onBufferDraw(); + } + canvas.drawBitmap(mBuffer, 0, 0, null); + } + + private void onBufferDraw() { + if (mBuffer == null || mKeyboardChanged) { + if (mBuffer == null || mKeyboardChanged && + (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) { + // Make sure our bitmap is at least 1x1 + final int width = Math.max(1, getWidth()); + final int height = Math.max(1, getHeight()); + mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + mCanvas = new Canvas(mBuffer); + } + invalidateAllKeys(); + mKeyboardChanged = false; + } + final Canvas canvas = mCanvas; + canvas.clipRect(mDirtyRect, Op.REPLACE); + + if (mKeyboard == null) return; + + final Paint paint = mPaint; + final Drawable keyBackground = mKeyBackground; + final Rect clipRegion = mClipRegion; + final Rect padding = mPadding; + final int kbdPaddingLeft = getPaddingLeft(); + final int kbdPaddingTop = getPaddingTop(); + final Key[] keys = mKeys; + final Key invalidKey = mInvalidatedKey; + + paint.setColor(mKeyTextColor); + boolean drawSingleKey = false; + if (invalidKey != null && canvas.getClipBounds(clipRegion)) { + // TODO we should use Rect.inset and Rect.contains here. + // Is clipRegion completely contained within the invalidated key? + if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left && + invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top && + invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right && + invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) { + drawSingleKey = true; + } + } + canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + final int keyCount = keys.length; + for (int i = 0; i < keyCount; i++) { + final Key key = keys[i]; + if (drawSingleKey && invalidKey != key) { + continue; + } + int[] drawableState = key.getCurrentDrawableState(); + keyBackground.setState(drawableState); + + // Switch the character to uppercase if shift is pressed + String label = key.label == null? null : adjustCase(key.label).toString(); + + final Rect bounds = keyBackground.getBounds(); + if (key.width != bounds.right || key.height != bounds.bottom) { + keyBackground.setBounds(0, 0, key.width, key.height); + } + canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); + keyBackground.draw(canvas); + + boolean shouldDrawIcon = true; + if (label != null) { + // For characters, use large font. For labels like "Done", use small font. + final int labelSize; + if (label.length() > 1 && key.codes.length < 2) { + labelSize = mLabelTextSize; + paint.setTypeface(Typeface.DEFAULT_BOLD); + } else { + labelSize = mKeyTextSize; + paint.setTypeface(mKeyTextStyle); + } + paint.setTextSize(labelSize); + + Integer labelHeightValue = mTextHeightCache.get(labelSize); + final int labelHeight; + if (labelHeightValue != null) { + labelHeight = labelHeightValue; + } else { + Rect textBounds = new Rect(); + paint.getTextBounds(KEY_LABEL_HEIGHT_REFERENCE_CHAR, 0, 1, textBounds); + labelHeight = textBounds.height(); + mTextHeightCache.put(labelSize, labelHeight); + } + + // Draw a drop shadow for the text + paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); + final int centerX = (key.width + padding.left - padding.right) / 2; + final int centerY = (key.height + padding.top - padding.bottom) / 2; + final float baseline = centerY + + labelHeight * KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR; + canvas.drawText(label, centerX, baseline, paint); + // Turn off drop shadow + paint.setShadowLayer(0, 0, 0, 0); + + // Usually don't draw icon if label is not null, but we draw icon for the number + // hint and popup hint. + shouldDrawIcon = shouldDrawLabelAndIcon(key); + } + if (key.icon != null && shouldDrawIcon) { + // Special handing for the upper-right number hint icons + final int drawableWidth; + final int drawableHeight; + final int drawableX; + final int drawableY; + if (shouldDrawIconFully(key)) { + drawableWidth = key.width; + drawableHeight = key.height; + drawableX = 0; + drawableY = NUMBER_HINT_VERTICAL_ADJUSTMENT_PIXEL; + } else { + drawableWidth = key.icon.getIntrinsicWidth(); + drawableHeight = key.icon.getIntrinsicHeight(); + drawableX = (key.width + padding.left - padding.right - drawableWidth) / 2; + drawableY = (key.height + padding.top - padding.bottom - drawableHeight) / 2; + } + canvas.translate(drawableX, drawableY); + key.icon.setBounds(0, 0, drawableWidth, drawableHeight); + key.icon.draw(canvas); + canvas.translate(-drawableX, -drawableY); + } + canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); + } + mInvalidatedKey = null; + // Overlay a dark rectangle to dim the keyboard + if (mMiniKeyboard != null) { + paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); + canvas.drawRect(0, 0, getWidth(), getHeight(), paint); + } + + if (DEBUG) { + if (mShowTouchPoints) { + for (PointerTracker tracker : mPointerTrackers) { + int startX = tracker.getStartX(); + int startY = tracker.getStartY(); + int lastX = tracker.getLastX(); + int lastY = tracker.getLastY(); + paint.setAlpha(128); + paint.setColor(0xFFFF0000); + canvas.drawCircle(startX, startY, 3, paint); + canvas.drawLine(startX, startY, lastX, lastY, paint); + paint.setColor(0xFF0000FF); + canvas.drawCircle(lastX, lastY, 3, paint); + paint.setColor(0xFF00FF00); + canvas.drawCircle((startX + lastX) / 2, (startY + lastY) / 2, 2, paint); + } + } + } + + mDrawPending = false; + mDirtyRect.setEmpty(); + } + + // TODO: clean up this method. + private void dismissKeyPreview() { + for (PointerTracker tracker : mPointerTrackers) + tracker.updateKey(NOT_A_KEY); + showPreview(NOT_A_KEY, null); + } + + public void showPreview(int keyIndex, PointerTracker tracker) { + int oldKeyIndex = mOldPreviewKeyIndex; + mOldPreviewKeyIndex = keyIndex; + final boolean isLanguageSwitchEnabled = (mKeyboard instanceof LatinKeyboard) + && ((LatinKeyboard)mKeyboard).isLanguageSwitchEnabled(); + // We should re-draw popup preview when 1) we need to hide the preview, 2) we will show + // the space key preview and 3) pointer moves off the space key to other letter key, we + // should hide the preview of the previous key. + final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null) + || tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex); + // If key changed and preview is on or the key is space (language switch is enabled) + if (oldKeyIndex != keyIndex + && (mShowPreview + || (hidePreviewOrShowSpaceKeyPreview && isLanguageSwitchEnabled))) { + if (keyIndex == NOT_A_KEY) { + mHandler.cancelPopupPreview(); + mHandler.dismissPreview(mDelayAfterPreview); + } else if (tracker != null) { + mHandler.popupPreview(mDelayBeforePreview, keyIndex, tracker); + } + } + } + + private void showKey(final int keyIndex, PointerTracker tracker) { + Key key = tracker.getKey(keyIndex); + if (key == null) + return; + // Should not draw hint icon in key preview + if (key.icon != null && !shouldDrawLabelAndIcon(key)) { + mPreviewText.setCompoundDrawables(null, null, null, + key.iconPreview != null ? key.iconPreview : key.icon); + mPreviewText.setText(null); + } else { + mPreviewText.setCompoundDrawables(null, null, null, null); + mPreviewText.setText(adjustCase(tracker.getPreviewText(key))); + if (key.label.length() > 1 && key.codes.length < 2) { + mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); + mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); + } else { + mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); + mPreviewText.setTypeface(mKeyTextStyle); + } + } + mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width + + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); + final int popupHeight = mPreviewHeight; + LayoutParams lp = mPreviewText.getLayoutParams(); + if (lp != null) { + lp.width = popupWidth; + lp.height = popupHeight; + } + + int popupPreviewX = key.x - (popupWidth - key.width) / 2; + int popupPreviewY = key.y - popupHeight + mPreviewOffset; + + mHandler.cancelDismissPreview(); + if (mOffsetInWindow == null) { + mOffsetInWindow = new int[2]; + getLocationInWindow(mOffsetInWindow); + mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero + mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero + int[] windowLocation = new int[2]; + getLocationOnScreen(windowLocation); + mWindowY = windowLocation[1]; + } + // Set the preview background state + mPreviewText.getBackground().setState( + key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); + popupPreviewX += mOffsetInWindow[0]; + popupPreviewY += mOffsetInWindow[1]; + + // If the popup cannot be shown above the key, put it on the side + if (popupPreviewY + mWindowY < 0) { + // If the key you're pressing is on the left side of the keyboard, show the popup on + // the right, offset by enough to see at least one key to the left/right. + if (key.x + key.width <= getWidth() / 2) { + popupPreviewX += (int) (key.width * 2.5); + } else { + popupPreviewX -= (int) (key.width * 2.5); + } + popupPreviewY += popupHeight; + } + + if (mPreviewPopup.isShowing()) { + mPreviewPopup.update(popupPreviewX, popupPreviewY, popupWidth, popupHeight); + } else { + mPreviewPopup.setWidth(popupWidth); + mPreviewPopup.setHeight(popupHeight); + mPreviewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY, + popupPreviewX, popupPreviewY); + } + // Record popup preview position to display mini-keyboard later at the same positon + mPopupPreviewDisplayedY = popupPreviewY; + mPreviewText.setVisibility(VISIBLE); + } + + /** + * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient + * because the keyboard renders the keys to an off-screen buffer and an invalidate() only + * draws the cached buffer. + * @see #invalidateKey(Key) + */ + public void invalidateAllKeys() { + mDirtyRect.union(0, 0, getWidth(), getHeight()); + mDrawPending = true; + invalidate(); + } + + /** + * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only + * one key is changing it's content. Any changes that affect the position or size of the key + * may not be honored. + * @param key key in the attached {@link Keyboard}. + * @see #invalidateAllKeys + */ + public void invalidateKey(Key key) { + if (key == null) + return; + mInvalidatedKey = key; + // TODO we should clean up this and record key's region to use in onBufferDraw. + mDirtyRect.union(key.x + getPaddingLeft(), key.y + getPaddingTop(), + key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); + onBufferDraw(); + invalidate(key.x + getPaddingLeft(), key.y + getPaddingTop(), + key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); + } + + private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) { + // Check if we have a popup layout specified first. + if (mPopupLayout == 0) { + return false; + } + + Key popupKey = tracker.getKey(keyIndex); + if (popupKey == null) + return false; + boolean result = onLongPress(popupKey); + if (result) { + dismissKeyPreview(); + mMiniKeyboardTrackerId = tracker.mPointerId; + // Mark this tracker "already processed" and remove it from the pointer queue + tracker.setAlreadyProcessed(); + mPointerQueue.remove(tracker); + } + return result; + } + + private View inflateMiniKeyboardContainer(Key popupKey) { + int popupKeyboardId = popupKey.popupResId; + LayoutInflater inflater = (LayoutInflater)getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + View container = inflater.inflate(mPopupLayout, null); + if (container == null) + throw new NullPointerException(); + + LatinKeyboardBaseView miniKeyboard = + (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView); + miniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { + public void onKey(int primaryCode, int[] keyCodes, int x, int y) { + mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y); + dismissPopupKeyboard(); + } + + public void onText(CharSequence text) { + mKeyboardActionListener.onText(text); + dismissPopupKeyboard(); + } + + public void onCancel() { + mKeyboardActionListener.onCancel(); + dismissPopupKeyboard(); + } + + public void swipeLeft() { + } + public void swipeRight() { + } + public void swipeUp() { + } + public void swipeDown() { + } + public void onPress(int primaryCode) { + mKeyboardActionListener.onPress(primaryCode); + } + public void onRelease(int primaryCode) { + mKeyboardActionListener.onRelease(primaryCode); + } + }); + // Override default ProximityKeyDetector. + miniKeyboard.mKeyDetector = new MiniKeyboardKeyDetector(mMiniKeyboardSlideAllowance); + // Remove gesture detector on mini-keyboard + miniKeyboard.mGestureDetector = null; + + Keyboard keyboard; + if (popupKey.popupCharacters != null) { + keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.popupCharacters, + -1, getPaddingLeft() + getPaddingRight()); + } else { + keyboard = new Keyboard(getContext(), popupKeyboardId); + } + miniKeyboard.setKeyboard(keyboard); + miniKeyboard.setPopupParent(this); + + container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); + + return container; + } + + private static boolean isOneRowKeys(List keys) { + if (keys.size() == 0) return false; + final int edgeFlags = keys.get(0).edgeFlags; + // HACK: The first key of mini keyboard which was inflated from xml and has multiple rows, + // does not have both top and bottom edge flags on at the same time. On the other hand, + // the first key of mini keyboard that was created with popupCharacters must have both top + // and bottom edge flags on. + // When you want to use one row mini-keyboard from xml file, make sure that the row has + // both top and bottom edge flags set. + return (edgeFlags & Keyboard.EDGE_TOP) != 0 && (edgeFlags & Keyboard.EDGE_BOTTOM) != 0; + } + + /** + * Called when a key is long pressed. By default this will open any popup keyboard associated + * with this key through the attributes popupLayout and popupCharacters. + * @param popupKey the key that was long pressed + * @return true if the long press is handled, false otherwise. Subclasses should call the + * method on the base class if the subclass doesn't wish to handle the call. + */ + protected boolean onLongPress(Key popupKey) { + // TODO if popupKey.popupCharacters has only one letter, send it as key without opening + // mini keyboard. + + if (popupKey.popupResId == 0) + return false; + + View container = mMiniKeyboardCache.get(popupKey); + if (container == null) { + container = inflateMiniKeyboardContainer(popupKey); + mMiniKeyboardCache.put(popupKey, container); + } + mMiniKeyboard = (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView); + if (mWindowOffset == null) { + mWindowOffset = new int[2]; + getLocationInWindow(mWindowOffset); + } + + // Get width of a key in the mini popup keyboard = "miniKeyWidth". + // On the other hand, "popupKey.width" is width of the pressed key on the main keyboard. + // We adjust the position of mini popup keyboard with the edge key in it: + // a) When we have the leftmost key in popup keyboard directly above the pressed key + // Right edges of both keys should be aligned for consistent default selection + // b) When we have the rightmost key in popup keyboard directly above the pressed key + // Left edges of both keys should be aligned for consistent default selection + final List miniKeys = mMiniKeyboard.getKeyboard().getKeys(); + final int miniKeyWidth = miniKeys.size() > 0 ? miniKeys.get(0).width : 0; + + // HACK: Have the leftmost number in the popup characters right above the key + boolean isNumberAtLeftmost = + hasMultiplePopupChars(popupKey) && isNumberAtLeftmostPopupChar(popupKey); + int popupX = popupKey.x + mWindowOffset[0]; + popupX += getPaddingLeft(); + if (isNumberAtLeftmost) { + popupX += popupKey.width - miniKeyWidth; // adjustment for a) described above + popupX -= container.getPaddingLeft(); + } else { + popupX += miniKeyWidth; // adjustment for b) described above + popupX -= container.getMeasuredWidth(); + popupX += container.getPaddingRight(); + } + int popupY = popupKey.y + mWindowOffset[1]; + popupY += getPaddingTop(); + popupY -= container.getMeasuredHeight(); + popupY += container.getPaddingBottom(); + final int x = popupX; + final int y = mShowPreview && isOneRowKeys(miniKeys) ? mPopupPreviewDisplayedY : popupY; + + int adjustedX = x; + if (x < 0) { + adjustedX = 0; + } else if (x > (getMeasuredWidth() - container.getMeasuredWidth())) { + adjustedX = getMeasuredWidth() - container.getMeasuredWidth(); + } + mMiniKeyboardOriginX = adjustedX + container.getPaddingLeft() - mWindowOffset[0]; + mMiniKeyboardOriginY = y + container.getPaddingTop() - mWindowOffset[1]; + mMiniKeyboard.setPopupOffset(adjustedX, y); + mMiniKeyboard.setShifted(isShifted()); + // Mini keyboard needs no pop-up key preview displayed. + mMiniKeyboard.setPreviewEnabled(false); + mMiniKeyboardPopup.setContentView(container); + mMiniKeyboardPopup.setWidth(container.getMeasuredWidth()); + mMiniKeyboardPopup.setHeight(container.getMeasuredHeight()); + mMiniKeyboardPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y); + + // Inject down event on the key to mini keyboard. + long eventTime = SystemClock.uptimeMillis(); + mMiniKeyboardPopupTime = eventTime; + MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, popupKey.x + + popupKey.width / 2, popupKey.y + popupKey.height / 2, eventTime); + mMiniKeyboard.onTouchEvent(downEvent); + downEvent.recycle(); + + invalidateAllKeys(); + return true; + } + + private static boolean hasMultiplePopupChars(Key key) { + if (key.popupCharacters != null && key.popupCharacters.length() > 1) { + return true; + } + return false; + } + + private boolean shouldDrawIconFully(Key key) { + return isNumberAtEdgeOfPopupChars(key) || isLatinF1Key(key) + || LatinKeyboard.hasPuncOrSmileysPopup(key); + } + + private boolean shouldDrawLabelAndIcon(Key key) { + return isNumberAtEdgeOfPopupChars(key) || isNonMicLatinF1Key(key) + || LatinKeyboard.hasPuncOrSmileysPopup(key); + } + + private boolean isLatinF1Key(Key key) { + return (mKeyboard instanceof LatinKeyboard) && ((LatinKeyboard)mKeyboard).isF1Key(key); + } + + private boolean isNonMicLatinF1Key(Key key) { + return isLatinF1Key(key) && key.label != null; + } + + private static boolean isNumberAtEdgeOfPopupChars(Key key) { + return isNumberAtLeftmostPopupChar(key) || isNumberAtRightmostPopupChar(key); + } + + /* package */ static boolean isNumberAtLeftmostPopupChar(Key key) { + if (key.popupCharacters != null && key.popupCharacters.length() > 0 + && isAsciiDigit(key.popupCharacters.charAt(0))) { + return true; + } + return false; + } + + /* package */ static boolean isNumberAtRightmostPopupChar(Key key) { + if (key.popupCharacters != null && key.popupCharacters.length() > 0 + && isAsciiDigit(key.popupCharacters.charAt(key.popupCharacters.length() - 1))) { + return true; + } + return false; + } + + private static boolean isAsciiDigit(char c) { + return (c < 0x80) && Character.isDigit(c); + } + + private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) { + return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action, + x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0); + } + + private PointerTracker getPointerTracker(final int id) { + final ArrayList pointers = mPointerTrackers; + final Key[] keys = mKeys; + final OnKeyboardActionListener listener = mKeyboardActionListener; + + // Create pointer trackers until we can get 'id+1'-th tracker, if needed. + for (int i = pointers.size(); i <= id; i++) { + final PointerTracker tracker = + new PointerTracker(i, mHandler, mKeyDetector, this, getResources()); + if (keys != null) + tracker.setKeyboard(keys, mKeyHysteresisDistance); + if (listener != null) + tracker.setOnKeyboardActionListener(listener); + pointers.add(tracker); + } + + return pointers.get(id); + } + + public boolean isInSlidingKeyInput() { + if (mMiniKeyboard != null) { + return mMiniKeyboard.isInSlidingKeyInput(); + } else { + return mPointerQueue.isInSlidingKeyInput(); + } + } + + public int getPointerCount() { + return mOldPointerCount; + } + + @Override + public boolean onTouchEvent(MotionEvent me) { + final int action = me.getActionMasked(); + final int pointerCount = me.getPointerCount(); + final int oldPointerCount = mOldPointerCount; + mOldPointerCount = pointerCount; + + // TODO: cleanup this code into a multi-touch to single-touch event converter class? + // If the device does not have distinct multi-touch support panel, ignore all multi-touch + // events except a transition from/to single-touch. + if (!mHasDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { + return true; + } + + // Track the last few movements to look for spurious swipes. + mSwipeTracker.addMovement(me); + + // Gesture detector must be enabled only when mini-keyboard is not on the screen. + if (mMiniKeyboard == null + && mGestureDetector != null && mGestureDetector.onTouchEvent(me)) { + dismissKeyPreview(); + mHandler.cancelKeyTimers(); + return true; + } + + final long eventTime = me.getEventTime(); + final int index = me.getActionIndex(); + final int id = me.getPointerId(index); + final int x = (int)me.getX(index); + final int y = (int)me.getY(index); + + // Needs to be called after the gesture detector gets a turn, as it may have + // displayed the mini keyboard + if (mMiniKeyboard != null) { + final int miniKeyboardPointerIndex = me.findPointerIndex(mMiniKeyboardTrackerId); + if (miniKeyboardPointerIndex >= 0 && miniKeyboardPointerIndex < pointerCount) { + final int miniKeyboardX = (int)me.getX(miniKeyboardPointerIndex); + final int miniKeyboardY = (int)me.getY(miniKeyboardPointerIndex); + MotionEvent translated = generateMiniKeyboardMotionEvent(action, + miniKeyboardX, miniKeyboardY, eventTime); + mMiniKeyboard.onTouchEvent(translated); + translated.recycle(); + } + return true; + } + + if (mHandler.isInKeyRepeat()) { + // It will keep being in the key repeating mode while the key is being pressed. + if (action == MotionEvent.ACTION_MOVE) { + return true; + } + final PointerTracker tracker = getPointerTracker(id); + // Key repeating timer will be canceled if 2 or more keys are in action, and current + // event (UP or DOWN) is non-modifier key. + if (pointerCount > 1 && !tracker.isModifier()) { + mHandler.cancelKeyRepeatTimer(); + } + // Up event will pass through. + } + + // TODO: cleanup this code into a multi-touch to single-touch event converter class? + // Translate mutli-touch event to single-touch events on the device that has no distinct + // multi-touch panel. + if (!mHasDistinctMultitouch) { + // Use only main (id=0) pointer tracker. + PointerTracker tracker = getPointerTracker(0); + if (pointerCount == 1 && oldPointerCount == 2) { + // Multi-touch to single touch transition. + // Send a down event for the latest pointer. + tracker.onDownEvent(x, y, eventTime); + } else if (pointerCount == 2 && oldPointerCount == 1) { + // Single-touch to multi-touch transition. + // Send an up event for the last pointer. + tracker.onUpEvent(tracker.getLastX(), tracker.getLastY(), eventTime); + } else if (pointerCount == 1 && oldPointerCount == 1) { + tracker.onTouchEvent(action, x, y, eventTime); + } else { + Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount + + " (old " + oldPointerCount + ")"); + } + return true; + } + + if (action == MotionEvent.ACTION_MOVE) { + for (int i = 0; i < pointerCount; i++) { + PointerTracker tracker = getPointerTracker(me.getPointerId(i)); + tracker.onMoveEvent((int)me.getX(i), (int)me.getY(i), eventTime); + } + } else { + PointerTracker tracker = getPointerTracker(id); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + onDownEvent(tracker, x, y, eventTime); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + onUpEvent(tracker, x, y, eventTime); + break; + case MotionEvent.ACTION_CANCEL: + onCancelEvent(tracker, x, y, eventTime); + break; + } + } + + return true; + } + + private void onDownEvent(PointerTracker tracker, int x, int y, long eventTime) { + if (tracker.isOnModifierKey(x, y)) { + // Before processing a down event of modifier key, all pointers already being tracked + // should be released. + mPointerQueue.releaseAllPointersExcept(null, eventTime); + } + tracker.onDownEvent(x, y, eventTime); + mPointerQueue.add(tracker); + } + + private void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) { + if (tracker.isModifier()) { + // Before processing an up event of modifier key, all pointers already being tracked + // should be released. + mPointerQueue.releaseAllPointersExcept(tracker, eventTime); + } else { + int index = mPointerQueue.lastIndexOf(tracker); + if (index >= 0) { + mPointerQueue.releaseAllPointersOlderThan(tracker, eventTime); + } else { + Log.w(TAG, "onUpEvent: corresponding down event not found for pointer " + + tracker.mPointerId); + } + } + tracker.onUpEvent(x, y, eventTime); + mPointerQueue.remove(tracker); + } + + private void onCancelEvent(PointerTracker tracker, int x, int y, long eventTime) { + tracker.onCancelEvent(x, y, eventTime); + mPointerQueue.remove(tracker); + } + + protected void swipeRight() { + mKeyboardActionListener.swipeRight(); + } + + protected void swipeLeft() { + mKeyboardActionListener.swipeLeft(); + } + + protected void swipeUp() { + mKeyboardActionListener.swipeUp(); + } + + protected void swipeDown() { + mKeyboardActionListener.swipeDown(); + } + + public void closing() { + mPreviewPopup.dismiss(); + mHandler.cancelAllMessages(); + + dismissPopupKeyboard(); + mBuffer = null; + mCanvas = null; + mMiniKeyboardCache.clear(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + closing(); + } + + private void dismissPopupKeyboard() { + if (mMiniKeyboardPopup.isShowing()) { + mMiniKeyboardPopup.dismiss(); + mMiniKeyboard = null; + mMiniKeyboardOriginX = 0; + mMiniKeyboardOriginY = 0; + invalidateAllKeys(); + } + } + + public boolean handleBack() { + if (mMiniKeyboardPopup.isShowing()) { + dismissPopupKeyboard(); + return true; + } + return false; + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboardView.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboardView.java new file mode 100644 index 00000000..ac7b0bef --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/LatinKeyboardView.java @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import java.util.List; + +public class LatinKeyboardView extends LatinKeyboardBaseView { + + static final int KEYCODE_OPTIONS = -100; + static final int KEYCODE_OPTIONS_LONGPRESS = -101; + static final int KEYCODE_F1 = -103; + static final int KEYCODE_NEXT_LANGUAGE = -104; + static final int KEYCODE_PREV_LANGUAGE = -105; + static final int KEYCODE_KP2A = -200; + + private Keyboard mPhoneKeyboard; + + /** Whether we've started dropping move events because we found a big jump */ + private boolean mDroppingEvents; + /** + * Whether multi-touch disambiguation needs to be disabled if a real multi-touch event has + * occured + */ + private boolean mDisableDisambiguation; + /** The distance threshold at which we start treating the touch session as a multi-touch */ + private int mJumpThresholdSquare = Integer.MAX_VALUE; + /** The y coordinate of the last row */ + private int mLastRowY; + + public LatinKeyboardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setPhoneKeyboard(Keyboard phoneKeyboard) { + mPhoneKeyboard = phoneKeyboard; + } + + @Override + public void setPreviewEnabled(boolean previewEnabled) { + if (getKeyboard() == mPhoneKeyboard) { + // Phone keyboard never shows popup preview (except language switch). + super.setPreviewEnabled(false); + } else { + super.setPreviewEnabled(previewEnabled); + } + } + + @Override + public void setKeyboard(Keyboard newKeyboard) { + final Keyboard oldKeyboard = getKeyboard(); + if (oldKeyboard instanceof LatinKeyboard) { + // Reset old keyboard state before switching to new keyboard. + ((LatinKeyboard)oldKeyboard).keyReleased(); + } + super.setKeyboard(newKeyboard); + // One-seventh of the keyboard width seems like a reasonable threshold + mJumpThresholdSquare = newKeyboard.getMinWidth() / 7; + mJumpThresholdSquare *= mJumpThresholdSquare; + // Assuming there are 4 rows, this is the coordinate of the last row + mLastRowY = (newKeyboard.getHeight() * 3) / 4; + setKeyboardLocal(newKeyboard); + } + + @Override + protected boolean onLongPress(Key key) { + int primaryCode = key.codes[0]; + if (primaryCode == KEYCODE_OPTIONS) { + return invokeOnKey(KEYCODE_OPTIONS_LONGPRESS); + } else if (primaryCode == '0' && getKeyboard() == mPhoneKeyboard) { + // Long pressing on 0 in phone number keypad gives you a '+'. + return invokeOnKey('+'); + } else { + return super.onLongPress(key); + } + } + + private boolean invokeOnKey(int primaryCode) { + getOnKeyboardActionListener().onKey(primaryCode, null, + LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, + LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); + return true; + } + + @Override + protected CharSequence adjustCase(CharSequence label) { + Keyboard keyboard = getKeyboard(); + if (keyboard.isShifted() + && keyboard instanceof LatinKeyboard + && ((LatinKeyboard) keyboard).isAlphaKeyboard() + && !TextUtils.isEmpty(label) && label.length() < 3 + && Character.isLowerCase(label.charAt(0))) { + return label.toString().toUpperCase(getKeyboardLocale()); + } + return label; + } + + public boolean setShiftLocked(boolean shiftLocked) { + Keyboard keyboard = getKeyboard(); + if (keyboard instanceof LatinKeyboard) { + ((LatinKeyboard)keyboard).setShiftLocked(shiftLocked); + invalidateAllKeys(); + return true; + } + return false; + } + + /** + * This function checks to see if we need to handle any sudden jumps in the pointer location + * that could be due to a multi-touch being treated as a move by the firmware or hardware. + * Once a sudden jump is detected, all subsequent move events are discarded + * until an UP is received.

+ * When a sudden jump is detected, an UP event is simulated at the last position and when + * the sudden moves subside, a DOWN event is simulated for the second key. + * @param me the motion event + * @return true if the event was consumed, so that it doesn't continue to be handled by + * KeyboardView. + */ + private boolean handleSuddenJump(MotionEvent me) { + final int action = me.getAction(); + final int x = (int) me.getX(); + final int y = (int) me.getY(); + boolean result = false; + + // Real multi-touch event? Stop looking for sudden jumps + if (me.getPointerCount() > 1) { + mDisableDisambiguation = true; + } + if (mDisableDisambiguation) { + // If UP, reset the multi-touch flag + if (action == MotionEvent.ACTION_UP) mDisableDisambiguation = false; + return false; + } + + switch (action) { + case MotionEvent.ACTION_DOWN: + // Reset the "session" + mDroppingEvents = false; + mDisableDisambiguation = false; + break; + case MotionEvent.ACTION_MOVE: + // Is this a big jump? + final int distanceSquare = (mLastX - x) * (mLastX - x) + (mLastY - y) * (mLastY - y); + // Check the distance and also if the move is not entirely within the bottom row + // If it's only in the bottom row, it might be an intentional slide gesture + // for language switching + if (distanceSquare > mJumpThresholdSquare + && (mLastY < mLastRowY || y < mLastRowY)) { + // If we're not yet dropping events, start dropping and send an UP event + if (!mDroppingEvents) { + mDroppingEvents = true; + // Send an up event + MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), + MotionEvent.ACTION_UP, + mLastX, mLastY, me.getMetaState()); + super.onTouchEvent(translated); + translated.recycle(); + } + result = true; + } else if (mDroppingEvents) { + // If moves are small and we're already dropping events, continue dropping + result = true; + } + break; + case MotionEvent.ACTION_UP: + if (mDroppingEvents) { + // Send a down event first, as we dropped a bunch of sudden jumps and assume that + // the user is releasing the touch on the second key. + MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), + MotionEvent.ACTION_DOWN, + x, y, me.getMetaState()); + super.onTouchEvent(translated); + translated.recycle(); + mDroppingEvents = false; + // Let the up event get processed as well, result = false + } + break; + } + // Track the previous coordinate + mLastX = x; + mLastY = y; + return result; + } + + @Override + public boolean onTouchEvent(MotionEvent me) { + LatinKeyboard keyboard = (LatinKeyboard) getKeyboard(); + if (DEBUG_LINE) { + mLastX = (int) me.getX(); + mLastY = (int) me.getY(); + invalidate(); + } + + // If there was a sudden jump, return without processing the actual motion event. + if (handleSuddenJump(me)) + return true; + + // Reset any bounding box controls in the keyboard + if (me.getAction() == MotionEvent.ACTION_DOWN) { + keyboard.keyReleased(); + } + + if (me.getAction() == MotionEvent.ACTION_UP) { + int languageDirection = keyboard.getLanguageChangeDirection(); + if (languageDirection != 0) { + getOnKeyboardActionListener().onKey( + languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE, + null, mLastX, mLastY); + me.setAction(MotionEvent.ACTION_CANCEL); + keyboard.keyReleased(); + return super.onTouchEvent(me); + } + } + + return super.onTouchEvent(me); + } + + /**************************** INSTRUMENTATION *******************************/ + + static final boolean DEBUG_AUTO_PLAY = false; + static final boolean DEBUG_LINE = false; + private static final int MSG_TOUCH_DOWN = 1; + private static final int MSG_TOUCH_UP = 2; + + Handler mHandler2; + + private String mStringToPlay; + private int mStringIndex; + private boolean mDownDelivered; + private Key[] mAsciiKeys = new Key[256]; + private boolean mPlaying; + private int mLastX; + private int mLastY; + private Paint mPaint; + + private void setKeyboardLocal(Keyboard k) { + if (DEBUG_AUTO_PLAY) { + findKeys(); + if (mHandler2 == null) { + mHandler2 = new Handler() { + @Override + public void handleMessage(Message msg) { + removeMessages(MSG_TOUCH_DOWN); + removeMessages(MSG_TOUCH_UP); + if (mPlaying == false) return; + + switch (msg.what) { + case MSG_TOUCH_DOWN: + if (mStringIndex >= mStringToPlay.length()) { + mPlaying = false; + return; + } + char c = mStringToPlay.charAt(mStringIndex); + while (c > 255 || mAsciiKeys[c] == null) { + mStringIndex++; + if (mStringIndex >= mStringToPlay.length()) { + mPlaying = false; + return; + } + c = mStringToPlay.charAt(mStringIndex); + } + int x = mAsciiKeys[c].x + 10; + int y = mAsciiKeys[c].y + 26; + MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), + SystemClock.uptimeMillis(), + MotionEvent.ACTION_DOWN, x, y, 0); + LatinKeyboardView.this.dispatchTouchEvent(me); + me.recycle(); + sendEmptyMessageDelayed(MSG_TOUCH_UP, 500); // Deliver up in 500ms if nothing else + // happens + mDownDelivered = true; + break; + case MSG_TOUCH_UP: + char cUp = mStringToPlay.charAt(mStringIndex); + int x2 = mAsciiKeys[cUp].x + 10; + int y2 = mAsciiKeys[cUp].y + 26; + mStringIndex++; + + MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(), + SystemClock.uptimeMillis(), + MotionEvent.ACTION_UP, x2, y2, 0); + LatinKeyboardView.this.dispatchTouchEvent(me2); + me2.recycle(); + sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 500); // Deliver up in 500ms if nothing else + // happens + mDownDelivered = false; + break; + } + } + }; + + } + } + } + + private void findKeys() { + List keys = getKeyboard().getKeys(); + // Get the keys on this keyboard + for (int i = 0; i < keys.size(); i++) { + int code = keys.get(i).codes[0]; + if (code >= 0 && code <= 255) { + mAsciiKeys[code] = keys.get(i); + } + } + } + + public void startPlaying(String s) { + if (DEBUG_AUTO_PLAY) { + if (s == null) return; + mStringToPlay = s.toLowerCase(); + mPlaying = true; + mDownDelivered = false; + mStringIndex = 0; + mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 10); + } + } + + @Override + public void draw(Canvas c) { + LatinIMEUtil.GCUtils.getInstance().reset(); + boolean tryGC = true; + for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { + try { + super.draw(c); + tryGC = false; + } catch (OutOfMemoryError e) { + tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait("LatinKeyboardView", e); + } + } + if (DEBUG_AUTO_PLAY) { + if (mPlaying) { + mHandler2.removeMessages(MSG_TOUCH_DOWN); + mHandler2.removeMessages(MSG_TOUCH_UP); + if (mDownDelivered) { + mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_UP, 20); + } else { + mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 20); + } + } + } + if (DEBUG_LINE) { + if (mPaint == null) { + mPaint = new Paint(); + mPaint.setColor(0x80FFFFFF); + mPaint.setAntiAlias(false); + } + c.drawLine(mLastX, 0, mLastX, getHeight(), mPaint); + c.drawLine(0, mLastY, getWidth(), mLastY, mPaint); + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/MiniKeyboardKeyDetector.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/MiniKeyboardKeyDetector.java new file mode 100644 index 00000000..00ee995b --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/MiniKeyboardKeyDetector.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.inputmethodservice.Keyboard.Key; + +class MiniKeyboardKeyDetector extends KeyDetector { + private static final int MAX_NEARBY_KEYS = 1; + + private final int mSlideAllowanceSquare; + private final int mSlideAllowanceSquareTop; + + public MiniKeyboardKeyDetector(float slideAllowance) { + super(); + mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance); + // Top slide allowance is slightly longer (sqrt(2) times) than other edges. + mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2; + } + + @Override + protected int getMaxNearbyKeys() { + return MAX_NEARBY_KEYS; + } + + @Override + public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) { + final Key[] keys = getKeys(); + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); + int closestKeyIndex = LatinKeyboardBaseView.NOT_A_KEY; + int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; + final int keyCount = keys.length; + for (int i = 0; i < keyCount; i++) { + final Key key = keys[i]; + int dist = key.squaredDistanceFrom(touchX, touchY); + if (dist < closestKeyDist) { + closestKeyIndex = i; + closestKeyDist = dist; + } + } + if (allKeys != null && closestKeyIndex != LatinKeyboardBaseView.NOT_A_KEY) + allKeys[0] = keys[closestKeyIndex].codes[0]; + return closestKeyIndex; + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ModifierKeyState.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ModifierKeyState.java new file mode 100644 index 00000000..5da00d2e --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ModifierKeyState.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +class ModifierKeyState { + private static final int RELEASING = 0; + private static final int PRESSING = 1; + private static final int MOMENTARY = 2; + + private int mState = RELEASING; + + public void onPress() { + mState = PRESSING; + } + + public void onRelease() { + mState = RELEASING; + } + + public void onOtherKeyPressed() { + if (mState == PRESSING) + mState = MOMENTARY; + } + + public boolean isMomentary() { + return mState == MOMENTARY; + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/PointerTracker.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/PointerTracker.java new file mode 100644 index 00000000..54ca0c2e --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/PointerTracker.java @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import keepass2android.softkeyboard.LatinKeyboardBaseView.OnKeyboardActionListener; +import keepass2android.softkeyboard.LatinKeyboardBaseView.UIHandler; + +import android.content.res.Resources; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; +import android.util.Log; +import android.view.MotionEvent; + +public class PointerTracker { + private static final String TAG = "PointerTracker"; + private static final boolean DEBUG = false; + private static final boolean DEBUG_MOVE = false; + + public interface UIProxy { + public void invalidateKey(Key key); + public void showPreview(int keyIndex, PointerTracker tracker); + public boolean hasDistinctMultitouch(); + } + + public final int mPointerId; + + // Timing constants + private final int mDelayBeforeKeyRepeatStart; + private final int mLongPressKeyTimeout; + private final int mMultiTapKeyTimeout; + + // Miscellaneous constants + private static final int NOT_A_KEY = LatinKeyboardBaseView.NOT_A_KEY; + private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; + + private final UIProxy mProxy; + private final UIHandler mHandler; + private final KeyDetector mKeyDetector; + private OnKeyboardActionListener mListener; + private final KeyboardSwitcher mKeyboardSwitcher; + private final boolean mHasDistinctMultitouch; + + private Key[] mKeys; + private int mKeyHysteresisDistanceSquared = -1; + + private final KeyState mKeyState; + + // true if keyboard layout has been changed. + private boolean mKeyboardLayoutHasBeenChanged; + + // true if event is already translated to a key action (long press or mini-keyboard) + private boolean mKeyAlreadyProcessed; + + // true if this pointer is repeatable key + private boolean mIsRepeatableKey; + + // true if this pointer is in sliding key input + private boolean mIsInSlidingKeyInput; + + // For multi-tap + private int mLastSentIndex; + private int mTapCount; + private long mLastTapTime; + private boolean mInMultiTap; + private final StringBuilder mPreviewLabel = new StringBuilder(1); + + // pressed key + private int mPreviousKey = NOT_A_KEY; + + // This class keeps track of a key index and a position where this pointer is. + private static class KeyState { + private final KeyDetector mKeyDetector; + + // The position and time at which first down event occurred. + private int mStartX; + private int mStartY; + private long mDownTime; + + // The current key index where this pointer is. + private int mKeyIndex = NOT_A_KEY; + // The position where mKeyIndex was recognized for the first time. + private int mKeyX; + private int mKeyY; + + // Last pointer position. + private int mLastX; + private int mLastY; + + public KeyState(KeyDetector keyDetecor) { + mKeyDetector = keyDetecor; + } + + public int getKeyIndex() { + return mKeyIndex; + } + + public int getKeyX() { + return mKeyX; + } + + public int getKeyY() { + return mKeyY; + } + + public int getStartX() { + return mStartX; + } + + public int getStartY() { + return mStartY; + } + + public long getDownTime() { + return mDownTime; + } + + public int getLastX() { + return mLastX; + } + + public int getLastY() { + return mLastY; + } + + public int onDownKey(int x, int y, long eventTime) { + mStartX = x; + mStartY = y; + mDownTime = eventTime; + + return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); + } + + private int onMoveKeyInternal(int x, int y) { + mLastX = x; + mLastY = y; + return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + } + + public int onMoveKey(int x, int y) { + return onMoveKeyInternal(x, y); + } + + public int onMoveToNewKey(int keyIndex, int x, int y) { + mKeyIndex = keyIndex; + mKeyX = x; + mKeyY = y; + return keyIndex; + } + + public int onUpKey(int x, int y) { + return onMoveKeyInternal(x, y); + } + } + + public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, UIProxy proxy, + Resources res) { + if (proxy == null || handler == null || keyDetector == null) + throw new NullPointerException(); + mPointerId = id; + mProxy = proxy; + mHandler = handler; + mKeyDetector = keyDetector; + mKeyboardSwitcher = KeyboardSwitcher.getInstance(); + mKeyState = new KeyState(keyDetector); + mHasDistinctMultitouch = proxy.hasDistinctMultitouch(); + mDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start); + mLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout); + mMultiTapKeyTimeout = res.getInteger(R.integer.config_multi_tap_key_timeout); + resetMultiTap(); + } + + public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { + mListener = listener; + } + + public void setKeyboard(Key[] keys, float keyHysteresisDistance) { + if (keys == null || keyHysteresisDistance < 0) + throw new IllegalArgumentException(); + mKeys = keys; + mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); + // Mark that keyboard layout has been changed. + mKeyboardLayoutHasBeenChanged = true; + } + + public boolean isInSlidingKeyInput() { + return mIsInSlidingKeyInput; + } + + private boolean isValidKeyIndex(int keyIndex) { + return keyIndex >= 0 && keyIndex < mKeys.length; + } + + public Key getKey(int keyIndex) { + return isValidKeyIndex(keyIndex) ? mKeys[keyIndex] : null; + } + + private boolean isModifierInternal(int keyIndex) { + Key key = getKey(keyIndex); + if (key == null) + return false; + int primaryCode = key.codes[0]; + return primaryCode == Keyboard.KEYCODE_SHIFT + || primaryCode == Keyboard.KEYCODE_MODE_CHANGE; + } + + public boolean isModifier() { + return isModifierInternal(mKeyState.getKeyIndex()); + } + + public boolean isOnModifierKey(int x, int y) { + return isModifierInternal(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); + } + + public boolean isSpaceKey(int keyIndex) { + Key key = getKey(keyIndex); + return key != null && key.codes[0] == KP2AKeyboard.KEYCODE_SPACE; + } + + public void updateKey(int keyIndex) { + if (mKeyAlreadyProcessed) + return; + int oldKeyIndex = mPreviousKey; + mPreviousKey = keyIndex; + if (keyIndex != oldKeyIndex) { + if (isValidKeyIndex(oldKeyIndex)) { + // if new key index is not a key, old key was just released inside of the key. + final boolean inside = (keyIndex == NOT_A_KEY); + mKeys[oldKeyIndex].onReleased(inside); + mProxy.invalidateKey(mKeys[oldKeyIndex]); + } + if (isValidKeyIndex(keyIndex)) { + mKeys[keyIndex].onPressed(); + mProxy.invalidateKey(mKeys[keyIndex]); + } + } + } + + public void setAlreadyProcessed() { + mKeyAlreadyProcessed = true; + } + + public void onTouchEvent(int action, int x, int y, long eventTime) { + switch (action) { + case MotionEvent.ACTION_MOVE: + onMoveEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + onDownEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + onUpEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_CANCEL: + onCancelEvent(x, y, eventTime); + break; + } + } + + public void onDownEvent(int x, int y, long eventTime) { + if (DEBUG) + debugLog("onDownEvent:", x, y); + int keyIndex = mKeyState.onDownKey(x, y, eventTime); + mKeyboardLayoutHasBeenChanged = false; + mKeyAlreadyProcessed = false; + mIsRepeatableKey = false; + mIsInSlidingKeyInput = false; + checkMultiTap(eventTime, keyIndex); + if (mListener != null) { + if (isValidKeyIndex(keyIndex)) { + mListener.onPress(mKeys[keyIndex].codes[0]); + // This onPress call may have changed keyboard layout. Those cases are detected at + // {@link #setKeyboard}. In those cases, we should update keyIndex according to the + // new keyboard layout. + if (mKeyboardLayoutHasBeenChanged) { + mKeyboardLayoutHasBeenChanged = false; + keyIndex = mKeyState.onDownKey(x, y, eventTime); + } + } + } + if (isValidKeyIndex(keyIndex)) { + if (mKeys[keyIndex].repeatable) { + repeatKey(keyIndex); + mHandler.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this); + mIsRepeatableKey = true; + } + startLongPressTimer(keyIndex); + } + showKeyPreviewAndUpdateKey(keyIndex); + } + + public void onMoveEvent(int x, int y, long eventTime) { + if (DEBUG_MOVE) + debugLog("onMoveEvent:", x, y); + if (mKeyAlreadyProcessed) + return; + final KeyState keyState = mKeyState; + int keyIndex = keyState.onMoveKey(x, y); + final Key oldKey = getKey(keyState.getKeyIndex()); + if (isValidKeyIndex(keyIndex)) { + if (oldKey == null) { + // The pointer has been slid in to the new key, but the finger was not on any keys. + // In this case, we must call onPress() to notify that the new key is being pressed. + if (mListener != null) { + mListener.onPress(getKey(keyIndex).codes[0]); + // This onPress call may have changed keyboard layout. Those cases are detected + // at {@link #setKeyboard}. In those cases, we should update keyIndex according + // to the new keyboard layout. + if (mKeyboardLayoutHasBeenChanged) { + mKeyboardLayoutHasBeenChanged = false; + keyIndex = keyState.onMoveKey(x, y); + } + } + keyState.onMoveToNewKey(keyIndex, x, y); + startLongPressTimer(keyIndex); + } else if (!isMinorMoveBounce(x, y, keyIndex)) { + // The pointer has been slid in to the new key from the previous key, we must call + // onRelease() first to notify that the previous key has been released, then call + // onPress() to notify that the new key is being pressed. + mIsInSlidingKeyInput = true; + if (mListener != null) + mListener.onRelease(oldKey.codes[0]); + resetMultiTap(); + if (mListener != null) { + mListener.onPress(getKey(keyIndex).codes[0]); + // This onPress call may have changed keyboard layout. Those cases are detected + // at {@link #setKeyboard}. In those cases, we should update keyIndex according + // to the new keyboard layout. + if (mKeyboardLayoutHasBeenChanged) { + mKeyboardLayoutHasBeenChanged = false; + keyIndex = keyState.onMoveKey(x, y); + } + } + keyState.onMoveToNewKey(keyIndex, x, y); + startLongPressTimer(keyIndex); + } + } else { + if (oldKey != null && !isMinorMoveBounce(x, y, keyIndex)) { + // The pointer has been slid out from the previous key, we must call onRelease() to + // notify that the previous key has been released. + mIsInSlidingKeyInput = true; + if (mListener != null) + mListener.onRelease(oldKey.codes[0]); + resetMultiTap(); + keyState.onMoveToNewKey(keyIndex, x ,y); + mHandler.cancelLongPressTimer(); + } + } + showKeyPreviewAndUpdateKey(keyState.getKeyIndex()); + } + + public void onUpEvent(int x, int y, long eventTime) { + if (DEBUG) + debugLog("onUpEvent :", x, y); + mHandler.cancelKeyTimers(); + mHandler.cancelPopupPreview(); + showKeyPreviewAndUpdateKey(NOT_A_KEY); + mIsInSlidingKeyInput = false; + if (mKeyAlreadyProcessed) + return; + int keyIndex = mKeyState.onUpKey(x, y); + if (isMinorMoveBounce(x, y, keyIndex)) { + // Use previous fixed key index and coordinates. + keyIndex = mKeyState.getKeyIndex(); + x = mKeyState.getKeyX(); + y = mKeyState.getKeyY(); + } + if (!mIsRepeatableKey) { + detectAndSendKey(keyIndex, x, y, eventTime); + } + + if (isValidKeyIndex(keyIndex)) + mProxy.invalidateKey(mKeys[keyIndex]); + } + + public void onCancelEvent(int x, int y, long eventTime) { + if (DEBUG) + debugLog("onCancelEvt:", x, y); + mHandler.cancelKeyTimers(); + mHandler.cancelPopupPreview(); + showKeyPreviewAndUpdateKey(NOT_A_KEY); + mIsInSlidingKeyInput = false; + int keyIndex = mKeyState.getKeyIndex(); + if (isValidKeyIndex(keyIndex)) + mProxy.invalidateKey(mKeys[keyIndex]); + } + + public void repeatKey(int keyIndex) { + Key key = getKey(keyIndex); + if (key != null) { + // While key is repeating, because there is no need to handle multi-tap key, we can + // pass -1 as eventTime argument. + detectAndSendKey(keyIndex, key.x, key.y, -1); + } + } + + public int getLastX() { + return mKeyState.getLastX(); + } + + public int getLastY() { + return mKeyState.getLastY(); + } + + public long getDownTime() { + return mKeyState.getDownTime(); + } + + // These package scope methods are only for debugging purpose. + /* package */ int getStartX() { + return mKeyState.getStartX(); + } + + /* package */ int getStartY() { + return mKeyState.getStartY(); + } + + private boolean isMinorMoveBounce(int x, int y, int newKey) { + if (mKeys == null || mKeyHysteresisDistanceSquared < 0) + throw new IllegalStateException("keyboard and/or hysteresis not set"); + int curKey = mKeyState.getKeyIndex(); + if (newKey == curKey) { + return true; + } else if (isValidKeyIndex(curKey)) { + return getSquareDistanceToKeyEdge(x, y, mKeys[curKey]) < mKeyHysteresisDistanceSquared; + } else { + return false; + } + } + + private static int getSquareDistanceToKeyEdge(int x, int y, Key key) { + final int left = key.x; + final int right = key.x + key.width; + final int top = key.y; + final int bottom = key.y + key.height; + final int edgeX = x < left ? left : (x > right ? right : x); + final int edgeY = y < top ? top : (y > bottom ? bottom : y); + final int dx = x - edgeX; + final int dy = y - edgeY; + return dx * dx + dy * dy; + } + + private void showKeyPreviewAndUpdateKey(int keyIndex) { + updateKey(keyIndex); + // The modifier key, such as shift key, should not be shown as preview when multi-touch is + // supported. On the other hand, if multi-touch is not supported, the modifier key should + // be shown as preview. + if (mHasDistinctMultitouch && isModifier()) { + mProxy.showPreview(NOT_A_KEY, this); + } else { + mProxy.showPreview(keyIndex, this); + } + } + + private void startLongPressTimer(int keyIndex) { + if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) { + // We use longer timeout for sliding finger input started from the symbols mode key. + mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); + } else { + mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this); + } + } + + private void detectAndSendKey(int index, int x, int y, long eventTime) { + final OnKeyboardActionListener listener = mListener; + final Key key = getKey(index); + + if (key == null) { + if (listener != null) + listener.onCancel(); + } else { + if (key.text != null) { + if (listener != null) { + listener.onText(key.text); + listener.onRelease(0); // dummy key code + } + } else { + int code = key.codes[0]; + int[] codes = mKeyDetector.newCodeArray(); + mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); + // Multi-tap + if (mInMultiTap) { + if (mTapCount != -1) { + mListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y); + } else { + mTapCount = 0; + } + code = key.codes[mTapCount]; + } + /* + * Swap the first and second values in the codes array if the primary code is not + * the first value but the second value in the array. This happens when key + * debouncing is in effect. + */ + if (codes.length >= 2 && codes[0] != code && codes[1] == code) { + codes[1] = codes[0]; + codes[0] = code; + } + if (listener != null) { + listener.onKey(code, codes, x, y); + listener.onRelease(code); + } + } + mLastSentIndex = index; + mLastTapTime = eventTime; + } + } + + /** + * Handle multi-tap keys by producing the key label for the current multi-tap state. + */ + public CharSequence getPreviewText(Key key) { + if (mInMultiTap) { + // Multi-tap + mPreviewLabel.setLength(0); + mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); + return mPreviewLabel; + } else { + return key.label; + } + } + + private void resetMultiTap() { + mLastSentIndex = NOT_A_KEY; + mTapCount = 0; + mLastTapTime = -1; + mInMultiTap = false; + } + + private void checkMultiTap(long eventTime, int keyIndex) { + Key key = getKey(keyIndex); + if (key == null) + return; + + final boolean isMultiTap = + (eventTime < mLastTapTime + mMultiTapKeyTimeout && keyIndex == mLastSentIndex); + if (key.codes.length > 1) { + mInMultiTap = true; + if (isMultiTap) { + mTapCount = (mTapCount + 1) % key.codes.length; + return; + } else { + mTapCount = -1; + return; + } + } + if (!isMultiTap) { + resetMultiTap(); + } + } + + private void debugLog(String title, int x, int y) { + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + Key key = getKey(keyIndex); + final String code; + if (key == null) { + code = "----"; + } else { + int primaryCode = key.codes[0]; + code = String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode); + } + Log.d(TAG, String.format("%s%s[%d] %3d,%3d %3d(%s) %s", title, + (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, keyIndex, code, + (isModifier() ? "modifier" : ""))); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ProximityKeyDetector.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ProximityKeyDetector.java new file mode 100644 index 00000000..5c20c798 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/ProximityKeyDetector.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.inputmethodservice.Keyboard.Key; + +import java.util.Arrays; + +class ProximityKeyDetector extends KeyDetector { + private static final int MAX_NEARBY_KEYS = 12; + + // working area + private int[] mDistances = new int[MAX_NEARBY_KEYS]; + + @Override + protected int getMaxNearbyKeys() { + return MAX_NEARBY_KEYS; + } + + @Override + public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) { + final Key[] keys = getKeys(); + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); + int primaryIndex = LatinKeyboardBaseView.NOT_A_KEY; + int closestKey = LatinKeyboardBaseView.NOT_A_KEY; + int closestKeyDist = mProximityThresholdSquare + 1; + int[] distances = mDistances; + Arrays.fill(distances, Integer.MAX_VALUE); + int [] nearestKeyIndices = mKeyboard.getNearestKeys(touchX, touchY); + final int keyCount = nearestKeyIndices.length; + for (int i = 0; i < keyCount; i++) { + final Key key = keys[nearestKeyIndices[i]]; + int dist = 0; + boolean isInside = key.isInside(touchX, touchY); + if (isInside) { + primaryIndex = nearestKeyIndices[i]; + } + + if (((mProximityCorrectOn + && (dist = key.squaredDistanceFrom(touchX, touchY)) < mProximityThresholdSquare) + || isInside) + && key.codes[0] > 32) { + // Find insertion point + final int nCodes = key.codes.length; + if (dist < closestKeyDist) { + closestKeyDist = dist; + closestKey = nearestKeyIndices[i]; + } + + if (allKeys == null) continue; + + for (int j = 0; j < distances.length; j++) { + if (distances[j] > dist) { + // Make space for nCodes codes + System.arraycopy(distances, j, distances, j + nCodes, + distances.length - j - nCodes); + System.arraycopy(allKeys, j, allKeys, j + nCodes, + allKeys.length - j - nCodes); + System.arraycopy(key.codes, 0, allKeys, j, nCodes); + Arrays.fill(distances, j, j + nCodes, dist); + break; + } + } + } + } + if (primaryIndex == LatinKeyboardBaseView.NOT_A_KEY) { + primaryIndex = closestKey; + } + return primaryIndex; + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/SharedPreferencesCompat.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/SharedPreferencesCompat.java new file mode 100644 index 00000000..ee7e65ab --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/SharedPreferencesCompat.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import android.content.SharedPreferences; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Reflection utils to call SharedPreferences$Editor.apply when possible, + * falling back to commit when apply isn't available. + */ +public class SharedPreferencesCompat { + private static final Method sApplyMethod = findApplyMethod(); + + private static Method findApplyMethod() { + try { + return SharedPreferences.Editor.class.getMethod("apply"); + } catch (NoSuchMethodException unused) { + // fall through + } + return null; + } + + public static void apply(SharedPreferences.Editor editor) { + if (sApplyMethod != null) { + try { + sApplyMethod.invoke(editor); + return; + } catch (InvocationTargetException unused) { + // fall through + } catch (IllegalAccessException unused) { + // fall through + } + } + editor.commit(); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Suggest.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Suggest.java new file mode 100644 index 00000000..48fece90 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/Suggest.java @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.Context; +import android.text.AutoText; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * This class loads a dictionary and provides a list of suggestions for a given sequence of + * characters. This includes corrections and completions. + * @hide pending API Council Approval + */ +public class Suggest implements Dictionary.WordCallback { + + public static final int APPROX_MAX_WORD_LENGTH = 32; + + public static final int CORRECTION_NONE = 0; + public static final int CORRECTION_BASIC = 1; + public static final int CORRECTION_FULL = 2; + public static final int CORRECTION_FULL_BIGRAM = 3; + + /** + * Words that appear in both bigram and unigram data gets multiplier ranging from + * BIGRAM_MULTIPLIER_MIN to BIGRAM_MULTIPLIER_MAX depending on the frequency score from + * bigram data. + */ + public static final double BIGRAM_MULTIPLIER_MIN = 1.2; + public static final double BIGRAM_MULTIPLIER_MAX = 1.5; + + /** + * Maximum possible bigram frequency. Will depend on how many bits are being used in data + * structure. Maximum bigram freqeuncy will get the BIGRAM_MULTIPLIER_MAX as the multiplier. + */ + public static final int MAXIMUM_BIGRAM_FREQUENCY = 127; + + public static final int DIC_USER_TYPED = 0; + public static final int DIC_MAIN = 1; + public static final int DIC_USER = 2; + public static final int DIC_AUTO = 3; + public static final int DIC_CONTACTS = 4; + // If you add a type of dictionary, increment DIC_TYPE_LAST_ID + public static final int DIC_TYPE_LAST_ID = 4; + + static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000; + + private BinaryDictionary mMainDict; +/* + private Dictionary mUserDictionary; + + private Dictionary mAutoDictionary; + + private Dictionary mContactsDictionary; + + private Dictionary mUserBigramDictionary; +*/ + private int mPrefMaxSuggestions = 12; + + private static final int PREF_MAX_BIGRAMS = 60; + + private boolean mAutoTextEnabled; + + private int[] mPriorities = new int[mPrefMaxSuggestions]; + private int[] mBigramPriorities = new int[PREF_MAX_BIGRAMS]; + + // Handle predictive correction for only the first 1280 characters for performance reasons + // If we support scripts that need latin characters beyond that, we should probably use some + // kind of a sparse array or language specific list with a mapping lookup table. + // 1280 is the size of the BASE_CHARS array in ExpandableDictionary, which is a basic set of + // latin characters. + private int[] mNextLettersFrequencies = new int[1280]; + private ArrayList mSuggestions = new ArrayList(); + ArrayList mBigramSuggestions = new ArrayList(); + private ArrayList mStringPool = new ArrayList(); + private boolean mHaveCorrection; + private CharSequence mOriginalWord; + private String mLowerOriginalWord; + + // TODO: Remove these member variables by passing more context to addWord() callback method + private boolean mIsFirstCharCapitalized; + private boolean mIsAllUpperCase; + + private int mCorrectionMode = CORRECTION_BASIC; + + public Suggest(Context context, int[] dictionaryResId) { + mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN); + initPool(); + } + + public Suggest(Context context, ByteBuffer byteBuffer) { + mMainDict = new BinaryDictionary(context, byteBuffer, DIC_MAIN); + initPool(); + } + + private void initPool() { + for (int i = 0; i < mPrefMaxSuggestions; i++) { + StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); + mStringPool.add(sb); + } + } + + public void setAutoTextEnabled(boolean enabled) { + mAutoTextEnabled = enabled; + } + + public int getCorrectionMode() { + return mCorrectionMode; + } + + public void setCorrectionMode(int mode) { + mCorrectionMode = mode; + } + + public boolean hasMainDictionary() { + return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD; + } + + public int getApproxMaxWordLength() { + return APPROX_MAX_WORD_LENGTH; + } +/* + *//** + * Sets an optional user dictionary resource to be loaded. The user dictionary is consulted + * before the main dictionary, if set. + *//* + public void setUserDictionary(Dictionary userDictionary) { + mUserDictionary = userDictionary; + } + + *//** + * Sets an optional contacts dictionary resource to be loaded. + *//* + public void setContactsDictionary(Dictionary userDictionary) { + mContactsDictionary = userDictionary; + } + + public void setAutoDictionary(Dictionary autoDictionary) { + mAutoDictionary = autoDictionary; + } + + public void setUserBigramDictionary(Dictionary userBigramDictionary) { + mUserBigramDictionary = userBigramDictionary; + } +*/ + /** + * Number of suggestions to generate from the input key sequence. This has + * to be a number between 1 and 100 (inclusive). + * @param maxSuggestions + * @throws IllegalArgumentException if the number is out of range + */ + public void setMaxSuggestions(int maxSuggestions) { + if (maxSuggestions < 1 || maxSuggestions > 100) { + throw new IllegalArgumentException("maxSuggestions must be between 1 and 100"); + } + mPrefMaxSuggestions = maxSuggestions; + mPriorities = new int[mPrefMaxSuggestions]; + mBigramPriorities = new int[PREF_MAX_BIGRAMS]; + collectGarbage(mSuggestions, mPrefMaxSuggestions); + while (mStringPool.size() < mPrefMaxSuggestions) { + StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); + mStringPool.add(sb); + } + } + + private boolean haveSufficientCommonality(String original, CharSequence suggestion) { + final int originalLength = original.length(); + final int suggestionLength = suggestion.length(); + final int minLength = Math.min(originalLength, suggestionLength); + if (minLength <= 2) return true; + int matching = 0; + int lessMatching = 0; // Count matches if we skip one character + int i; + for (i = 0; i < minLength; i++) { + final char origChar = ExpandableDictionary.toLowerCase(original.charAt(i)); + if (origChar == ExpandableDictionary.toLowerCase(suggestion.charAt(i))) { + matching++; + lessMatching++; + } else if (i + 1 < suggestionLength + && origChar == ExpandableDictionary.toLowerCase(suggestion.charAt(i + 1))) { + lessMatching++; + } + } + matching = Math.max(matching, lessMatching); + + if (minLength <= 4) { + return matching >= 2; + } else { + return matching > minLength / 2; + } + } + + /** + * Returns a list of words that match the list of character codes passed in. + * This list will be overwritten the next time this function is called. + * @param view a view for retrieving the context for AutoText + * @param wordComposer contains what is currently being typed + * @param prevWordForBigram previous word (used only for bigram) + * @return list of suggestions. + */ + public List getSuggestions(View view, WordComposer wordComposer, + boolean includeTypedWordIfValid, CharSequence prevWordForBigram) { + LatinImeLogger.onStartSuggestion(prevWordForBigram); + mHaveCorrection = false; + mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); + mIsAllUpperCase = wordComposer.isAllUpperCase(); + collectGarbage(mSuggestions, mPrefMaxSuggestions); + Arrays.fill(mPriorities, 0); + Arrays.fill(mNextLettersFrequencies, 0); + + // Save a lowercase version of the original word + mOriginalWord = wordComposer.getTypedWord(); + if (mOriginalWord != null) { + final String mOriginalWordString = mOriginalWord.toString(); + mOriginalWord = mOriginalWordString; + mLowerOriginalWord = mOriginalWordString.toLowerCase(); + // Treating USER_TYPED as UNIGRAM suggestion for logging now. + LatinImeLogger.onAddSuggestedWord(mOriginalWordString, Suggest.DIC_USER_TYPED, + Dictionary.DataType.UNIGRAM); + } else { + mLowerOriginalWord = ""; + } + + if (wordComposer.size() == 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM + || mCorrectionMode == CORRECTION_BASIC)) { + // At first character typed, search only the bigrams + Arrays.fill(mBigramPriorities, 0); + collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS); + + if (!TextUtils.isEmpty(prevWordForBigram)) { + CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); + if (mMainDict.isValidWord(lowerPrevWord)) { + prevWordForBigram = lowerPrevWord; + } + /*if (mUserBigramDictionary != null) { + mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this, + mNextLettersFrequencies); + } + if (mContactsDictionary != null) { + mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this, + mNextLettersFrequencies); + }*/ + if (mMainDict != null) { + mMainDict.getBigrams(wordComposer, prevWordForBigram, this, + mNextLettersFrequencies); + } + char currentChar = wordComposer.getTypedWord().charAt(0); + // TODO: Must pay attention to locale when changing case. + char currentCharUpper = Character.toUpperCase(currentChar); + int count = 0; + int bigramSuggestionSize = mBigramSuggestions.size(); + for (int i = 0; i < bigramSuggestionSize; i++) { + if (mBigramSuggestions.get(i).charAt(0) == currentChar + || mBigramSuggestions.get(i).charAt(0) == currentCharUpper) { + int poolSize = mStringPool.size(); + StringBuilder sb = poolSize > 0 ? + (StringBuilder) mStringPool.remove(poolSize - 1) + : new StringBuilder(getApproxMaxWordLength()); + sb.setLength(0); + sb.append(mBigramSuggestions.get(i)); + mSuggestions.add(count++, sb); + if (count > mPrefMaxSuggestions) break; + } + } + } + + } else if (wordComposer.size() > 1) { + // At second character typed, search the unigrams (scores being affected by bigrams) + /*if (mUserDictionary != null || mContactsDictionary != null) { + if (mUserDictionary != null) { + mUserDictionary.getWords(wordComposer, this, mNextLettersFrequencies); + } + if (mContactsDictionary != null) { + mContactsDictionary.getWords(wordComposer, this, mNextLettersFrequencies); + } + + if (mSuggestions.size() > 0 && isValidWord(mOriginalWord) + && (mCorrectionMode == CORRECTION_FULL + || mCorrectionMode == CORRECTION_FULL_BIGRAM)) { + mHaveCorrection = true; + } + }*/ + mMainDict.getWords(wordComposer, this, mNextLettersFrequencies); + if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM) + && mSuggestions.size() > 0) { + mHaveCorrection = true; + } + } + if (mOriginalWord != null) { + mSuggestions.add(0, mOriginalWord.toString()); + } + + // Check if the first suggestion has a minimum number of characters in common + if (wordComposer.size() > 1 && mSuggestions.size() > 1 + && (mCorrectionMode == CORRECTION_FULL + || mCorrectionMode == CORRECTION_FULL_BIGRAM)) { + if (!haveSufficientCommonality(mLowerOriginalWord, mSuggestions.get(1))) { + mHaveCorrection = false; + } + } + if (mAutoTextEnabled) { + int i = 0; + int max = 6; + // Don't autotext the suggestions from the dictionaries + if (mCorrectionMode == CORRECTION_BASIC) max = 1; + while (i < mSuggestions.size() && i < max) { + String suggestedWord = mSuggestions.get(i).toString().toLowerCase(); + CharSequence autoText = + AutoText.get(suggestedWord, 0, suggestedWord.length(), view); + // Is there an AutoText correction? + boolean canAdd = autoText != null; + // Is that correction already the current prediction (or original word)? + canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i)); + // Is that correction already the next predicted word? + if (canAdd && i + 1 < mSuggestions.size() && mCorrectionMode != CORRECTION_BASIC) { + canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1)); + } + if (canAdd) { + mHaveCorrection = true; + mSuggestions.add(i + 1, autoText); + i++; + } + i++; + } + } + removeDupes(); + return mSuggestions; + } + + public int[] getNextLettersFrequencies() { + return mNextLettersFrequencies; + } + + private void removeDupes() { + final ArrayList suggestions = mSuggestions; + if (suggestions.size() < 2) return; + int i = 1; + // Don't cache suggestions.size(), since we may be removing items + while (i < suggestions.size()) { + final CharSequence cur = suggestions.get(i); + // Compare each candidate with each previous candidate + for (int j = 0; j < i; j++) { + CharSequence previous = suggestions.get(j); + if (TextUtils.equals(cur, previous)) { + removeFromSuggestions(i); + i--; + break; + } + } + i++; + } + } + + private void removeFromSuggestions(int index) { + CharSequence garbage = mSuggestions.remove(index); + if (garbage != null && garbage instanceof StringBuilder) { + mStringPool.add(garbage); + } + } + + public boolean hasMinimalCorrection() { + return mHaveCorrection; + } + + private boolean compareCaseInsensitive(final String mLowerOriginalWord, + final char[] word, final int offset, final int length) { + final int originalLength = mLowerOriginalWord.length(); + if (originalLength == length && Character.isUpperCase(word[offset])) { + for (int i = 0; i < originalLength; i++) { + if (mLowerOriginalWord.charAt(i) != Character.toLowerCase(word[offset+i])) { + return false; + } + } + return true; + } + return false; + } + + public boolean addWord(final char[] word, final int offset, final int length, int freq, + final int dicTypeId, final Dictionary.DataType dataType) { + Dictionary.DataType dataTypeForLog = dataType; + ArrayList suggestions; + int[] priorities; + int prefMaxSuggestions; + if(dataType == Dictionary.DataType.BIGRAM) { + suggestions = mBigramSuggestions; + priorities = mBigramPriorities; + prefMaxSuggestions = PREF_MAX_BIGRAMS; + } else { + suggestions = mSuggestions; + priorities = mPriorities; + prefMaxSuggestions = mPrefMaxSuggestions; + } + + int pos = 0; + + // Check if it's the same word, only caps are different + if (compareCaseInsensitive(mLowerOriginalWord, word, offset, length)) { + pos = 0; + } else { + if (dataType == Dictionary.DataType.UNIGRAM) { + // Check if the word was already added before (by bigram data) + int bigramSuggestion = searchBigramSuggestion(word,offset,length); + if(bigramSuggestion >= 0) { + dataTypeForLog = Dictionary.DataType.BIGRAM; + // turn freq from bigram into multiplier specified above + double multiplier = (((double) mBigramPriorities[bigramSuggestion]) + / MAXIMUM_BIGRAM_FREQUENCY) + * (BIGRAM_MULTIPLIER_MAX - BIGRAM_MULTIPLIER_MIN) + + BIGRAM_MULTIPLIER_MIN; + /* Log.d(TAG,"bigram num: " + bigramSuggestion + + " wordB: " + mBigramSuggestions.get(bigramSuggestion).toString() + + " currentPriority: " + freq + " bigramPriority: " + + mBigramPriorities[bigramSuggestion] + + " multiplier: " + multiplier); */ + freq = (int)Math.round((freq * multiplier)); + } + } + + // Check the last one's priority and bail + if (priorities[prefMaxSuggestions - 1] >= freq) return true; + while (pos < prefMaxSuggestions) { + if (priorities[pos] < freq + || (priorities[pos] == freq && length < suggestions.get(pos).length())) { + break; + } + pos++; + } + } + if (pos >= prefMaxSuggestions) { + return true; + } + + System.arraycopy(priorities, pos, priorities, pos + 1, + prefMaxSuggestions - pos - 1); + priorities[pos] = freq; + int poolSize = mStringPool.size(); + StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1) + : new StringBuilder(getApproxMaxWordLength()); + sb.setLength(0); + // TODO: Must pay attention to locale when changing case. + if (mIsAllUpperCase) { + sb.append(new String(word, offset, length).toUpperCase()); + } else if (mIsFirstCharCapitalized) { + sb.append(Character.toUpperCase(word[offset])); + if (length > 1) { + sb.append(word, offset + 1, length - 1); + } + } else { + sb.append(word, offset, length); + } + suggestions.add(pos, sb); + if (suggestions.size() > prefMaxSuggestions) { + CharSequence garbage = suggestions.remove(prefMaxSuggestions); + if (garbage instanceof StringBuilder) { + mStringPool.add(garbage); + } + } else { + LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId, dataTypeForLog); + } + return true; + } + + private int searchBigramSuggestion(final char[] word, final int offset, final int length) { + // TODO This is almost O(n^2). Might need fix. + // search whether the word appeared in bigram data + int bigramSuggestSize = mBigramSuggestions.size(); + for(int i = 0; i < bigramSuggestSize; i++) { + if(mBigramSuggestions.get(i).length() == length) { + boolean chk = true; + for(int j = 0; j < length; j++) { + if(mBigramSuggestions.get(i).charAt(j) != word[offset+j]) { + chk = false; + break; + } + } + if(chk) return i; + } + } + + return -1; + } + + public boolean isValidWord(final CharSequence word) { + if (word == null || word.length() == 0) { + return false; + } + return mMainDict.isValidWord(word) + /*|| (mUserDictionary != null && mUserDictionary.isValidWord(word)) + || (mAutoDictionary != null && mAutoDictionary.isValidWord(word)) + || (mContactsDictionary != null && mContactsDictionary.isValidWord(word))*/; + } + + private void collectGarbage(ArrayList suggestions, int prefMaxSuggestions) { + int poolSize = mStringPool.size(); + int garbageSize = suggestions.size(); + while (poolSize < prefMaxSuggestions && garbageSize > 0) { + CharSequence garbage = suggestions.get(garbageSize - 1); + if (garbage != null && garbage instanceof StringBuilder) { + mStringPool.add(garbage); + poolSize++; + } + garbageSize--; + } + if (poolSize == prefMaxSuggestions + 1) { + Log.w("Suggest", "String pool got too big: " + poolSize); + } + suggestions.clear(); + } + + public void close() { + if (mMainDict != null) { + mMainDict.close(); + } + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/SwipeTracker.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/SwipeTracker.java new file mode 100644 index 00000000..c5a522e1 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/SwipeTracker.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.view.MotionEvent; + +class SwipeTracker { + private static final int NUM_PAST = 4; + private static final int LONGEST_PAST_TIME = 200; + + final EventRingBuffer mBuffer = new EventRingBuffer(NUM_PAST); + + private float mYVelocity; + private float mXVelocity; + + public void addMovement(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mBuffer.clear(); + return; + } + long time = ev.getEventTime(); + final int count = ev.getHistorySize(); + for (int i = 0; i < count; i++) { + addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), ev.getHistoricalEventTime(i)); + } + addPoint(ev.getX(), ev.getY(), time); + } + + private void addPoint(float x, float y, long time) { + final EventRingBuffer buffer = mBuffer; + while (buffer.size() > 0) { + long lastT = buffer.getTime(0); + if (lastT >= time - LONGEST_PAST_TIME) + break; + buffer.dropOldest(); + } + buffer.add(x, y, time); + } + + public void computeCurrentVelocity(int units) { + computeCurrentVelocity(units, Float.MAX_VALUE); + } + + public void computeCurrentVelocity(int units, float maxVelocity) { + final EventRingBuffer buffer = mBuffer; + final float oldestX = buffer.getX(0); + final float oldestY = buffer.getY(0); + final long oldestTime = buffer.getTime(0); + + float accumX = 0; + float accumY = 0; + final int count = buffer.size(); + for (int pos = 1; pos < count; pos++) { + final int dur = (int)(buffer.getTime(pos) - oldestTime); + if (dur == 0) continue; + float dist = buffer.getX(pos) - oldestX; + float vel = (dist / dur) * units; // pixels/frame. + if (accumX == 0) accumX = vel; + else accumX = (accumX + vel) * .5f; + + dist = buffer.getY(pos) - oldestY; + vel = (dist / dur) * units; // pixels/frame. + if (accumY == 0) accumY = vel; + else accumY = (accumY + vel) * .5f; + } + mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) + : Math.min(accumX, maxVelocity); + mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) + : Math.min(accumY, maxVelocity); + } + + public float getXVelocity() { + return mXVelocity; + } + + public float getYVelocity() { + return mYVelocity; + } + + static class EventRingBuffer { + private final int bufSize; + private final float xBuf[]; + private final float yBuf[]; + private final long timeBuf[]; + private int top; // points new event + private int end; // points oldest event + private int count; // the number of valid data + + public EventRingBuffer(int max) { + this.bufSize = max; + xBuf = new float[max]; + yBuf = new float[max]; + timeBuf = new long[max]; + clear(); + } + + public void clear() { + top = end = count = 0; + } + + public int size() { + return count; + } + + // Position 0 points oldest event + private int index(int pos) { + return (end + pos) % bufSize; + } + + private int advance(int index) { + return (index + 1) % bufSize; + } + + public void add(float x, float y, long time) { + xBuf[top] = x; + yBuf[top] = y; + timeBuf[top] = time; + top = advance(top); + if (count < bufSize) { + count++; + } else { + end = advance(end); + } + } + + public float getX(int pos) { + return xBuf[index(pos)]; + } + + public float getY(int pos) { + return yBuf[index(pos)]; + } + + public long getTime(int pos) { + return timeBuf[index(pos)]; + } + + public void dropOldest() { + count--; + end = advance(end); + } + } +} \ No newline at end of file diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/TextEntryState.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/TextEntryState.java new file mode 100644 index 00000000..4950425f --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/TextEntryState.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import android.content.Context; +import android.inputmethodservice.Keyboard.Key; +import android.text.format.DateFormat; +import android.util.Log; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Calendar; + +public class TextEntryState { + + private static final boolean DBG = false; + + private static final String TAG = "TextEntryState"; + + private static boolean LOGGING = false; + + private static int sBackspaceCount = 0; + + private static int sAutoSuggestCount = 0; + + private static int sAutoSuggestUndoneCount = 0; + + private static int sManualSuggestCount = 0; + + private static int sWordNotInDictionaryCount = 0; + + private static int sSessionCount = 0; + + private static int sTypedChars; + + private static int sActualChars; + + public enum State { + UNKNOWN, + START, + IN_WORD, + ACCEPTED_DEFAULT, + PICKED_SUGGESTION, + PUNCTUATION_AFTER_WORD, + PUNCTUATION_AFTER_ACCEPTED, + SPACE_AFTER_ACCEPTED, + SPACE_AFTER_PICKED, + UNDO_COMMIT, + CORRECTING, + PICKED_CORRECTION; + } + + private static State sState = State.UNKNOWN; + + private static FileOutputStream sKeyLocationFile; + private static FileOutputStream sUserActionFile; + + public static void newSession(Context context) { + sSessionCount++; + sAutoSuggestCount = 0; + sBackspaceCount = 0; + sAutoSuggestUndoneCount = 0; + sManualSuggestCount = 0; + sWordNotInDictionaryCount = 0; + sTypedChars = 0; + sActualChars = 0; + sState = State.START; + + if (LOGGING) { + try { + sKeyLocationFile = context.openFileOutput("key.txt", Context.MODE_APPEND); + sUserActionFile = context.openFileOutput("action.txt", Context.MODE_APPEND); + } catch (IOException ioe) { + Log.e("TextEntryState", "Couldn't open file for output: " + ioe); + } + } + } + + public static void endSession() { + if (sKeyLocationFile == null) { + return; + } + try { + sKeyLocationFile.close(); + // Write to log file + // Write timestamp, settings, + String out = DateFormat.format("MM:dd hh:mm:ss", Calendar.getInstance().getTime()) + .toString() + + " BS: " + sBackspaceCount + + " auto: " + sAutoSuggestCount + + " manual: " + sManualSuggestCount + + " typed: " + sWordNotInDictionaryCount + + " undone: " + sAutoSuggestUndoneCount + + " saved: " + ((float) (sActualChars - sTypedChars) / sActualChars) + + "\n"; + sUserActionFile.write(out.getBytes()); + sUserActionFile.close(); + sKeyLocationFile = null; + sUserActionFile = null; + } catch (IOException ioe) { + + } + } + + public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord) { + if (typedWord == null) return; + if (!typedWord.equals(actualWord)) { + sAutoSuggestCount++; + } + sTypedChars += typedWord.length(); + sActualChars += actualWord.length(); + sState = State.ACCEPTED_DEFAULT; + LatinImeLogger.logOnAutoSuggestion(typedWord.toString(), actualWord.toString()); + displayState(); + } + + // State.ACCEPTED_DEFAULT will be changed to other sub-states + // (see "case ACCEPTED_DEFAULT" in typedCharacter() below), + // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state. + public static void backToAcceptedDefault(CharSequence typedWord) { + if (typedWord == null) return; + switch (sState) { + case SPACE_AFTER_ACCEPTED: + case PUNCTUATION_AFTER_ACCEPTED: + case IN_WORD: + sState = State.ACCEPTED_DEFAULT; + break; + } + displayState(); + } + + public static void acceptedTyped(CharSequence typedWord) { + sWordNotInDictionaryCount++; + sState = State.PICKED_SUGGESTION; + displayState(); + } + + public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) { + sManualSuggestCount++; + State oldState = sState; + if (typedWord.equals(actualWord)) { + acceptedTyped(typedWord); + } + if (oldState == State.CORRECTING || oldState == State.PICKED_CORRECTION) { + sState = State.PICKED_CORRECTION; + } else { + sState = State.PICKED_SUGGESTION; + } + displayState(); + } + + public static void selectedForCorrection() { + sState = State.CORRECTING; + displayState(); + } + + public static void typedCharacter(char c, boolean isSeparator) { + boolean isSpace = c == ' '; + switch (sState) { + case IN_WORD: + if (isSpace || isSeparator) { + sState = State.START; + } else { + // State hasn't changed. + } + break; + case ACCEPTED_DEFAULT: + case SPACE_AFTER_PICKED: + if (isSpace) { + sState = State.SPACE_AFTER_ACCEPTED; + } else if (isSeparator) { + sState = State.PUNCTUATION_AFTER_ACCEPTED; + } else { + sState = State.IN_WORD; + } + break; + case PICKED_SUGGESTION: + case PICKED_CORRECTION: + if (isSpace) { + sState = State.SPACE_AFTER_PICKED; + } else if (isSeparator) { + // Swap + sState = State.PUNCTUATION_AFTER_ACCEPTED; + } else { + sState = State.IN_WORD; + } + break; + case START: + case UNKNOWN: + case SPACE_AFTER_ACCEPTED: + case PUNCTUATION_AFTER_ACCEPTED: + case PUNCTUATION_AFTER_WORD: + if (!isSpace && !isSeparator) { + sState = State.IN_WORD; + } else { + sState = State.START; + } + break; + case UNDO_COMMIT: + if (isSpace || isSeparator) { + sState = State.ACCEPTED_DEFAULT; + } else { + sState = State.IN_WORD; + } + break; + case CORRECTING: + sState = State.START; + break; + } + displayState(); + } + + public static void backspace() { + if (sState == State.ACCEPTED_DEFAULT) { + sState = State.UNDO_COMMIT; + sAutoSuggestUndoneCount++; + LatinImeLogger.logOnAutoSuggestionCanceled(); + } else if (sState == State.UNDO_COMMIT) { + sState = State.IN_WORD; + } + sBackspaceCount++; + displayState(); + } + + public static void reset() { + sState = State.START; + displayState(); + } + + public static State getState() { + if (DBG) { + Log.d(TAG, "Returning state = " + sState); + } + return sState; + } + + public static boolean isCorrecting() { + return sState == State.CORRECTING || sState == State.PICKED_CORRECTION; + } + + public static void keyPressedAt(Key key, int x, int y) { + if (LOGGING && sKeyLocationFile != null && key.codes[0] >= 32) { + String out = + "KEY: " + (char) key.codes[0] + + " X: " + x + + " Y: " + y + + " MX: " + (key.x + key.width / 2) + + " MY: " + (key.y + key.height / 2) + + "\n"; + try { + sKeyLocationFile.write(out.getBytes()); + } catch (IOException ioe) { + // TODO: May run out of space + } + } + } + + private static void displayState() { + if (DBG) { + Log.d(TAG, "State = " + sState); + } + } +} + diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/UserBigramDictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/UserBigramDictionary.java new file mode 100644 index 00000000..820c2a8d --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/UserBigramDictionary.java @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.os.AsyncTask; +import android.provider.BaseColumns; +import android.util.Log; + +/** + * Stores all the pairs user types in databases. Prune the database if the size + * gets too big. Unlike AutoDictionary, it even stores the pairs that are already + * in the dictionary. + */ +public class UserBigramDictionary extends ExpandableDictionary { + private static final String TAG = "UserBigramDictionary"; + + /** Any pair being typed or picked */ + private static final int FREQUENCY_FOR_TYPED = 2; + + /** Maximum frequency for all pairs */ + private static final int FREQUENCY_MAX = 127; + + /** + * If this pair is typed 6 times, it would be suggested. + * Should be smaller than ContactsDictionary.FREQUENCY_FOR_CONTACTS_BIGRAM + */ + protected static final int SUGGEST_THRESHOLD = 6 * FREQUENCY_FOR_TYPED; + + /** Maximum number of pairs. Pruning will start when databases goes above this number. */ + private static int sMaxUserBigrams = 10000; + + /** + * When it hits maximum bigram pair, it will delete until you are left with + * only (sMaxUserBigrams - sDeleteUserBigrams) pairs. + * Do not keep this number small to avoid deleting too often. + */ + private static int sDeleteUserBigrams = 1000; + + /** + * Database version should increase if the database structure changes + */ + private static final int DATABASE_VERSION = 1; + + private static final String DATABASE_NAME = "userbigram_dict.db"; + + /** Name of the words table in the database */ + private static final String MAIN_TABLE_NAME = "main"; + // TODO: Consume less space by using a unique id for locale instead of the whole + // 2-5 character string. (Same TODO from AutoDictionary) + private static final String MAIN_COLUMN_ID = BaseColumns._ID; + private static final String MAIN_COLUMN_WORD1 = "word1"; + private static final String MAIN_COLUMN_WORD2 = "word2"; + private static final String MAIN_COLUMN_LOCALE = "locale"; + + /** Name of the frequency table in the database */ + private static final String FREQ_TABLE_NAME = "frequency"; + private static final String FREQ_COLUMN_ID = BaseColumns._ID; + private static final String FREQ_COLUMN_PAIR_ID = "pair_id"; + private static final String FREQ_COLUMN_FREQUENCY = "freq"; + + private final KP2AKeyboard mIme; + + /** Locale for which this auto dictionary is storing words */ + private String mLocale; + + private HashSet mPendingWrites = new HashSet(); + private final Object mPendingWritesLock = new Object(); + private static volatile boolean sUpdatingDB = false; + + private final static HashMap sDictProjectionMap; + + static { + sDictProjectionMap = new HashMap(); + sDictProjectionMap.put(MAIN_COLUMN_ID, MAIN_COLUMN_ID); + sDictProjectionMap.put(MAIN_COLUMN_WORD1, MAIN_COLUMN_WORD1); + sDictProjectionMap.put(MAIN_COLUMN_WORD2, MAIN_COLUMN_WORD2); + sDictProjectionMap.put(MAIN_COLUMN_LOCALE, MAIN_COLUMN_LOCALE); + + sDictProjectionMap.put(FREQ_COLUMN_ID, FREQ_COLUMN_ID); + sDictProjectionMap.put(FREQ_COLUMN_PAIR_ID, FREQ_COLUMN_PAIR_ID); + sDictProjectionMap.put(FREQ_COLUMN_FREQUENCY, FREQ_COLUMN_FREQUENCY); + } + + private static DatabaseHelper sOpenHelper = null; + + private static class Bigram { + String word1; + String word2; + int frequency; + + Bigram(String word1, String word2, int frequency) { + this.word1 = word1; + this.word2 = word2; + this.frequency = frequency; + } + + @Override + public boolean equals(Object bigram) { + Bigram bigram2 = (Bigram) bigram; + return (word1.equals(bigram2.word1) && word2.equals(bigram2.word2)); + } + + @Override + public int hashCode() { + return (word1 + " " + word2).hashCode(); + } + } + + public void setDatabaseMax(int maxUserBigram) { + sMaxUserBigrams = maxUserBigram; + } + + public void setDatabaseDelete(int deleteUserBigram) { + sDeleteUserBigrams = deleteUserBigram; + } + + public UserBigramDictionary(Context context, KP2AKeyboard ime, String locale, int dicTypeId) { + super(context, dicTypeId); + mIme = ime; + mLocale = locale; + if (sOpenHelper == null) { + sOpenHelper = new DatabaseHelper(getContext()); + } + if (mLocale != null && mLocale.length() > 1) { + loadDictionary(); + } + } + + @Override + public void close() { + flushPendingWrites(); + // Don't close the database as locale changes will require it to be reopened anyway + // Also, the database is written to somewhat frequently, so it needs to be kept alive + // throughout the life of the process. + // mOpenHelper.close(); + super.close(); + } + + /** + * Pair will be added to the userbigram database. + */ + public int addBigrams(String word1, String word2) { + // remove caps + if (mIme != null && mIme.getCurrentWord().isAutoCapitalized()) { + word2 = Character.toLowerCase(word2.charAt(0)) + word2.substring(1); + } + + int freq = super.addBigram(word1, word2, FREQUENCY_FOR_TYPED); + if (freq > FREQUENCY_MAX) freq = FREQUENCY_MAX; + synchronized (mPendingWritesLock) { + if (freq == FREQUENCY_FOR_TYPED || mPendingWrites.isEmpty()) { + mPendingWrites.add(new Bigram(word1, word2, freq)); + } else { + Bigram bi = new Bigram(word1, word2, freq); + mPendingWrites.remove(bi); + mPendingWrites.add(bi); + } + } + + return freq; + } + + /** + * Schedules a background thread to write any pending words to the database. + */ + public void flushPendingWrites() { + synchronized (mPendingWritesLock) { + // Nothing pending? Return + if (mPendingWrites.isEmpty()) return; + // Create a background thread to write the pending entries + new UpdateDbTask(getContext(), sOpenHelper, mPendingWrites, mLocale).execute(); + // Create a new map for writing new entries into while the old one is written to db + mPendingWrites = new HashSet(); + } + } + + /** Used for testing purpose **/ + void waitUntilUpdateDBDone() { + synchronized (mPendingWritesLock) { + while (sUpdatingDB) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + return; + } + } + + @Override + public void loadDictionaryAsync() { + // Load the words that correspond to the current input locale + Cursor cursor = query(MAIN_COLUMN_LOCALE + "=?", new String[] { mLocale }); + try { + if (cursor.moveToFirst()) { + int word1Index = cursor.getColumnIndex(MAIN_COLUMN_WORD1); + int word2Index = cursor.getColumnIndex(MAIN_COLUMN_WORD2); + int frequencyIndex = cursor.getColumnIndex(FREQ_COLUMN_FREQUENCY); + while (!cursor.isAfterLast()) { + String word1 = cursor.getString(word1Index); + String word2 = cursor.getString(word2Index); + int frequency = cursor.getInt(frequencyIndex); + // Safeguard against adding really long words. Stack may overflow due + // to recursive lookup + if (word1.length() < MAX_WORD_LENGTH && word2.length() < MAX_WORD_LENGTH) { + super.setBigram(word1, word2, frequency); + } + cursor.moveToNext(); + } + } + } finally { + cursor.close(); + } + } + + /** + * Query the database + */ + private Cursor query(String selection, String[] selectionArgs) { + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + + // main INNER JOIN frequency ON (main._id=freq.pair_id) + qb.setTables(MAIN_TABLE_NAME + " INNER JOIN " + FREQ_TABLE_NAME + " ON (" + + MAIN_TABLE_NAME + "." + MAIN_COLUMN_ID + "=" + FREQ_TABLE_NAME + "." + + FREQ_COLUMN_PAIR_ID +")"); + + qb.setProjectionMap(sDictProjectionMap); + + // Get the database and run the query + SQLiteDatabase db = sOpenHelper.getReadableDatabase(); + Cursor c = qb.query(db, + new String[] { MAIN_COLUMN_WORD1, MAIN_COLUMN_WORD2, FREQ_COLUMN_FREQUENCY }, + selection, selectionArgs, null, null, null); + return c; + } + + /** + * This class helps open, create, and upgrade the database file. + */ + private static class DatabaseHelper extends SQLiteOpenHelper { + + DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("PRAGMA foreign_keys = ON;"); + db.execSQL("CREATE TABLE " + MAIN_TABLE_NAME + " (" + + MAIN_COLUMN_ID + " INTEGER PRIMARY KEY," + + MAIN_COLUMN_WORD1 + " TEXT," + + MAIN_COLUMN_WORD2 + " TEXT," + + MAIN_COLUMN_LOCALE + " TEXT" + + ");"); + db.execSQL("CREATE TABLE " + FREQ_TABLE_NAME + " (" + + FREQ_COLUMN_ID + " INTEGER PRIMARY KEY," + + FREQ_COLUMN_PAIR_ID + " INTEGER," + + FREQ_COLUMN_FREQUENCY + " INTEGER," + + "FOREIGN KEY(" + FREQ_COLUMN_PAIR_ID + ") REFERENCES " + MAIN_TABLE_NAME + + "(" + MAIN_COLUMN_ID + ")" + " ON DELETE CASCADE" + + ");"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + + newVersion + ", which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS " + MAIN_TABLE_NAME); + db.execSQL("DROP TABLE IF EXISTS " + FREQ_TABLE_NAME); + onCreate(db); + } + } + + /** + * Async task to write pending words to the database so that it stays in sync with + * the in-memory trie. + */ + private static class UpdateDbTask extends AsyncTask { + private final HashSet mMap; + private final DatabaseHelper mDbHelper; + private final String mLocale; + + public UpdateDbTask(Context context, DatabaseHelper openHelper, + HashSet pendingWrites, String locale) { + mMap = pendingWrites; + mLocale = locale; + mDbHelper = openHelper; + } + + /** Prune any old data if the database is getting too big. */ + private void checkPruneData(SQLiteDatabase db) { + db.execSQL("PRAGMA foreign_keys = ON;"); + Cursor c = db.query(FREQ_TABLE_NAME, new String[] { FREQ_COLUMN_PAIR_ID }, + null, null, null, null, null); + try { + int totalRowCount = c.getCount(); + // prune out old data if we have too much data + if (totalRowCount > sMaxUserBigrams) { + int numDeleteRows = (totalRowCount - sMaxUserBigrams) + sDeleteUserBigrams; + int pairIdColumnId = c.getColumnIndex(FREQ_COLUMN_PAIR_ID); + c.moveToFirst(); + int count = 0; + while (count < numDeleteRows && !c.isAfterLast()) { + String pairId = c.getString(pairIdColumnId); + // Deleting from MAIN table will delete the frequencies + // due to FOREIGN KEY .. ON DELETE CASCADE + db.delete(MAIN_TABLE_NAME, MAIN_COLUMN_ID + "=?", + new String[] { pairId }); + c.moveToNext(); + count++; + } + } + } finally { + c.close(); + } + } + + @Override + protected void onPreExecute() { + sUpdatingDB = true; + } + + @Override + protected Void doInBackground(Void... v) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + db.execSQL("PRAGMA foreign_keys = ON;"); + // Write all the entries to the db + Iterator iterator = mMap.iterator(); + while (iterator.hasNext()) { + Bigram bi = iterator.next(); + + // find pair id + Cursor c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, + MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND " + + MAIN_COLUMN_LOCALE + "=?", + new String[] { bi.word1, bi.word2, mLocale }, null, null, null); + + int pairId; + if (c.moveToFirst()) { + // existing pair + pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID)); + db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?", + new String[] { Integer.toString(pairId) }); + } else { + // new pair + Long pairIdLong = db.insert(MAIN_TABLE_NAME, null, + getContentValues(bi.word1, bi.word2, mLocale)); + pairId = pairIdLong.intValue(); + } + c.close(); + + // insert new frequency + db.insert(FREQ_TABLE_NAME, null, getFrequencyContentValues(pairId, bi.frequency)); + } + checkPruneData(db); + sUpdatingDB = false; + + return null; + } + + private ContentValues getContentValues(String word1, String word2, String locale) { + ContentValues values = new ContentValues(3); + values.put(MAIN_COLUMN_WORD1, word1); + values.put(MAIN_COLUMN_WORD2, word2); + values.put(MAIN_COLUMN_LOCALE, locale); + return values; + } + + private ContentValues getFrequencyContentValues(int pairId, int frequency) { + ContentValues values = new ContentValues(2); + values.put(FREQ_COLUMN_PAIR_ID, pairId); + values.put(FREQ_COLUMN_FREQUENCY, frequency); + return values; + } + } + +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/UserDictionary.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/UserDictionary.java new file mode 100644 index 00000000..5366d6f0 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/UserDictionary.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package keepass2android.softkeyboard; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.provider.UserDictionary.Words; + +public class UserDictionary extends ExpandableDictionary { + + private static final String[] PROJECTION = { + Words._ID, + Words.WORD, + Words.FREQUENCY + }; + + private static final int INDEX_WORD = 1; + private static final int INDEX_FREQUENCY = 2; + + private ContentObserver mObserver; + private String mLocale; + + public UserDictionary(Context context, String locale) { + super(context, Suggest.DIC_USER); + mLocale = locale; + // Perform a managed query. The Activity will handle closing and requerying the cursor + // when needed. + ContentResolver cres = context.getContentResolver(); + + cres.registerContentObserver(Words.CONTENT_URI, true, mObserver = new ContentObserver(null) { + @Override + public void onChange(boolean self) { + setRequiresReload(true); + } + }); + + loadDictionary(); + } + + @Override + public synchronized void close() { + if (mObserver != null) { + getContext().getContentResolver().unregisterContentObserver(mObserver); + mObserver = null; + } + super.close(); + } + + @Override + public void loadDictionaryAsync() { + //Cursor cursor = getContext().getContentResolver() + // .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)", + // new String[] { mLocale }, null); + //addWords(cursor); + } + + /** + * Adds a word to the dictionary and makes it persistent. + * @param word the word to add. If the word is capitalized, then the dictionary will + * recognize it as a capitalized word when searched. + * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered + * the highest. + * @TODO use a higher or float range for frequency + */ + @Override + public synchronized void addWord(String word, int frequency) { + // Force load the dictionary here synchronously + if (getRequiresReload()) loadDictionaryAsync(); + // Safeguard against adding long words. Can cause stack overflow. + if (word.length() >= getMaxWordLength()) return; + + super.addWord(word, frequency); + + // Update the user dictionary provider + final ContentValues values = new ContentValues(5); + values.put(Words.WORD, word); + values.put(Words.FREQUENCY, frequency); + values.put(Words.LOCALE, mLocale); + values.put(Words.APP_ID, 0); + + final ContentResolver contentResolver = getContext().getContentResolver(); + new Thread("addWord") { + public void run() { + contentResolver.insert(Words.CONTENT_URI, values); + } + }.start(); + + // In case the above does a synchronous callback of the change observer + setRequiresReload(false); + } + + @Override + public synchronized void getWords(final WordComposer codes, final WordCallback callback, + int[] nextLettersFrequencies) { + super.getWords(codes, callback, nextLettersFrequencies); + } + + @Override + public synchronized boolean isValidWord(CharSequence word) { + return super.isValidWord(word); + } + + private void addWords(Cursor cursor) { + clearDictionary(); + + final int maxWordLength = getMaxWordLength(); + if (cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + String word = cursor.getString(INDEX_WORD); + int frequency = cursor.getInt(INDEX_FREQUENCY); + // Safeguard against adding really long words. Stack may overflow due + // to recursion + if (word.length() < maxWordLength) { + super.addWord(word, frequency); + } + cursor.moveToNext(); + } + } + cursor.close(); + } +} diff --git a/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/WordComposer.java b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/WordComposer.java new file mode 100644 index 00000000..47cd4ece --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/java/src/keepass2android/softkeyboard/WordComposer.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package keepass2android.softkeyboard; + +import java.util.ArrayList; + +/** + * A place to store the currently composing word with information such as adjacent key codes as well + */ +public class WordComposer { + /** + * The list of unicode values for each keystroke (including surrounding keys) + */ + private final ArrayList mCodes; + + /** + * The word chosen from the candidate list, until it is committed. + */ + private String mPreferredWord; + + private final StringBuilder mTypedWord; + + private int mCapsCount; + + private boolean mAutoCapitalized; + + /** + * Whether the user chose to capitalize the first char of the word. + */ + private boolean mIsFirstCharCapitalized; + + public WordComposer() { + mCodes = new ArrayList(12); + mTypedWord = new StringBuilder(20); + } + + WordComposer(WordComposer copy) { + mCodes = new ArrayList(copy.mCodes); + mPreferredWord = copy.mPreferredWord; + mTypedWord = new StringBuilder(copy.mTypedWord); + mCapsCount = copy.mCapsCount; + mAutoCapitalized = copy.mAutoCapitalized; + mIsFirstCharCapitalized = copy.mIsFirstCharCapitalized; + } + + /** + * Clear out the keys registered so far. + */ + public void reset() { + mCodes.clear(); + mIsFirstCharCapitalized = false; + mPreferredWord = null; + mTypedWord.setLength(0); + mCapsCount = 0; + } + + /** + * Number of keystrokes in the composing word. + * @return the number of keystrokes + */ + public int size() { + return mCodes.size(); + } + + /** + * Returns the codes at a particular position in the word. + * @param index the position in the word + * @return the unicode for the pressed and surrounding keys + */ + public int[] getCodesAt(int index) { + return mCodes.get(index); + } + + /** + * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of + * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. + * @param codes the array of unicode values + */ + public void add(int primaryCode, int[] codes) { + mTypedWord.append((char) primaryCode); + correctPrimaryJuxtapos(primaryCode, codes); + mCodes.add(codes); + if (Character.isUpperCase((char) primaryCode)) mCapsCount++; + } + + /** + * Swaps the first and second values in the codes array if the primary code is not the first + * value in the array but the second. This happens when the preferred key is not the key that + * the user released the finger on. + * @param primaryCode the preferred character + * @param codes array of codes based on distance from touch point + */ + private void correctPrimaryJuxtapos(int primaryCode, int[] codes) { + if (codes.length < 2) return; + if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { + codes[1] = codes[0]; + codes[0] = primaryCode; + } + } + + /** + * Delete the last keystroke as a result of hitting backspace. + */ + public void deleteLast() { + final int codesSize = mCodes.size(); + if (codesSize > 0) { + mCodes.remove(codesSize - 1); + final int lastPos = mTypedWord.length() - 1; + char last = mTypedWord.charAt(lastPos); + mTypedWord.deleteCharAt(lastPos); + if (Character.isUpperCase(last)) mCapsCount--; + } + } + + /** + * Returns the word as it was typed, without any correction applied. + * @return the word that was typed so far + */ + public CharSequence getTypedWord() { + int wordSize = mCodes.size(); + if (wordSize == 0) { + return null; + } + return mTypedWord; + } + + public void setFirstCharCapitalized(boolean capitalized) { + mIsFirstCharCapitalized = capitalized; + } + + /** + * Whether or not the user typed a capital letter as the first letter in the word + * @return capitalization preference + */ + public boolean isFirstCharCapitalized() { + return mIsFirstCharCapitalized; + } + + /** + * Whether or not all of the user typed chars are upper case + * @return true if all user typed chars are upper case, false otherwise + */ + public boolean isAllUpperCase() { + return (mCapsCount > 0) && (mCapsCount == size()); + } + + /** + * Stores the user's selected word, before it is actually committed to the text field. + * @param preferred + */ + public void setPreferredWord(String preferred) { + mPreferredWord = preferred; + } + + /** + * Return the word chosen by the user, or the typed word if no other word was chosen. + * @return the preferred word + */ + public CharSequence getPreferredWord() { + return mPreferredWord != null ? mPreferredWord : getTypedWord(); + } + + /** + * Returns true if more than one character is upper case, otherwise returns false. + */ + public boolean isMostlyCaps() { + return mCapsCount > 1; + } + + /** + * Saves the reason why the word is capitalized - whether it was automatic or + * due to the user hitting shift in the middle of a sentence. + * @param auto whether it was an automatic capitalization due to start of sentence + */ + public void setAutoCapitalized(boolean auto) { + mAutoCapitalized = auto; + } + + /** + * Returns whether the word was automatically capitalized. + * @return whether the word was automatically capitalized + */ + public boolean isAutoCapitalized() { + return mAutoCapitalized; + } +} diff --git a/src/java/KP2ASoftKeyboard2/native/howtobuild.txt b/src/java/KP2ASoftKeyboard2/native/howtobuild.txt new file mode 100644 index 00000000..775dff24 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/howtobuild.txt @@ -0,0 +1,4 @@ +in Cygwin-Console: +cd /cygdrive/c/users/Philipp/Documents/keepass2android//repo/externalstuff/LatinIME-gingerbread/native +/cygdrive/c/Users/Philipp/Downloads/android-ndk-r9c-windows-x86_64/android-ndk-r9c/ndk-build +native/libs kopieren nach java/libs \ No newline at end of file diff --git a/src/java/KP2ASoftKeyboard2/native/jni/Android.mk b/src/java/KP2ASoftKeyboard2/native/jni/Android.mk new file mode 100644 index 00000000..57ebee70 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/Android.mk @@ -0,0 +1,20 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/src + +LOCAL_SRC_FILES := \ + keepass2android_softkeyboard_BinaryDictionary.cpp \ + dictionary.cpp \ + char_utils.cpp + +ifneq ($(TARGET_ARCH),x86) +LOCAL_NDK_VERSION := 4 +LOCAL_SDK_VERSION := 8 +endif + +LOCAL_MODULE := libjni_latinime + +LOCAL_MODULE_TAGS := user + +include $(BUILD_SHARED_LIBRARY) diff --git a/src/java/KP2ASoftKeyboard2/native/jni/Application.mk b/src/java/KP2ASoftKeyboard2/native/jni/Application.mk new file mode 100644 index 00000000..7bc5d257 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/Application.mk @@ -0,0 +1,3 @@ +APP_MODULES := libjni_latinime +APP_OPTIM := release +APP_ABI := armeabi armeabi-v7a x86 mips diff --git a/src/java/KP2ASoftKeyboard2/native/jni/basechars.h b/src/java/KP2ASoftKeyboard2/native/jni/basechars.h new file mode 100644 index 00000000..5a440660 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/basechars.h @@ -0,0 +1,172 @@ +/** + * Table mapping most combined Latin, Greek, and Cyrillic characters + * to their base characters. If c is in range, BASE_CHARS[c] == c + * if c is not a combined character, or the base character if it + * is combined. + */ +static unsigned short BASE_CHARS[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x0020, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x0020, 0x00a9, 0x0061, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0020, + 0x00b0, 0x00b1, 0x0032, 0x0033, 0x0020, 0x03bc, 0x00b6, 0x00b7, + 0x0020, 0x0031, 0x006f, 0x00bb, 0x0031, 0x0031, 0x0033, 0x00bf, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00c6, 0x0043, + 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, + 0x00d0, 0x004e, 0x004f, 0x004f, 0x004f, 0x004f, 0x004f, 0x00d7, + 0x004f, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00de, 0x0073, // Manually changed d8 to 4f + // Manually changed df to 73 + 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00e6, 0x0063, + 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, + 0x00f0, 0x006e, 0x006f, 0x006f, 0x006f, 0x006f, 0x006f, 0x00f7, + 0x006f, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00fe, 0x0079, // Manually changed f8 to 6f + 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063, + 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064, + 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065, + 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, + 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, + 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, + 0x0049, 0x0131, 0x0049, 0x0069, 0x004a, 0x006a, 0x004b, 0x006b, + 0x0138, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, + 0x006c, 0x0141, 0x0142, 0x004e, 0x006e, 0x004e, 0x006e, 0x004e, + 0x006e, 0x02bc, 0x014a, 0x014b, 0x004f, 0x006f, 0x004f, 0x006f, + 0x004f, 0x006f, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072, + 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073, + 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167, + 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, + 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079, + 0x0059, 0x005a, 0x007a, 0x005a, 0x007a, 0x005a, 0x007a, 0x0073, + 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, + 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e, 0x018f, + 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, + 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f, + 0x004f, 0x006f, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, + 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x0055, + 0x0075, 0x01b1, 0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7, + 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x0044, 0x0044, 0x0064, 0x004c, + 0x004c, 0x006c, 0x004e, 0x004e, 0x006e, 0x0041, 0x0061, 0x0049, + 0x0069, 0x004f, 0x006f, 0x0055, 0x0075, 0x00dc, 0x00fc, 0x00dc, + 0x00fc, 0x00dc, 0x00fc, 0x00dc, 0x00fc, 0x01dd, 0x00c4, 0x00e4, + 0x0226, 0x0227, 0x00c6, 0x00e6, 0x01e4, 0x01e5, 0x0047, 0x0067, + 0x004b, 0x006b, 0x004f, 0x006f, 0x01ea, 0x01eb, 0x01b7, 0x0292, + 0x006a, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01f6, 0x01f7, + 0x004e, 0x006e, 0x00c5, 0x00e5, 0x00c6, 0x00e6, 0x00d8, 0x00f8, + 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065, + 0x0049, 0x0069, 0x0049, 0x0069, 0x004f, 0x006f, 0x004f, 0x006f, + 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075, + 0x0053, 0x0073, 0x0054, 0x0074, 0x021c, 0x021d, 0x0048, 0x0068, + 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061, + 0x0045, 0x0065, 0x00d6, 0x00f6, 0x00d5, 0x00f5, 0x004f, 0x006f, + 0x022e, 0x022f, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, + 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, + 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, + 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, + 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, + 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, + 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, + 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x0068, 0x0266, 0x006a, 0x0072, 0x0279, 0x027b, 0x0281, 0x0077, + 0x0079, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02de, 0x02df, + 0x0263, 0x006c, 0x0073, 0x0078, 0x0295, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, + 0x0370, 0x0371, 0x0372, 0x0373, 0x02b9, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x0020, 0x037b, 0x037c, 0x037d, 0x003b, 0x037f, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00a8, 0x0391, 0x00b7, + 0x0395, 0x0397, 0x0399, 0x038b, 0x039f, 0x038d, 0x03a5, 0x03a9, + 0x03ca, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x0399, 0x03a5, 0x03b1, 0x03b5, 0x03b7, 0x03b9, + 0x03cb, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03b9, 0x03c5, 0x03bf, 0x03c5, 0x03c9, 0x03cf, + 0x03b2, 0x03b8, 0x03a5, 0x03d2, 0x03d2, 0x03c6, 0x03c0, 0x03d7, + 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, + 0x03e0, 0x03e1, 0x03e2, 0x03e3, 0x03e4, 0x03e5, 0x03e6, 0x03e7, + 0x03e8, 0x03e9, 0x03ea, 0x03eb, 0x03ec, 0x03ed, 0x03ee, 0x03ef, + 0x03ba, 0x03c1, 0x03c2, 0x03f3, 0x0398, 0x03b5, 0x03f6, 0x03f7, + 0x03f8, 0x03a3, 0x03fa, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff, + 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, + 0x0408, 0x0409, 0x040a, 0x040b, 0x041a, 0x0418, 0x0423, 0x040f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0418, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0438, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456, + 0x0458, 0x0459, 0x045a, 0x045b, 0x043a, 0x0438, 0x0443, 0x045f, + 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, + 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f, + 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475, + 0x0478, 0x0479, 0x047a, 0x047b, 0x047c, 0x047d, 0x047e, 0x047f, + 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, + 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, + 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x049f, + 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, + 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, + 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, + 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x04be, 0x04bf, + 0x04c0, 0x0416, 0x0436, 0x04c3, 0x04c4, 0x04c5, 0x04c6, 0x04c7, + 0x04c8, 0x04c9, 0x04ca, 0x04cb, 0x04cc, 0x04cd, 0x04ce, 0x04cf, + 0x0410, 0x0430, 0x0410, 0x0430, 0x04d4, 0x04d5, 0x0415, 0x0435, + 0x04d8, 0x04d9, 0x04d8, 0x04d9, 0x0416, 0x0436, 0x0417, 0x0437, + 0x04e0, 0x04e1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041e, 0x043e, + 0x04e8, 0x04e9, 0x04e8, 0x04e9, 0x042d, 0x044d, 0x0423, 0x0443, + 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7, + 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff, +}; + +// generated with: +// cat UnicodeData.txt | perl -e 'while (<>) { @foo = split(/;/); $foo[5] =~ s/<.*> //; $base[hex($foo[0])] = hex($foo[5]);} for ($i = 0; $i < 0x500; $i += 8) { for ($j = $i; $j < $i + 8; $j++) { printf("0x%04x, ", $base[$j] ? $base[$j] : $j)}; print "\n"; }' diff --git a/src/java/KP2ASoftKeyboard2/native/jni/char_utils.cpp b/src/java/KP2ASoftKeyboard2/native/jni/char_utils.cpp new file mode 100644 index 00000000..a31a0632 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/char_utils.cpp @@ -0,0 +1,899 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace latinime { + +struct LatinCapitalSmallPair { + unsigned short capital; + unsigned short small; +}; + +// Generated from http://unicode.org/Public/UNIDATA/UnicodeData.txt +// +// 1. Run the following code. Bascially taken from +// Dictionary::toLowerCase(unsigned short c) in dictionary.cpp. +// Then, get the list of chars where cc != ccc. +// +// unsigned short c, cc, ccc, ccc2; +// for (c = 0; c < 0xFFFF ; c++) { +// if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) { +// cc = BASE_CHARS[c]; +// } else { +// cc = c; +// } +// +// // tolower +// int isBase = 0; +// if (cc >='A' && cc <= 'Z') { +// ccc = (cc | 0x20); +// ccc2 = ccc; +// isBase = 1; +// } else if (cc > 0x7F) { +// ccc = u_tolower(cc); +// ccc2 = latin_tolower(cc); +// } else { +// ccc = cc; +// ccc2 = ccc; +// } +// if (!isBase && cc != ccc) { +// wprintf(L" 0x%04X => 0x%04X => 0x%04X %lc => %lc => %lc \n", +// c, cc, ccc, c, cc, ccc); +// //assert(ccc == ccc2); +// } +// } +// +// Initially, started with an empty latin_tolower() as below. +// +// unsigned short latin_tolower(unsigned short c) { +// return c; +// } +// +// +// 2. Process the list obtained by 1 by the following perl script and apply +// 'sort -u' as well. Get the SORTED_CHAR_MAP[]. +// Note that '$1' in the perl script is 'cc' in the above C code. +// +// while(<>) { +// / 0x\w* => 0x(\w*) =/; +// open(HDL, "grep -iw ^" . $1 . " UnicodeData.txt | "); +// $line = ; +// chomp $line; +// @cols = split(/;/, $line); +// print " { 0x$1, 0x$cols[13] }, // $cols[1]\n"; +// } +// +// +// 3. Update the latin_tolower() function above with SORTED_CHAR_MAP. Enable +// the assert(ccc == ccc2) above and confirm the function exits successfully. +// +static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = { + { 0x00C4, 0x00E4 }, // LATIN CAPITAL LETTER A WITH DIAERESIS + { 0x00C5, 0x00E5 }, // LATIN CAPITAL LETTER A WITH RING ABOVE + { 0x00C6, 0x00E6 }, // LATIN CAPITAL LETTER AE + { 0x00D0, 0x00F0 }, // LATIN CAPITAL LETTER ETH + { 0x00D5, 0x00F5 }, // LATIN CAPITAL LETTER O WITH TILDE + { 0x00D6, 0x00F6 }, // LATIN CAPITAL LETTER O WITH DIAERESIS + { 0x00D8, 0x00F8 }, // LATIN CAPITAL LETTER O WITH STROKE + { 0x00DC, 0x00FC }, // LATIN CAPITAL LETTER U WITH DIAERESIS + { 0x00DE, 0x00FE }, // LATIN CAPITAL LETTER THORN + { 0x0110, 0x0111 }, // LATIN CAPITAL LETTER D WITH STROKE + { 0x0126, 0x0127 }, // LATIN CAPITAL LETTER H WITH STROKE + { 0x0141, 0x0142 }, // LATIN CAPITAL LETTER L WITH STROKE + { 0x014A, 0x014B }, // LATIN CAPITAL LETTER ENG + { 0x0152, 0x0153 }, // LATIN CAPITAL LIGATURE OE + { 0x0166, 0x0167 }, // LATIN CAPITAL LETTER T WITH STROKE + { 0x0181, 0x0253 }, // LATIN CAPITAL LETTER B WITH HOOK + { 0x0182, 0x0183 }, // LATIN CAPITAL LETTER B WITH TOPBAR + { 0x0184, 0x0185 }, // LATIN CAPITAL LETTER TONE SIX + { 0x0186, 0x0254 }, // LATIN CAPITAL LETTER OPEN O + { 0x0187, 0x0188 }, // LATIN CAPITAL LETTER C WITH HOOK + { 0x0189, 0x0256 }, // LATIN CAPITAL LETTER AFRICAN D + { 0x018A, 0x0257 }, // LATIN CAPITAL LETTER D WITH HOOK + { 0x018B, 0x018C }, // LATIN CAPITAL LETTER D WITH TOPBAR + { 0x018E, 0x01DD }, // LATIN CAPITAL LETTER REVERSED E + { 0x018F, 0x0259 }, // LATIN CAPITAL LETTER SCHWA + { 0x0190, 0x025B }, // LATIN CAPITAL LETTER OPEN E + { 0x0191, 0x0192 }, // LATIN CAPITAL LETTER F WITH HOOK + { 0x0193, 0x0260 }, // LATIN CAPITAL LETTER G WITH HOOK + { 0x0194, 0x0263 }, // LATIN CAPITAL LETTER GAMMA + { 0x0196, 0x0269 }, // LATIN CAPITAL LETTER IOTA + { 0x0197, 0x0268 }, // LATIN CAPITAL LETTER I WITH STROKE + { 0x0198, 0x0199 }, // LATIN CAPITAL LETTER K WITH HOOK + { 0x019C, 0x026F }, // LATIN CAPITAL LETTER TURNED M + { 0x019D, 0x0272 }, // LATIN CAPITAL LETTER N WITH LEFT HOOK + { 0x019F, 0x0275 }, // LATIN CAPITAL LETTER O WITH MIDDLE TILDE + { 0x01A2, 0x01A3 }, // LATIN CAPITAL LETTER OI + { 0x01A4, 0x01A5 }, // LATIN CAPITAL LETTER P WITH HOOK + { 0x01A6, 0x0280 }, // LATIN LETTER YR + { 0x01A7, 0x01A8 }, // LATIN CAPITAL LETTER TONE TWO + { 0x01A9, 0x0283 }, // LATIN CAPITAL LETTER ESH + { 0x01AC, 0x01AD }, // LATIN CAPITAL LETTER T WITH HOOK + { 0x01AE, 0x0288 }, // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK + { 0x01B1, 0x028A }, // LATIN CAPITAL LETTER UPSILON + { 0x01B2, 0x028B }, // LATIN CAPITAL LETTER V WITH HOOK + { 0x01B3, 0x01B4 }, // LATIN CAPITAL LETTER Y WITH HOOK + { 0x01B5, 0x01B6 }, // LATIN CAPITAL LETTER Z WITH STROKE + { 0x01B7, 0x0292 }, // LATIN CAPITAL LETTER EZH + { 0x01B8, 0x01B9 }, // LATIN CAPITAL LETTER EZH REVERSED + { 0x01BC, 0x01BD }, // LATIN CAPITAL LETTER TONE FIVE + { 0x01E4, 0x01E5 }, // LATIN CAPITAL LETTER G WITH STROKE + { 0x01EA, 0x01EB }, // LATIN CAPITAL LETTER O WITH OGONEK + { 0x01F6, 0x0195 }, // LATIN CAPITAL LETTER HWAIR + { 0x01F7, 0x01BF }, // LATIN CAPITAL LETTER WYNN + { 0x021C, 0x021D }, // LATIN CAPITAL LETTER YOGH + { 0x0220, 0x019E }, // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG + { 0x0222, 0x0223 }, // LATIN CAPITAL LETTER OU + { 0x0224, 0x0225 }, // LATIN CAPITAL LETTER Z WITH HOOK + { 0x0226, 0x0227 }, // LATIN CAPITAL LETTER A WITH DOT ABOVE + { 0x022E, 0x022F }, // LATIN CAPITAL LETTER O WITH DOT ABOVE + { 0x023A, 0x2C65 }, // LATIN CAPITAL LETTER A WITH STROKE + { 0x023B, 0x023C }, // LATIN CAPITAL LETTER C WITH STROKE + { 0x023D, 0x019A }, // LATIN CAPITAL LETTER L WITH BAR + { 0x023E, 0x2C66 }, // LATIN CAPITAL LETTER T WITH DIAGONAL STROKE + { 0x0241, 0x0242 }, // LATIN CAPITAL LETTER GLOTTAL STOP + { 0x0243, 0x0180 }, // LATIN CAPITAL LETTER B WITH STROKE + { 0x0244, 0x0289 }, // LATIN CAPITAL LETTER U BAR + { 0x0245, 0x028C }, // LATIN CAPITAL LETTER TURNED V + { 0x0246, 0x0247 }, // LATIN CAPITAL LETTER E WITH STROKE + { 0x0248, 0x0249 }, // LATIN CAPITAL LETTER J WITH STROKE + { 0x024A, 0x024B }, // LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL + { 0x024C, 0x024D }, // LATIN CAPITAL LETTER R WITH STROKE + { 0x024E, 0x024F }, // LATIN CAPITAL LETTER Y WITH STROKE + { 0x0370, 0x0371 }, // GREEK CAPITAL LETTER HETA + { 0x0372, 0x0373 }, // GREEK CAPITAL LETTER ARCHAIC SAMPI + { 0x0376, 0x0377 }, // GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA + { 0x0391, 0x03B1 }, // GREEK CAPITAL LETTER ALPHA + { 0x0392, 0x03B2 }, // GREEK CAPITAL LETTER BETA + { 0x0393, 0x03B3 }, // GREEK CAPITAL LETTER GAMMA + { 0x0394, 0x03B4 }, // GREEK CAPITAL LETTER DELTA + { 0x0395, 0x03B5 }, // GREEK CAPITAL LETTER EPSILON + { 0x0396, 0x03B6 }, // GREEK CAPITAL LETTER ZETA + { 0x0397, 0x03B7 }, // GREEK CAPITAL LETTER ETA + { 0x0398, 0x03B8 }, // GREEK CAPITAL LETTER THETA + { 0x0399, 0x03B9 }, // GREEK CAPITAL LETTER IOTA + { 0x039A, 0x03BA }, // GREEK CAPITAL LETTER KAPPA + { 0x039B, 0x03BB }, // GREEK CAPITAL LETTER LAMDA + { 0x039C, 0x03BC }, // GREEK CAPITAL LETTER MU + { 0x039D, 0x03BD }, // GREEK CAPITAL LETTER NU + { 0x039E, 0x03BE }, // GREEK CAPITAL LETTER XI + { 0x039F, 0x03BF }, // GREEK CAPITAL LETTER OMICRON + { 0x03A0, 0x03C0 }, // GREEK CAPITAL LETTER PI + { 0x03A1, 0x03C1 }, // GREEK CAPITAL LETTER RHO + { 0x03A3, 0x03C3 }, // GREEK CAPITAL LETTER SIGMA + { 0x03A4, 0x03C4 }, // GREEK CAPITAL LETTER TAU + { 0x03A5, 0x03C5 }, // GREEK CAPITAL LETTER UPSILON + { 0x03A6, 0x03C6 }, // GREEK CAPITAL LETTER PHI + { 0x03A7, 0x03C7 }, // GREEK CAPITAL LETTER CHI + { 0x03A8, 0x03C8 }, // GREEK CAPITAL LETTER PSI + { 0x03A9, 0x03C9 }, // GREEK CAPITAL LETTER OMEGA + { 0x03CF, 0x03D7 }, // GREEK CAPITAL KAI SYMBOL + { 0x03D8, 0x03D9 }, // GREEK LETTER ARCHAIC KOPPA + { 0x03DA, 0x03DB }, // GREEK LETTER STIGMA + { 0x03DC, 0x03DD }, // GREEK LETTER DIGAMMA + { 0x03DE, 0x03DF }, // GREEK LETTER KOPPA + { 0x03E0, 0x03E1 }, // GREEK LETTER SAMPI + { 0x03E2, 0x03E3 }, // COPTIC CAPITAL LETTER SHEI + { 0x03E4, 0x03E5 }, // COPTIC CAPITAL LETTER FEI + { 0x03E6, 0x03E7 }, // COPTIC CAPITAL LETTER KHEI + { 0x03E8, 0x03E9 }, // COPTIC CAPITAL LETTER HORI + { 0x03EA, 0x03EB }, // COPTIC CAPITAL LETTER GANGIA + { 0x03EC, 0x03ED }, // COPTIC CAPITAL LETTER SHIMA + { 0x03EE, 0x03EF }, // COPTIC CAPITAL LETTER DEI + { 0x03F7, 0x03F8 }, // GREEK CAPITAL LETTER SHO + { 0x03FA, 0x03FB }, // GREEK CAPITAL LETTER SAN + { 0x03FD, 0x037B }, // GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL + { 0x03FE, 0x037C }, // GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL + { 0x03FF, 0x037D }, // GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL + { 0x0402, 0x0452 }, // CYRILLIC CAPITAL LETTER DJE + { 0x0404, 0x0454 }, // CYRILLIC CAPITAL LETTER UKRAINIAN IE + { 0x0405, 0x0455 }, // CYRILLIC CAPITAL LETTER DZE + { 0x0406, 0x0456 }, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + { 0x0408, 0x0458 }, // CYRILLIC CAPITAL LETTER JE + { 0x0409, 0x0459 }, // CYRILLIC CAPITAL LETTER LJE + { 0x040A, 0x045A }, // CYRILLIC CAPITAL LETTER NJE + { 0x040B, 0x045B }, // CYRILLIC CAPITAL LETTER TSHE + { 0x040F, 0x045F }, // CYRILLIC CAPITAL LETTER DZHE + { 0x0410, 0x0430 }, // CYRILLIC CAPITAL LETTER A + { 0x0411, 0x0431 }, // CYRILLIC CAPITAL LETTER BE + { 0x0412, 0x0432 }, // CYRILLIC CAPITAL LETTER VE + { 0x0413, 0x0433 }, // CYRILLIC CAPITAL LETTER GHE + { 0x0414, 0x0434 }, // CYRILLIC CAPITAL LETTER DE + { 0x0415, 0x0435 }, // CYRILLIC CAPITAL LETTER IE + { 0x0416, 0x0436 }, // CYRILLIC CAPITAL LETTER ZHE + { 0x0417, 0x0437 }, // CYRILLIC CAPITAL LETTER ZE + { 0x0418, 0x0438 }, // CYRILLIC CAPITAL LETTER I + { 0x041A, 0x043A }, // CYRILLIC CAPITAL LETTER KA + { 0x041B, 0x043B }, // CYRILLIC CAPITAL LETTER EL + { 0x041C, 0x043C }, // CYRILLIC CAPITAL LETTER EM + { 0x041D, 0x043D }, // CYRILLIC CAPITAL LETTER EN + { 0x041E, 0x043E }, // CYRILLIC CAPITAL LETTER O + { 0x041F, 0x043F }, // CYRILLIC CAPITAL LETTER PE + { 0x0420, 0x0440 }, // CYRILLIC CAPITAL LETTER ER + { 0x0421, 0x0441 }, // CYRILLIC CAPITAL LETTER ES + { 0x0422, 0x0442 }, // CYRILLIC CAPITAL LETTER TE + { 0x0423, 0x0443 }, // CYRILLIC CAPITAL LETTER U + { 0x0424, 0x0444 }, // CYRILLIC CAPITAL LETTER EF + { 0x0425, 0x0445 }, // CYRILLIC CAPITAL LETTER HA + { 0x0426, 0x0446 }, // CYRILLIC CAPITAL LETTER TSE + { 0x0427, 0x0447 }, // CYRILLIC CAPITAL LETTER CHE + { 0x0428, 0x0448 }, // CYRILLIC CAPITAL LETTER SHA + { 0x0429, 0x0449 }, // CYRILLIC CAPITAL LETTER SHCHA + { 0x042A, 0x044A }, // CYRILLIC CAPITAL LETTER HARD SIGN + { 0x042B, 0x044B }, // CYRILLIC CAPITAL LETTER YERU + { 0x042C, 0x044C }, // CYRILLIC CAPITAL LETTER SOFT SIGN + { 0x042D, 0x044D }, // CYRILLIC CAPITAL LETTER E + { 0x042E, 0x044E }, // CYRILLIC CAPITAL LETTER YU + { 0x042F, 0x044F }, // CYRILLIC CAPITAL LETTER YA + { 0x0460, 0x0461 }, // CYRILLIC CAPITAL LETTER OMEGA + { 0x0462, 0x0463 }, // CYRILLIC CAPITAL LETTER YAT + { 0x0464, 0x0465 }, // CYRILLIC CAPITAL LETTER IOTIFIED E + { 0x0466, 0x0467 }, // CYRILLIC CAPITAL LETTER LITTLE YUS + { 0x0468, 0x0469 }, // CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS + { 0x046A, 0x046B }, // CYRILLIC CAPITAL LETTER BIG YUS + { 0x046C, 0x046D }, // CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS + { 0x046E, 0x046F }, // CYRILLIC CAPITAL LETTER KSI + { 0x0470, 0x0471 }, // CYRILLIC CAPITAL LETTER PSI + { 0x0472, 0x0473 }, // CYRILLIC CAPITAL LETTER FITA + { 0x0474, 0x0475 }, // CYRILLIC CAPITAL LETTER IZHITSA + { 0x0478, 0x0479 }, // CYRILLIC CAPITAL LETTER UK + { 0x047A, 0x047B }, // CYRILLIC CAPITAL LETTER ROUND OMEGA + { 0x047C, 0x047D }, // CYRILLIC CAPITAL LETTER OMEGA WITH TITLO + { 0x047E, 0x047F }, // CYRILLIC CAPITAL LETTER OT + { 0x0480, 0x0481 }, // CYRILLIC CAPITAL LETTER KOPPA + { 0x048A, 0x048B }, // CYRILLIC CAPITAL LETTER SHORT I WITH TAIL + { 0x048C, 0x048D }, // CYRILLIC CAPITAL LETTER SEMISOFT SIGN + { 0x048E, 0x048F }, // CYRILLIC CAPITAL LETTER ER WITH TICK + { 0x0490, 0x0491 }, // CYRILLIC CAPITAL LETTER GHE WITH UPTURN + { 0x0492, 0x0493 }, // CYRILLIC CAPITAL LETTER GHE WITH STROKE + { 0x0494, 0x0495 }, // CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK + { 0x0496, 0x0497 }, // CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER + { 0x0498, 0x0499 }, // CYRILLIC CAPITAL LETTER ZE WITH DESCENDER + { 0x049A, 0x049B }, // CYRILLIC CAPITAL LETTER KA WITH DESCENDER + { 0x049C, 0x049D }, // CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE + { 0x049E, 0x049F }, // CYRILLIC CAPITAL LETTER KA WITH STROKE + { 0x04A0, 0x04A1 }, // CYRILLIC CAPITAL LETTER BASHKIR KA + { 0x04A2, 0x04A3 }, // CYRILLIC CAPITAL LETTER EN WITH DESCENDER + { 0x04A4, 0x04A5 }, // CYRILLIC CAPITAL LIGATURE EN GHE + { 0x04A6, 0x04A7 }, // CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK + { 0x04A8, 0x04A9 }, // CYRILLIC CAPITAL LETTER ABKHASIAN HA + { 0x04AA, 0x04AB }, // CYRILLIC CAPITAL LETTER ES WITH DESCENDER + { 0x04AC, 0x04AD }, // CYRILLIC CAPITAL LETTER TE WITH DESCENDER + { 0x04AE, 0x04AF }, // CYRILLIC CAPITAL LETTER STRAIGHT U + { 0x04B0, 0x04B1 }, // CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE + { 0x04B2, 0x04B3 }, // CYRILLIC CAPITAL LETTER HA WITH DESCENDER + { 0x04B4, 0x04B5 }, // CYRILLIC CAPITAL LIGATURE TE TSE + { 0x04B6, 0x04B7 }, // CYRILLIC CAPITAL LETTER CHE WITH DESCENDER + { 0x04B8, 0x04B9 }, // CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE + { 0x04BA, 0x04BB }, // CYRILLIC CAPITAL LETTER SHHA + { 0x04BC, 0x04BD }, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE + { 0x04BE, 0x04BF }, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER + { 0x04C0, 0x04CF }, // CYRILLIC LETTER PALOCHKA + { 0x04C3, 0x04C4 }, // CYRILLIC CAPITAL LETTER KA WITH HOOK + { 0x04C5, 0x04C6 }, // CYRILLIC CAPITAL LETTER EL WITH TAIL + { 0x04C7, 0x04C8 }, // CYRILLIC CAPITAL LETTER EN WITH HOOK + { 0x04C9, 0x04CA }, // CYRILLIC CAPITAL LETTER EN WITH TAIL + { 0x04CB, 0x04CC }, // CYRILLIC CAPITAL LETTER KHAKASSIAN CHE + { 0x04CD, 0x04CE }, // CYRILLIC CAPITAL LETTER EM WITH TAIL + { 0x04D4, 0x04D5 }, // CYRILLIC CAPITAL LIGATURE A IE + { 0x04D8, 0x04D9 }, // CYRILLIC CAPITAL LETTER SCHWA + { 0x04E0, 0x04E1 }, // CYRILLIC CAPITAL LETTER ABKHASIAN DZE + { 0x04E8, 0x04E9 }, // CYRILLIC CAPITAL LETTER BARRED O + { 0x04F6, 0x04F7 }, // CYRILLIC CAPITAL LETTER GHE WITH DESCENDER + { 0x04FA, 0x04FB }, // CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK + { 0x04FC, 0x04FD }, // CYRILLIC CAPITAL LETTER HA WITH HOOK + { 0x04FE, 0x04FF }, // CYRILLIC CAPITAL LETTER HA WITH STROKE + { 0x0500, 0x0501 }, // CYRILLIC CAPITAL LETTER KOMI DE + { 0x0502, 0x0503 }, // CYRILLIC CAPITAL LETTER KOMI DJE + { 0x0504, 0x0505 }, // CYRILLIC CAPITAL LETTER KOMI ZJE + { 0x0506, 0x0507 }, // CYRILLIC CAPITAL LETTER KOMI DZJE + { 0x0508, 0x0509 }, // CYRILLIC CAPITAL LETTER KOMI LJE + { 0x050A, 0x050B }, // CYRILLIC CAPITAL LETTER KOMI NJE + { 0x050C, 0x050D }, // CYRILLIC CAPITAL LETTER KOMI SJE + { 0x050E, 0x050F }, // CYRILLIC CAPITAL LETTER KOMI TJE + { 0x0510, 0x0511 }, // CYRILLIC CAPITAL LETTER REVERSED ZE + { 0x0512, 0x0513 }, // CYRILLIC CAPITAL LETTER EL WITH HOOK + { 0x0514, 0x0515 }, // CYRILLIC CAPITAL LETTER LHA + { 0x0516, 0x0517 }, // CYRILLIC CAPITAL LETTER RHA + { 0x0518, 0x0519 }, // CYRILLIC CAPITAL LETTER YAE + { 0x051A, 0x051B }, // CYRILLIC CAPITAL LETTER QA + { 0x051C, 0x051D }, // CYRILLIC CAPITAL LETTER WE + { 0x051E, 0x051F }, // CYRILLIC CAPITAL LETTER ALEUT KA + { 0x0520, 0x0521 }, // CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK + { 0x0522, 0x0523 }, // CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK + { 0x0524, 0x0525 }, // CYRILLIC CAPITAL LETTER PE WITH DESCENDER + { 0x0531, 0x0561 }, // ARMENIAN CAPITAL LETTER AYB + { 0x0532, 0x0562 }, // ARMENIAN CAPITAL LETTER BEN + { 0x0533, 0x0563 }, // ARMENIAN CAPITAL LETTER GIM + { 0x0534, 0x0564 }, // ARMENIAN CAPITAL LETTER DA + { 0x0535, 0x0565 }, // ARMENIAN CAPITAL LETTER ECH + { 0x0536, 0x0566 }, // ARMENIAN CAPITAL LETTER ZA + { 0x0537, 0x0567 }, // ARMENIAN CAPITAL LETTER EH + { 0x0538, 0x0568 }, // ARMENIAN CAPITAL LETTER ET + { 0x0539, 0x0569 }, // ARMENIAN CAPITAL LETTER TO + { 0x053A, 0x056A }, // ARMENIAN CAPITAL LETTER ZHE + { 0x053B, 0x056B }, // ARMENIAN CAPITAL LETTER INI + { 0x053C, 0x056C }, // ARMENIAN CAPITAL LETTER LIWN + { 0x053D, 0x056D }, // ARMENIAN CAPITAL LETTER XEH + { 0x053E, 0x056E }, // ARMENIAN CAPITAL LETTER CA + { 0x053F, 0x056F }, // ARMENIAN CAPITAL LETTER KEN + { 0x0540, 0x0570 }, // ARMENIAN CAPITAL LETTER HO + { 0x0541, 0x0571 }, // ARMENIAN CAPITAL LETTER JA + { 0x0542, 0x0572 }, // ARMENIAN CAPITAL LETTER GHAD + { 0x0543, 0x0573 }, // ARMENIAN CAPITAL LETTER CHEH + { 0x0544, 0x0574 }, // ARMENIAN CAPITAL LETTER MEN + { 0x0545, 0x0575 }, // ARMENIAN CAPITAL LETTER YI + { 0x0546, 0x0576 }, // ARMENIAN CAPITAL LETTER NOW + { 0x0547, 0x0577 }, // ARMENIAN CAPITAL LETTER SHA + { 0x0548, 0x0578 }, // ARMENIAN CAPITAL LETTER VO + { 0x0549, 0x0579 }, // ARMENIAN CAPITAL LETTER CHA + { 0x054A, 0x057A }, // ARMENIAN CAPITAL LETTER PEH + { 0x054B, 0x057B }, // ARMENIAN CAPITAL LETTER JHEH + { 0x054C, 0x057C }, // ARMENIAN CAPITAL LETTER RA + { 0x054D, 0x057D }, // ARMENIAN CAPITAL LETTER SEH + { 0x054E, 0x057E }, // ARMENIAN CAPITAL LETTER VEW + { 0x054F, 0x057F }, // ARMENIAN CAPITAL LETTER TIWN + { 0x0550, 0x0580 }, // ARMENIAN CAPITAL LETTER REH + { 0x0551, 0x0581 }, // ARMENIAN CAPITAL LETTER CO + { 0x0552, 0x0582 }, // ARMENIAN CAPITAL LETTER YIWN + { 0x0553, 0x0583 }, // ARMENIAN CAPITAL LETTER PIWR + { 0x0554, 0x0584 }, // ARMENIAN CAPITAL LETTER KEH + { 0x0555, 0x0585 }, // ARMENIAN CAPITAL LETTER OH + { 0x0556, 0x0586 }, // ARMENIAN CAPITAL LETTER FEH + { 0x10A0, 0x2D00 }, // GEORGIAN CAPITAL LETTER AN + { 0x10A1, 0x2D01 }, // GEORGIAN CAPITAL LETTER BAN + { 0x10A2, 0x2D02 }, // GEORGIAN CAPITAL LETTER GAN + { 0x10A3, 0x2D03 }, // GEORGIAN CAPITAL LETTER DON + { 0x10A4, 0x2D04 }, // GEORGIAN CAPITAL LETTER EN + { 0x10A5, 0x2D05 }, // GEORGIAN CAPITAL LETTER VIN + { 0x10A6, 0x2D06 }, // GEORGIAN CAPITAL LETTER ZEN + { 0x10A7, 0x2D07 }, // GEORGIAN CAPITAL LETTER TAN + { 0x10A8, 0x2D08 }, // GEORGIAN CAPITAL LETTER IN + { 0x10A9, 0x2D09 }, // GEORGIAN CAPITAL LETTER KAN + { 0x10AA, 0x2D0A }, // GEORGIAN CAPITAL LETTER LAS + { 0x10AB, 0x2D0B }, // GEORGIAN CAPITAL LETTER MAN + { 0x10AC, 0x2D0C }, // GEORGIAN CAPITAL LETTER NAR + { 0x10AD, 0x2D0D }, // GEORGIAN CAPITAL LETTER ON + { 0x10AE, 0x2D0E }, // GEORGIAN CAPITAL LETTER PAR + { 0x10AF, 0x2D0F }, // GEORGIAN CAPITAL LETTER ZHAR + { 0x10B0, 0x2D10 }, // GEORGIAN CAPITAL LETTER RAE + { 0x10B1, 0x2D11 }, // GEORGIAN CAPITAL LETTER SAN + { 0x10B2, 0x2D12 }, // GEORGIAN CAPITAL LETTER TAR + { 0x10B3, 0x2D13 }, // GEORGIAN CAPITAL LETTER UN + { 0x10B4, 0x2D14 }, // GEORGIAN CAPITAL LETTER PHAR + { 0x10B5, 0x2D15 }, // GEORGIAN CAPITAL LETTER KHAR + { 0x10B6, 0x2D16 }, // GEORGIAN CAPITAL LETTER GHAN + { 0x10B7, 0x2D17 }, // GEORGIAN CAPITAL LETTER QAR + { 0x10B8, 0x2D18 }, // GEORGIAN CAPITAL LETTER SHIN + { 0x10B9, 0x2D19 }, // GEORGIAN CAPITAL LETTER CHIN + { 0x10BA, 0x2D1A }, // GEORGIAN CAPITAL LETTER CAN + { 0x10BB, 0x2D1B }, // GEORGIAN CAPITAL LETTER JIL + { 0x10BC, 0x2D1C }, // GEORGIAN CAPITAL LETTER CIL + { 0x10BD, 0x2D1D }, // GEORGIAN CAPITAL LETTER CHAR + { 0x10BE, 0x2D1E }, // GEORGIAN CAPITAL LETTER XAN + { 0x10BF, 0x2D1F }, // GEORGIAN CAPITAL LETTER JHAN + { 0x10C0, 0x2D20 }, // GEORGIAN CAPITAL LETTER HAE + { 0x10C1, 0x2D21 }, // GEORGIAN CAPITAL LETTER HE + { 0x10C2, 0x2D22 }, // GEORGIAN CAPITAL LETTER HIE + { 0x10C3, 0x2D23 }, // GEORGIAN CAPITAL LETTER WE + { 0x10C4, 0x2D24 }, // GEORGIAN CAPITAL LETTER HAR + { 0x10C5, 0x2D25 }, // GEORGIAN CAPITAL LETTER HOE + { 0x1E00, 0x1E01 }, // LATIN CAPITAL LETTER A WITH RING BELOW + { 0x1E02, 0x1E03 }, // LATIN CAPITAL LETTER B WITH DOT ABOVE + { 0x1E04, 0x1E05 }, // LATIN CAPITAL LETTER B WITH DOT BELOW + { 0x1E06, 0x1E07 }, // LATIN CAPITAL LETTER B WITH LINE BELOW + { 0x1E08, 0x1E09 }, // LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE + { 0x1E0A, 0x1E0B }, // LATIN CAPITAL LETTER D WITH DOT ABOVE + { 0x1E0C, 0x1E0D }, // LATIN CAPITAL LETTER D WITH DOT BELOW + { 0x1E0E, 0x1E0F }, // LATIN CAPITAL LETTER D WITH LINE BELOW + { 0x1E10, 0x1E11 }, // LATIN CAPITAL LETTER D WITH CEDILLA + { 0x1E12, 0x1E13 }, // LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW + { 0x1E14, 0x1E15 }, // LATIN CAPITAL LETTER E WITH MACRON AND GRAVE + { 0x1E16, 0x1E17 }, // LATIN CAPITAL LETTER E WITH MACRON AND ACUTE + { 0x1E18, 0x1E19 }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW + { 0x1E1A, 0x1E1B }, // LATIN CAPITAL LETTER E WITH TILDE BELOW + { 0x1E1C, 0x1E1D }, // LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE + { 0x1E1E, 0x1E1F }, // LATIN CAPITAL LETTER F WITH DOT ABOVE + { 0x1E20, 0x1E21 }, // LATIN CAPITAL LETTER G WITH MACRON + { 0x1E22, 0x1E23 }, // LATIN CAPITAL LETTER H WITH DOT ABOVE + { 0x1E24, 0x1E25 }, // LATIN CAPITAL LETTER H WITH DOT BELOW + { 0x1E26, 0x1E27 }, // LATIN CAPITAL LETTER H WITH DIAERESIS + { 0x1E28, 0x1E29 }, // LATIN CAPITAL LETTER H WITH CEDILLA + { 0x1E2A, 0x1E2B }, // LATIN CAPITAL LETTER H WITH BREVE BELOW + { 0x1E2C, 0x1E2D }, // LATIN CAPITAL LETTER I WITH TILDE BELOW + { 0x1E2E, 0x1E2F }, // LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE + { 0x1E30, 0x1E31 }, // LATIN CAPITAL LETTER K WITH ACUTE + { 0x1E32, 0x1E33 }, // LATIN CAPITAL LETTER K WITH DOT BELOW + { 0x1E34, 0x1E35 }, // LATIN CAPITAL LETTER K WITH LINE BELOW + { 0x1E36, 0x1E37 }, // LATIN CAPITAL LETTER L WITH DOT BELOW + { 0x1E38, 0x1E39 }, // LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON + { 0x1E3A, 0x1E3B }, // LATIN CAPITAL LETTER L WITH LINE BELOW + { 0x1E3C, 0x1E3D }, // LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW + { 0x1E3E, 0x1E3F }, // LATIN CAPITAL LETTER M WITH ACUTE + { 0x1E40, 0x1E41 }, // LATIN CAPITAL LETTER M WITH DOT ABOVE + { 0x1E42, 0x1E43 }, // LATIN CAPITAL LETTER M WITH DOT BELOW + { 0x1E44, 0x1E45 }, // LATIN CAPITAL LETTER N WITH DOT ABOVE + { 0x1E46, 0x1E47 }, // LATIN CAPITAL LETTER N WITH DOT BELOW + { 0x1E48, 0x1E49 }, // LATIN CAPITAL LETTER N WITH LINE BELOW + { 0x1E4A, 0x1E4B }, // LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW + { 0x1E4C, 0x1E4D }, // LATIN CAPITAL LETTER O WITH TILDE AND ACUTE + { 0x1E4E, 0x1E4F }, // LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS + { 0x1E50, 0x1E51 }, // LATIN CAPITAL LETTER O WITH MACRON AND GRAVE + { 0x1E52, 0x1E53 }, // LATIN CAPITAL LETTER O WITH MACRON AND ACUTE + { 0x1E54, 0x1E55 }, // LATIN CAPITAL LETTER P WITH ACUTE + { 0x1E56, 0x1E57 }, // LATIN CAPITAL LETTER P WITH DOT ABOVE + { 0x1E58, 0x1E59 }, // LATIN CAPITAL LETTER R WITH DOT ABOVE + { 0x1E5A, 0x1E5B }, // LATIN CAPITAL LETTER R WITH DOT BELOW + { 0x1E5C, 0x1E5D }, // LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON + { 0x1E5E, 0x1E5F }, // LATIN CAPITAL LETTER R WITH LINE BELOW + { 0x1E60, 0x1E61 }, // LATIN CAPITAL LETTER S WITH DOT ABOVE + { 0x1E62, 0x1E63 }, // LATIN CAPITAL LETTER S WITH DOT BELOW + { 0x1E64, 0x1E65 }, // LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE + { 0x1E66, 0x1E67 }, // LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE + { 0x1E68, 0x1E69 }, // LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE + { 0x1E6A, 0x1E6B }, // LATIN CAPITAL LETTER T WITH DOT ABOVE + { 0x1E6C, 0x1E6D }, // LATIN CAPITAL LETTER T WITH DOT BELOW + { 0x1E6E, 0x1E6F }, // LATIN CAPITAL LETTER T WITH LINE BELOW + { 0x1E70, 0x1E71 }, // LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW + { 0x1E72, 0x1E73 }, // LATIN CAPITAL LETTER U WITH DIAERESIS BELOW + { 0x1E74, 0x1E75 }, // LATIN CAPITAL LETTER U WITH TILDE BELOW + { 0x1E76, 0x1E77 }, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW + { 0x1E78, 0x1E79 }, // LATIN CAPITAL LETTER U WITH TILDE AND ACUTE + { 0x1E7A, 0x1E7B }, // LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS + { 0x1E7C, 0x1E7D }, // LATIN CAPITAL LETTER V WITH TILDE + { 0x1E7E, 0x1E7F }, // LATIN CAPITAL LETTER V WITH DOT BELOW + { 0x1E80, 0x1E81 }, // LATIN CAPITAL LETTER W WITH GRAVE + { 0x1E82, 0x1E83 }, // LATIN CAPITAL LETTER W WITH ACUTE + { 0x1E84, 0x1E85 }, // LATIN CAPITAL LETTER W WITH DIAERESIS + { 0x1E86, 0x1E87 }, // LATIN CAPITAL LETTER W WITH DOT ABOVE + { 0x1E88, 0x1E89 }, // LATIN CAPITAL LETTER W WITH DOT BELOW + { 0x1E8A, 0x1E8B }, // LATIN CAPITAL LETTER X WITH DOT ABOVE + { 0x1E8C, 0x1E8D }, // LATIN CAPITAL LETTER X WITH DIAERESIS + { 0x1E8E, 0x1E8F }, // LATIN CAPITAL LETTER Y WITH DOT ABOVE + { 0x1E90, 0x1E91 }, // LATIN CAPITAL LETTER Z WITH CIRCUMFLEX + { 0x1E92, 0x1E93 }, // LATIN CAPITAL LETTER Z WITH DOT BELOW + { 0x1E94, 0x1E95 }, // LATIN CAPITAL LETTER Z WITH LINE BELOW + { 0x1E9E, 0x00DF }, // LATIN CAPITAL LETTER SHARP S + { 0x1EA0, 0x1EA1 }, // LATIN CAPITAL LETTER A WITH DOT BELOW + { 0x1EA2, 0x1EA3 }, // LATIN CAPITAL LETTER A WITH HOOK ABOVE + { 0x1EA4, 0x1EA5 }, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE + { 0x1EA6, 0x1EA7 }, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE + { 0x1EA8, 0x1EA9 }, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE + { 0x1EAA, 0x1EAB }, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE + { 0x1EAC, 0x1EAD }, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW + { 0x1EAE, 0x1EAF }, // LATIN CAPITAL LETTER A WITH BREVE AND ACUTE + { 0x1EB0, 0x1EB1 }, // LATIN CAPITAL LETTER A WITH BREVE AND GRAVE + { 0x1EB2, 0x1EB3 }, // LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE + { 0x1EB4, 0x1EB5 }, // LATIN CAPITAL LETTER A WITH BREVE AND TILDE + { 0x1EB6, 0x1EB7 }, // LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW + { 0x1EB8, 0x1EB9 }, // LATIN CAPITAL LETTER E WITH DOT BELOW + { 0x1EBA, 0x1EBB }, // LATIN CAPITAL LETTER E WITH HOOK ABOVE + { 0x1EBC, 0x1EBD }, // LATIN CAPITAL LETTER E WITH TILDE + { 0x1EBE, 0x1EBF }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE + { 0x1EC0, 0x1EC1 }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE + { 0x1EC2, 0x1EC3 }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE + { 0x1EC4, 0x1EC5 }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE + { 0x1EC6, 0x1EC7 }, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW + { 0x1EC8, 0x1EC9 }, // LATIN CAPITAL LETTER I WITH HOOK ABOVE + { 0x1ECA, 0x1ECB }, // LATIN CAPITAL LETTER I WITH DOT BELOW + { 0x1ECC, 0x1ECD }, // LATIN CAPITAL LETTER O WITH DOT BELOW + { 0x1ECE, 0x1ECF }, // LATIN CAPITAL LETTER O WITH HOOK ABOVE + { 0x1ED0, 0x1ED1 }, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE + { 0x1ED2, 0x1ED3 }, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE + { 0x1ED4, 0x1ED5 }, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE + { 0x1ED6, 0x1ED7 }, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE + { 0x1ED8, 0x1ED9 }, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW + { 0x1EDA, 0x1EDB }, // LATIN CAPITAL LETTER O WITH HORN AND ACUTE + { 0x1EDC, 0x1EDD }, // LATIN CAPITAL LETTER O WITH HORN AND GRAVE + { 0x1EDE, 0x1EDF }, // LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE + { 0x1EE0, 0x1EE1 }, // LATIN CAPITAL LETTER O WITH HORN AND TILDE + { 0x1EE2, 0x1EE3 }, // LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW + { 0x1EE4, 0x1EE5 }, // LATIN CAPITAL LETTER U WITH DOT BELOW + { 0x1EE6, 0x1EE7 }, // LATIN CAPITAL LETTER U WITH HOOK ABOVE + { 0x1EE8, 0x1EE9 }, // LATIN CAPITAL LETTER U WITH HORN AND ACUTE + { 0x1EEA, 0x1EEB }, // LATIN CAPITAL LETTER U WITH HORN AND GRAVE + { 0x1EEC, 0x1EED }, // LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE + { 0x1EEE, 0x1EEF }, // LATIN CAPITAL LETTER U WITH HORN AND TILDE + { 0x1EF0, 0x1EF1 }, // LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW + { 0x1EF2, 0x1EF3 }, // LATIN CAPITAL LETTER Y WITH GRAVE + { 0x1EF4, 0x1EF5 }, // LATIN CAPITAL LETTER Y WITH DOT BELOW + { 0x1EF6, 0x1EF7 }, // LATIN CAPITAL LETTER Y WITH HOOK ABOVE + { 0x1EF8, 0x1EF9 }, // LATIN CAPITAL LETTER Y WITH TILDE + { 0x1EFA, 0x1EFB }, // LATIN CAPITAL LETTER MIDDLE-WELSH LL + { 0x1EFC, 0x1EFD }, // LATIN CAPITAL LETTER MIDDLE-WELSH V + { 0x1EFE, 0x1EFF }, // LATIN CAPITAL LETTER Y WITH LOOP + { 0x1F08, 0x1F00 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI + { 0x1F09, 0x1F01 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA + { 0x1F0A, 0x1F02 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA + { 0x1F0B, 0x1F03 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA + { 0x1F0C, 0x1F04 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA + { 0x1F0D, 0x1F05 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA + { 0x1F0E, 0x1F06 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI + { 0x1F0F, 0x1F07 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI + { 0x1F18, 0x1F10 }, // GREEK CAPITAL LETTER EPSILON WITH PSILI + { 0x1F19, 0x1F11 }, // GREEK CAPITAL LETTER EPSILON WITH DASIA + { 0x1F1A, 0x1F12 }, // GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA + { 0x1F1B, 0x1F13 }, // GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA + { 0x1F1C, 0x1F14 }, // GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA + { 0x1F1D, 0x1F15 }, // GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA + { 0x1F28, 0x1F20 }, // GREEK CAPITAL LETTER ETA WITH PSILI + { 0x1F29, 0x1F21 }, // GREEK CAPITAL LETTER ETA WITH DASIA + { 0x1F2A, 0x1F22 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA + { 0x1F2B, 0x1F23 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA + { 0x1F2C, 0x1F24 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA + { 0x1F2D, 0x1F25 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA + { 0x1F2E, 0x1F26 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI + { 0x1F2F, 0x1F27 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI + { 0x1F38, 0x1F30 }, // GREEK CAPITAL LETTER IOTA WITH PSILI + { 0x1F39, 0x1F31 }, // GREEK CAPITAL LETTER IOTA WITH DASIA + { 0x1F3A, 0x1F32 }, // GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA + { 0x1F3B, 0x1F33 }, // GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA + { 0x1F3C, 0x1F34 }, // GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA + { 0x1F3D, 0x1F35 }, // GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA + { 0x1F3E, 0x1F36 }, // GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI + { 0x1F3F, 0x1F37 }, // GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI + { 0x1F48, 0x1F40 }, // GREEK CAPITAL LETTER OMICRON WITH PSILI + { 0x1F49, 0x1F41 }, // GREEK CAPITAL LETTER OMICRON WITH DASIA + { 0x1F4A, 0x1F42 }, // GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA + { 0x1F4B, 0x1F43 }, // GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA + { 0x1F4C, 0x1F44 }, // GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA + { 0x1F4D, 0x1F45 }, // GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA + { 0x1F59, 0x1F51 }, // GREEK CAPITAL LETTER UPSILON WITH DASIA + { 0x1F5B, 0x1F53 }, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA + { 0x1F5D, 0x1F55 }, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA + { 0x1F5F, 0x1F57 }, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI + { 0x1F68, 0x1F60 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI + { 0x1F69, 0x1F61 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA + { 0x1F6A, 0x1F62 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA + { 0x1F6B, 0x1F63 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA + { 0x1F6C, 0x1F64 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA + { 0x1F6D, 0x1F65 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA + { 0x1F6E, 0x1F66 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI + { 0x1F6F, 0x1F67 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI + { 0x1F88, 0x1F80 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI + { 0x1F89, 0x1F81 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI + { 0x1F8A, 0x1F82 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI + { 0x1F8B, 0x1F83 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI + { 0x1F8C, 0x1F84 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI + { 0x1F8D, 0x1F85 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI + { 0x1F8E, 0x1F86 }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1F8F, 0x1F87 }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1F98, 0x1F90 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI + { 0x1F99, 0x1F91 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI + { 0x1F9A, 0x1F92 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI + { 0x1F9B, 0x1F93 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI + { 0x1F9C, 0x1F94 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI + { 0x1F9D, 0x1F95 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI + { 0x1F9E, 0x1F96 }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1F9F, 0x1F97 }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1FA8, 0x1FA0 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI + { 0x1FA9, 0x1FA1 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI + { 0x1FAA, 0x1FA2 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI + { 0x1FAB, 0x1FA3 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI + { 0x1FAC, 0x1FA4 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI + { 0x1FAD, 0x1FA5 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI + { 0x1FAE, 0x1FA6 }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1FAF, 0x1FA7 }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1FB8, 0x1FB0 }, // GREEK CAPITAL LETTER ALPHA WITH VRACHY + { 0x1FB9, 0x1FB1 }, // GREEK CAPITAL LETTER ALPHA WITH MACRON + { 0x1FBA, 0x1F70 }, // GREEK CAPITAL LETTER ALPHA WITH VARIA + { 0x1FBB, 0x1F71 }, // GREEK CAPITAL LETTER ALPHA WITH OXIA + { 0x1FBC, 0x1FB3 }, // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI + { 0x1FC8, 0x1F72 }, // GREEK CAPITAL LETTER EPSILON WITH VARIA + { 0x1FC9, 0x1F73 }, // GREEK CAPITAL LETTER EPSILON WITH OXIA + { 0x1FCA, 0x1F74 }, // GREEK CAPITAL LETTER ETA WITH VARIA + { 0x1FCB, 0x1F75 }, // GREEK CAPITAL LETTER ETA WITH OXIA + { 0x1FCC, 0x1FC3 }, // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI + { 0x1FD8, 0x1FD0 }, // GREEK CAPITAL LETTER IOTA WITH VRACHY + { 0x1FD9, 0x1FD1 }, // GREEK CAPITAL LETTER IOTA WITH MACRON + { 0x1FDA, 0x1F76 }, // GREEK CAPITAL LETTER IOTA WITH VARIA + { 0x1FDB, 0x1F77 }, // GREEK CAPITAL LETTER IOTA WITH OXIA + { 0x1FE8, 0x1FE0 }, // GREEK CAPITAL LETTER UPSILON WITH VRACHY + { 0x1FE9, 0x1FE1 }, // GREEK CAPITAL LETTER UPSILON WITH MACRON + { 0x1FEA, 0x1F7A }, // GREEK CAPITAL LETTER UPSILON WITH VARIA + { 0x1FEB, 0x1F7B }, // GREEK CAPITAL LETTER UPSILON WITH OXIA + { 0x1FEC, 0x1FE5 }, // GREEK CAPITAL LETTER RHO WITH DASIA + { 0x1FF8, 0x1F78 }, // GREEK CAPITAL LETTER OMICRON WITH VARIA + { 0x1FF9, 0x1F79 }, // GREEK CAPITAL LETTER OMICRON WITH OXIA + { 0x1FFA, 0x1F7C }, // GREEK CAPITAL LETTER OMEGA WITH VARIA + { 0x1FFB, 0x1F7D }, // GREEK CAPITAL LETTER OMEGA WITH OXIA + { 0x1FFC, 0x1FF3 }, // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI + { 0x2126, 0x03C9 }, // OHM SIGN + { 0x212A, 0x006B }, // KELVIN SIGN + { 0x212B, 0x00E5 }, // ANGSTROM SIGN + { 0x2132, 0x214E }, // TURNED CAPITAL F + { 0x2160, 0x2170 }, // ROMAN NUMERAL ONE + { 0x2161, 0x2171 }, // ROMAN NUMERAL TWO + { 0x2162, 0x2172 }, // ROMAN NUMERAL THREE + { 0x2163, 0x2173 }, // ROMAN NUMERAL FOUR + { 0x2164, 0x2174 }, // ROMAN NUMERAL FIVE + { 0x2165, 0x2175 }, // ROMAN NUMERAL SIX + { 0x2166, 0x2176 }, // ROMAN NUMERAL SEVEN + { 0x2167, 0x2177 }, // ROMAN NUMERAL EIGHT + { 0x2168, 0x2178 }, // ROMAN NUMERAL NINE + { 0x2169, 0x2179 }, // ROMAN NUMERAL TEN + { 0x216A, 0x217A }, // ROMAN NUMERAL ELEVEN + { 0x216B, 0x217B }, // ROMAN NUMERAL TWELVE + { 0x216C, 0x217C }, // ROMAN NUMERAL FIFTY + { 0x216D, 0x217D }, // ROMAN NUMERAL ONE HUNDRED + { 0x216E, 0x217E }, // ROMAN NUMERAL FIVE HUNDRED + { 0x216F, 0x217F }, // ROMAN NUMERAL ONE THOUSAND + { 0x2183, 0x2184 }, // ROMAN NUMERAL REVERSED ONE HUNDRED + { 0x24B6, 0x24D0 }, // CIRCLED LATIN CAPITAL LETTER A + { 0x24B7, 0x24D1 }, // CIRCLED LATIN CAPITAL LETTER B + { 0x24B8, 0x24D2 }, // CIRCLED LATIN CAPITAL LETTER C + { 0x24B9, 0x24D3 }, // CIRCLED LATIN CAPITAL LETTER D + { 0x24BA, 0x24D4 }, // CIRCLED LATIN CAPITAL LETTER E + { 0x24BB, 0x24D5 }, // CIRCLED LATIN CAPITAL LETTER F + { 0x24BC, 0x24D6 }, // CIRCLED LATIN CAPITAL LETTER G + { 0x24BD, 0x24D7 }, // CIRCLED LATIN CAPITAL LETTER H + { 0x24BE, 0x24D8 }, // CIRCLED LATIN CAPITAL LETTER I + { 0x24BF, 0x24D9 }, // CIRCLED LATIN CAPITAL LETTER J + { 0x24C0, 0x24DA }, // CIRCLED LATIN CAPITAL LETTER K + { 0x24C1, 0x24DB }, // CIRCLED LATIN CAPITAL LETTER L + { 0x24C2, 0x24DC }, // CIRCLED LATIN CAPITAL LETTER M + { 0x24C3, 0x24DD }, // CIRCLED LATIN CAPITAL LETTER N + { 0x24C4, 0x24DE }, // CIRCLED LATIN CAPITAL LETTER O + { 0x24C5, 0x24DF }, // CIRCLED LATIN CAPITAL LETTER P + { 0x24C6, 0x24E0 }, // CIRCLED LATIN CAPITAL LETTER Q + { 0x24C7, 0x24E1 }, // CIRCLED LATIN CAPITAL LETTER R + { 0x24C8, 0x24E2 }, // CIRCLED LATIN CAPITAL LETTER S + { 0x24C9, 0x24E3 }, // CIRCLED LATIN CAPITAL LETTER T + { 0x24CA, 0x24E4 }, // CIRCLED LATIN CAPITAL LETTER U + { 0x24CB, 0x24E5 }, // CIRCLED LATIN CAPITAL LETTER V + { 0x24CC, 0x24E6 }, // CIRCLED LATIN CAPITAL LETTER W + { 0x24CD, 0x24E7 }, // CIRCLED LATIN CAPITAL LETTER X + { 0x24CE, 0x24E8 }, // CIRCLED LATIN CAPITAL LETTER Y + { 0x24CF, 0x24E9 }, // CIRCLED LATIN CAPITAL LETTER Z + { 0x2C00, 0x2C30 }, // GLAGOLITIC CAPITAL LETTER AZU + { 0x2C01, 0x2C31 }, // GLAGOLITIC CAPITAL LETTER BUKY + { 0x2C02, 0x2C32 }, // GLAGOLITIC CAPITAL LETTER VEDE + { 0x2C03, 0x2C33 }, // GLAGOLITIC CAPITAL LETTER GLAGOLI + { 0x2C04, 0x2C34 }, // GLAGOLITIC CAPITAL LETTER DOBRO + { 0x2C05, 0x2C35 }, // GLAGOLITIC CAPITAL LETTER YESTU + { 0x2C06, 0x2C36 }, // GLAGOLITIC CAPITAL LETTER ZHIVETE + { 0x2C07, 0x2C37 }, // GLAGOLITIC CAPITAL LETTER DZELO + { 0x2C08, 0x2C38 }, // GLAGOLITIC CAPITAL LETTER ZEMLJA + { 0x2C09, 0x2C39 }, // GLAGOLITIC CAPITAL LETTER IZHE + { 0x2C0A, 0x2C3A }, // GLAGOLITIC CAPITAL LETTER INITIAL IZHE + { 0x2C0B, 0x2C3B }, // GLAGOLITIC CAPITAL LETTER I + { 0x2C0C, 0x2C3C }, // GLAGOLITIC CAPITAL LETTER DJERVI + { 0x2C0D, 0x2C3D }, // GLAGOLITIC CAPITAL LETTER KAKO + { 0x2C0E, 0x2C3E }, // GLAGOLITIC CAPITAL LETTER LJUDIJE + { 0x2C0F, 0x2C3F }, // GLAGOLITIC CAPITAL LETTER MYSLITE + { 0x2C10, 0x2C40 }, // GLAGOLITIC CAPITAL LETTER NASHI + { 0x2C11, 0x2C41 }, // GLAGOLITIC CAPITAL LETTER ONU + { 0x2C12, 0x2C42 }, // GLAGOLITIC CAPITAL LETTER POKOJI + { 0x2C13, 0x2C43 }, // GLAGOLITIC CAPITAL LETTER RITSI + { 0x2C14, 0x2C44 }, // GLAGOLITIC CAPITAL LETTER SLOVO + { 0x2C15, 0x2C45 }, // GLAGOLITIC CAPITAL LETTER TVRIDO + { 0x2C16, 0x2C46 }, // GLAGOLITIC CAPITAL LETTER UKU + { 0x2C17, 0x2C47 }, // GLAGOLITIC CAPITAL LETTER FRITU + { 0x2C18, 0x2C48 }, // GLAGOLITIC CAPITAL LETTER HERU + { 0x2C19, 0x2C49 }, // GLAGOLITIC CAPITAL LETTER OTU + { 0x2C1A, 0x2C4A }, // GLAGOLITIC CAPITAL LETTER PE + { 0x2C1B, 0x2C4B }, // GLAGOLITIC CAPITAL LETTER SHTA + { 0x2C1C, 0x2C4C }, // GLAGOLITIC CAPITAL LETTER TSI + { 0x2C1D, 0x2C4D }, // GLAGOLITIC CAPITAL LETTER CHRIVI + { 0x2C1E, 0x2C4E }, // GLAGOLITIC CAPITAL LETTER SHA + { 0x2C1F, 0x2C4F }, // GLAGOLITIC CAPITAL LETTER YERU + { 0x2C20, 0x2C50 }, // GLAGOLITIC CAPITAL LETTER YERI + { 0x2C21, 0x2C51 }, // GLAGOLITIC CAPITAL LETTER YATI + { 0x2C22, 0x2C52 }, // GLAGOLITIC CAPITAL LETTER SPIDERY HA + { 0x2C23, 0x2C53 }, // GLAGOLITIC CAPITAL LETTER YU + { 0x2C24, 0x2C54 }, // GLAGOLITIC CAPITAL LETTER SMALL YUS + { 0x2C25, 0x2C55 }, // GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL + { 0x2C26, 0x2C56 }, // GLAGOLITIC CAPITAL LETTER YO + { 0x2C27, 0x2C57 }, // GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS + { 0x2C28, 0x2C58 }, // GLAGOLITIC CAPITAL LETTER BIG YUS + { 0x2C29, 0x2C59 }, // GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS + { 0x2C2A, 0x2C5A }, // GLAGOLITIC CAPITAL LETTER FITA + { 0x2C2B, 0x2C5B }, // GLAGOLITIC CAPITAL LETTER IZHITSA + { 0x2C2C, 0x2C5C }, // GLAGOLITIC CAPITAL LETTER SHTAPIC + { 0x2C2D, 0x2C5D }, // GLAGOLITIC CAPITAL LETTER TROKUTASTI A + { 0x2C2E, 0x2C5E }, // GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE + { 0x2C60, 0x2C61 }, // LATIN CAPITAL LETTER L WITH DOUBLE BAR + { 0x2C62, 0x026B }, // LATIN CAPITAL LETTER L WITH MIDDLE TILDE + { 0x2C63, 0x1D7D }, // LATIN CAPITAL LETTER P WITH STROKE + { 0x2C64, 0x027D }, // LATIN CAPITAL LETTER R WITH TAIL + { 0x2C67, 0x2C68 }, // LATIN CAPITAL LETTER H WITH DESCENDER + { 0x2C69, 0x2C6A }, // LATIN CAPITAL LETTER K WITH DESCENDER + { 0x2C6B, 0x2C6C }, // LATIN CAPITAL LETTER Z WITH DESCENDER + { 0x2C6D, 0x0251 }, // LATIN CAPITAL LETTER ALPHA + { 0x2C6E, 0x0271 }, // LATIN CAPITAL LETTER M WITH HOOK + { 0x2C6F, 0x0250 }, // LATIN CAPITAL LETTER TURNED A + { 0x2C70, 0x0252 }, // LATIN CAPITAL LETTER TURNED ALPHA + { 0x2C72, 0x2C73 }, // LATIN CAPITAL LETTER W WITH HOOK + { 0x2C75, 0x2C76 }, // LATIN CAPITAL LETTER HALF H + { 0x2C7E, 0x023F }, // LATIN CAPITAL LETTER S WITH SWASH TAIL + { 0x2C7F, 0x0240 }, // LATIN CAPITAL LETTER Z WITH SWASH TAIL + { 0x2C80, 0x2C81 }, // COPTIC CAPITAL LETTER ALFA + { 0x2C82, 0x2C83 }, // COPTIC CAPITAL LETTER VIDA + { 0x2C84, 0x2C85 }, // COPTIC CAPITAL LETTER GAMMA + { 0x2C86, 0x2C87 }, // COPTIC CAPITAL LETTER DALDA + { 0x2C88, 0x2C89 }, // COPTIC CAPITAL LETTER EIE + { 0x2C8A, 0x2C8B }, // COPTIC CAPITAL LETTER SOU + { 0x2C8C, 0x2C8D }, // COPTIC CAPITAL LETTER ZATA + { 0x2C8E, 0x2C8F }, // COPTIC CAPITAL LETTER HATE + { 0x2C90, 0x2C91 }, // COPTIC CAPITAL LETTER THETHE + { 0x2C92, 0x2C93 }, // COPTIC CAPITAL LETTER IAUDA + { 0x2C94, 0x2C95 }, // COPTIC CAPITAL LETTER KAPA + { 0x2C96, 0x2C97 }, // COPTIC CAPITAL LETTER LAULA + { 0x2C98, 0x2C99 }, // COPTIC CAPITAL LETTER MI + { 0x2C9A, 0x2C9B }, // COPTIC CAPITAL LETTER NI + { 0x2C9C, 0x2C9D }, // COPTIC CAPITAL LETTER KSI + { 0x2C9E, 0x2C9F }, // COPTIC CAPITAL LETTER O + { 0x2CA0, 0x2CA1 }, // COPTIC CAPITAL LETTER PI + { 0x2CA2, 0x2CA3 }, // COPTIC CAPITAL LETTER RO + { 0x2CA4, 0x2CA5 }, // COPTIC CAPITAL LETTER SIMA + { 0x2CA6, 0x2CA7 }, // COPTIC CAPITAL LETTER TAU + { 0x2CA8, 0x2CA9 }, // COPTIC CAPITAL LETTER UA + { 0x2CAA, 0x2CAB }, // COPTIC CAPITAL LETTER FI + { 0x2CAC, 0x2CAD }, // COPTIC CAPITAL LETTER KHI + { 0x2CAE, 0x2CAF }, // COPTIC CAPITAL LETTER PSI + { 0x2CB0, 0x2CB1 }, // COPTIC CAPITAL LETTER OOU + { 0x2CB2, 0x2CB3 }, // COPTIC CAPITAL LETTER DIALECT-P ALEF + { 0x2CB4, 0x2CB5 }, // COPTIC CAPITAL LETTER OLD COPTIC AIN + { 0x2CB6, 0x2CB7 }, // COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE + { 0x2CB8, 0x2CB9 }, // COPTIC CAPITAL LETTER DIALECT-P KAPA + { 0x2CBA, 0x2CBB }, // COPTIC CAPITAL LETTER DIALECT-P NI + { 0x2CBC, 0x2CBD }, // COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI + { 0x2CBE, 0x2CBF }, // COPTIC CAPITAL LETTER OLD COPTIC OOU + { 0x2CC0, 0x2CC1 }, // COPTIC CAPITAL LETTER SAMPI + { 0x2CC2, 0x2CC3 }, // COPTIC CAPITAL LETTER CROSSED SHEI + { 0x2CC4, 0x2CC5 }, // COPTIC CAPITAL LETTER OLD COPTIC SHEI + { 0x2CC6, 0x2CC7 }, // COPTIC CAPITAL LETTER OLD COPTIC ESH + { 0x2CC8, 0x2CC9 }, // COPTIC CAPITAL LETTER AKHMIMIC KHEI + { 0x2CCA, 0x2CCB }, // COPTIC CAPITAL LETTER DIALECT-P HORI + { 0x2CCC, 0x2CCD }, // COPTIC CAPITAL LETTER OLD COPTIC HORI + { 0x2CCE, 0x2CCF }, // COPTIC CAPITAL LETTER OLD COPTIC HA + { 0x2CD0, 0x2CD1 }, // COPTIC CAPITAL LETTER L-SHAPED HA + { 0x2CD2, 0x2CD3 }, // COPTIC CAPITAL LETTER OLD COPTIC HEI + { 0x2CD4, 0x2CD5 }, // COPTIC CAPITAL LETTER OLD COPTIC HAT + { 0x2CD6, 0x2CD7 }, // COPTIC CAPITAL LETTER OLD COPTIC GANGIA + { 0x2CD8, 0x2CD9 }, // COPTIC CAPITAL LETTER OLD COPTIC DJA + { 0x2CDA, 0x2CDB }, // COPTIC CAPITAL LETTER OLD COPTIC SHIMA + { 0x2CDC, 0x2CDD }, // COPTIC CAPITAL LETTER OLD NUBIAN SHIMA + { 0x2CDE, 0x2CDF }, // COPTIC CAPITAL LETTER OLD NUBIAN NGI + { 0x2CE0, 0x2CE1 }, // COPTIC CAPITAL LETTER OLD NUBIAN NYI + { 0x2CE2, 0x2CE3 }, // COPTIC CAPITAL LETTER OLD NUBIAN WAU + { 0x2CEB, 0x2CEC }, // COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI + { 0x2CED, 0x2CEE }, // COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA + { 0xA640, 0xA641 }, // CYRILLIC CAPITAL LETTER ZEMLYA + { 0xA642, 0xA643 }, // CYRILLIC CAPITAL LETTER DZELO + { 0xA644, 0xA645 }, // CYRILLIC CAPITAL LETTER REVERSED DZE + { 0xA646, 0xA647 }, // CYRILLIC CAPITAL LETTER IOTA + { 0xA648, 0xA649 }, // CYRILLIC CAPITAL LETTER DJERV + { 0xA64A, 0xA64B }, // CYRILLIC CAPITAL LETTER MONOGRAPH UK + { 0xA64C, 0xA64D }, // CYRILLIC CAPITAL LETTER BROAD OMEGA + { 0xA64E, 0xA64F }, // CYRILLIC CAPITAL LETTER NEUTRAL YER + { 0xA650, 0xA651 }, // CYRILLIC CAPITAL LETTER YERU WITH BACK YER + { 0xA652, 0xA653 }, // CYRILLIC CAPITAL LETTER IOTIFIED YAT + { 0xA654, 0xA655 }, // CYRILLIC CAPITAL LETTER REVERSED YU + { 0xA656, 0xA657 }, // CYRILLIC CAPITAL LETTER IOTIFIED A + { 0xA658, 0xA659 }, // CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS + { 0xA65A, 0xA65B }, // CYRILLIC CAPITAL LETTER BLENDED YUS + { 0xA65C, 0xA65D }, // CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS + { 0xA65E, 0xA65F }, // CYRILLIC CAPITAL LETTER YN + { 0xA662, 0xA663 }, // CYRILLIC CAPITAL LETTER SOFT DE + { 0xA664, 0xA665 }, // CYRILLIC CAPITAL LETTER SOFT EL + { 0xA666, 0xA667 }, // CYRILLIC CAPITAL LETTER SOFT EM + { 0xA668, 0xA669 }, // CYRILLIC CAPITAL LETTER MONOCULAR O + { 0xA66A, 0xA66B }, // CYRILLIC CAPITAL LETTER BINOCULAR O + { 0xA66C, 0xA66D }, // CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O + { 0xA680, 0xA681 }, // CYRILLIC CAPITAL LETTER DWE + { 0xA682, 0xA683 }, // CYRILLIC CAPITAL LETTER DZWE + { 0xA684, 0xA685 }, // CYRILLIC CAPITAL LETTER ZHWE + { 0xA686, 0xA687 }, // CYRILLIC CAPITAL LETTER CCHE + { 0xA688, 0xA689 }, // CYRILLIC CAPITAL LETTER DZZE + { 0xA68A, 0xA68B }, // CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK + { 0xA68C, 0xA68D }, // CYRILLIC CAPITAL LETTER TWE + { 0xA68E, 0xA68F }, // CYRILLIC CAPITAL LETTER TSWE + { 0xA690, 0xA691 }, // CYRILLIC CAPITAL LETTER TSSE + { 0xA692, 0xA693 }, // CYRILLIC CAPITAL LETTER TCHE + { 0xA694, 0xA695 }, // CYRILLIC CAPITAL LETTER HWE + { 0xA696, 0xA697 }, // CYRILLIC CAPITAL LETTER SHWE + { 0xA722, 0xA723 }, // LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF + { 0xA724, 0xA725 }, // LATIN CAPITAL LETTER EGYPTOLOGICAL AIN + { 0xA726, 0xA727 }, // LATIN CAPITAL LETTER HENG + { 0xA728, 0xA729 }, // LATIN CAPITAL LETTER TZ + { 0xA72A, 0xA72B }, // LATIN CAPITAL LETTER TRESILLO + { 0xA72C, 0xA72D }, // LATIN CAPITAL LETTER CUATRILLO + { 0xA72E, 0xA72F }, // LATIN CAPITAL LETTER CUATRILLO WITH COMMA + { 0xA732, 0xA733 }, // LATIN CAPITAL LETTER AA + { 0xA734, 0xA735 }, // LATIN CAPITAL LETTER AO + { 0xA736, 0xA737 }, // LATIN CAPITAL LETTER AU + { 0xA738, 0xA739 }, // LATIN CAPITAL LETTER AV + { 0xA73A, 0xA73B }, // LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR + { 0xA73C, 0xA73D }, // LATIN CAPITAL LETTER AY + { 0xA73E, 0xA73F }, // LATIN CAPITAL LETTER REVERSED C WITH DOT + { 0xA740, 0xA741 }, // LATIN CAPITAL LETTER K WITH STROKE + { 0xA742, 0xA743 }, // LATIN CAPITAL LETTER K WITH DIAGONAL STROKE + { 0xA744, 0xA745 }, // LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE + { 0xA746, 0xA747 }, // LATIN CAPITAL LETTER BROKEN L + { 0xA748, 0xA749 }, // LATIN CAPITAL LETTER L WITH HIGH STROKE + { 0xA74A, 0xA74B }, // LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY + { 0xA74C, 0xA74D }, // LATIN CAPITAL LETTER O WITH LOOP + { 0xA74E, 0xA74F }, // LATIN CAPITAL LETTER OO + { 0xA750, 0xA751 }, // LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER + { 0xA752, 0xA753 }, // LATIN CAPITAL LETTER P WITH FLOURISH + { 0xA754, 0xA755 }, // LATIN CAPITAL LETTER P WITH SQUIRREL TAIL + { 0xA756, 0xA757 }, // LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER + { 0xA758, 0xA759 }, // LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE + { 0xA75A, 0xA75B }, // LATIN CAPITAL LETTER R ROTUNDA + { 0xA75C, 0xA75D }, // LATIN CAPITAL LETTER RUM ROTUNDA + { 0xA75E, 0xA75F }, // LATIN CAPITAL LETTER V WITH DIAGONAL STROKE + { 0xA760, 0xA761 }, // LATIN CAPITAL LETTER VY + { 0xA762, 0xA763 }, // LATIN CAPITAL LETTER VISIGOTHIC Z + { 0xA764, 0xA765 }, // LATIN CAPITAL LETTER THORN WITH STROKE + { 0xA766, 0xA767 }, // LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER + { 0xA768, 0xA769 }, // LATIN CAPITAL LETTER VEND + { 0xA76A, 0xA76B }, // LATIN CAPITAL LETTER ET + { 0xA76C, 0xA76D }, // LATIN CAPITAL LETTER IS + { 0xA76E, 0xA76F }, // LATIN CAPITAL LETTER CON + { 0xA779, 0xA77A }, // LATIN CAPITAL LETTER INSULAR D + { 0xA77B, 0xA77C }, // LATIN CAPITAL LETTER INSULAR F + { 0xA77D, 0x1D79 }, // LATIN CAPITAL LETTER INSULAR G + { 0xA77E, 0xA77F }, // LATIN CAPITAL LETTER TURNED INSULAR G + { 0xA780, 0xA781 }, // LATIN CAPITAL LETTER TURNED L + { 0xA782, 0xA783 }, // LATIN CAPITAL LETTER INSULAR R + { 0xA784, 0xA785 }, // LATIN CAPITAL LETTER INSULAR S + { 0xA786, 0xA787 }, // LATIN CAPITAL LETTER INSULAR T + { 0xA78B, 0xA78C }, // LATIN CAPITAL LETTER SALTILLO + { 0xFF21, 0xFF41 }, // FULLWIDTH LATIN CAPITAL LETTER A + { 0xFF22, 0xFF42 }, // FULLWIDTH LATIN CAPITAL LETTER B + { 0xFF23, 0xFF43 }, // FULLWIDTH LATIN CAPITAL LETTER C + { 0xFF24, 0xFF44 }, // FULLWIDTH LATIN CAPITAL LETTER D + { 0xFF25, 0xFF45 }, // FULLWIDTH LATIN CAPITAL LETTER E + { 0xFF26, 0xFF46 }, // FULLWIDTH LATIN CAPITAL LETTER F + { 0xFF27, 0xFF47 }, // FULLWIDTH LATIN CAPITAL LETTER G + { 0xFF28, 0xFF48 }, // FULLWIDTH LATIN CAPITAL LETTER H + { 0xFF29, 0xFF49 }, // FULLWIDTH LATIN CAPITAL LETTER I + { 0xFF2A, 0xFF4A }, // FULLWIDTH LATIN CAPITAL LETTER J + { 0xFF2B, 0xFF4B }, // FULLWIDTH LATIN CAPITAL LETTER K + { 0xFF2C, 0xFF4C }, // FULLWIDTH LATIN CAPITAL LETTER L + { 0xFF2D, 0xFF4D }, // FULLWIDTH LATIN CAPITAL LETTER M + { 0xFF2E, 0xFF4E }, // FULLWIDTH LATIN CAPITAL LETTER N + { 0xFF2F, 0xFF4F }, // FULLWIDTH LATIN CAPITAL LETTER O + { 0xFF30, 0xFF50 }, // FULLWIDTH LATIN CAPITAL LETTER P + { 0xFF31, 0xFF51 }, // FULLWIDTH LATIN CAPITAL LETTER Q + { 0xFF32, 0xFF52 }, // FULLWIDTH LATIN CAPITAL LETTER R + { 0xFF33, 0xFF53 }, // FULLWIDTH LATIN CAPITAL LETTER S + { 0xFF34, 0xFF54 }, // FULLWIDTH LATIN CAPITAL LETTER T + { 0xFF35, 0xFF55 }, // FULLWIDTH LATIN CAPITAL LETTER U + { 0xFF36, 0xFF56 }, // FULLWIDTH LATIN CAPITAL LETTER V + { 0xFF37, 0xFF57 }, // FULLWIDTH LATIN CAPITAL LETTER W + { 0xFF38, 0xFF58 }, // FULLWIDTH LATIN CAPITAL LETTER X + { 0xFF39, 0xFF59 }, // FULLWIDTH LATIN CAPITAL LETTER Y + { 0xFF3A, 0xFF5A } // FULLWIDTH LATIN CAPITAL LETTER Z +}; + +static int compare_pair_capital(const void *a, const void *b) { + return (int)(*(unsigned short *)a) + - (int)((struct LatinCapitalSmallPair*)b)->capital; +} + +unsigned short latin_tolower(unsigned short c) { + struct LatinCapitalSmallPair *p = + (struct LatinCapitalSmallPair *)bsearch(&c, SORTED_CHAR_MAP, + sizeof(SORTED_CHAR_MAP) / sizeof(SORTED_CHAR_MAP[0]), + sizeof(SORTED_CHAR_MAP[0]), + compare_pair_capital); + return p ? p->small : c; +} + +} // namespace latinime diff --git a/src/java/KP2ASoftKeyboard2/native/jni/char_utils.h b/src/java/KP2ASoftKeyboard2/native/jni/char_utils.h new file mode 100644 index 00000000..921ecb4a --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/char_utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_CHAR_UTILS_H +#define LATINIME_CHAR_UTILS_H + +namespace latinime { + +unsigned short latin_tolower(unsigned short c); + +}; // namespace latinime + +#endif // LATINIME_CHAR_UTILS_H diff --git a/src/java/KP2ASoftKeyboard2/native/jni/dictionary.cpp b/src/java/KP2ASoftKeyboard2/native/jni/dictionary.cpp new file mode 100644 index 00000000..1a39f585 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/dictionary.cpp @@ -0,0 +1,596 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +#include +//#define LOG_TAG "dictionary.cpp" +//#include +#define LOGI + +#include "dictionary.h" +#include "basechars.h" +#include "char_utils.h" + +#define DEBUG_DICT 0 +#define DICTIONARY_VERSION_MIN 200 +#define DICTIONARY_HEADER_SIZE 2 +#define NOT_VALID_WORD -99 + +namespace latinime { + +Dictionary::Dictionary(void *dict, int typedLetterMultiplier, int fullWordMultiplier) +{ + mDict = (unsigned char*) dict; + mTypedLetterMultiplier = typedLetterMultiplier; + mFullWordMultiplier = fullWordMultiplier; + getVersionNumber(); +} + +Dictionary::~Dictionary() +{ +} + +int Dictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies, + int maxWordLength, int maxWords, int maxAlternatives, int skipPos, + int *nextLetters, int nextLettersSize) +{ + int suggWords; + mFrequencies = frequencies; + mOutputChars = outWords; + mInputCodes = codes; + mInputLength = codesSize; + mMaxAlternatives = maxAlternatives; + mMaxWordLength = maxWordLength; + mMaxWords = maxWords; + mSkipPos = skipPos; + mMaxEditDistance = mInputLength < 5 ? 2 : mInputLength / 2; + mNextLettersFrequencies = nextLetters; + mNextLettersSize = nextLettersSize; + + if (checkIfDictVersionIsLatest()) { + getWordsRec(DICTIONARY_HEADER_SIZE, 0, mInputLength * 3, false, 1, 0, 0); + } else { + getWordsRec(0, 0, mInputLength * 3, false, 1, 0, 0); + } + + // Get the word count + suggWords = 0; + while (suggWords < mMaxWords && mFrequencies[suggWords] > 0) suggWords++; + if (DEBUG_DICT) LOGI("Returning %d words", suggWords); + + if (DEBUG_DICT) { + LOGI("Next letters: "); + for (int k = 0; k < nextLettersSize; k++) { + if (mNextLettersFrequencies[k] > 0) { + LOGI("%c = %d,", k, mNextLettersFrequencies[k]); + } + } + LOGI("\n"); + } + return suggWords; +} + +void +Dictionary::registerNextLetter(unsigned short c) +{ + if (c < mNextLettersSize) { + mNextLettersFrequencies[c]++; + } +} + +void +Dictionary::getVersionNumber() +{ + mVersion = (mDict[0] & 0xFF); + mBigram = (mDict[1] & 0xFF); + LOGI("IN NATIVE SUGGEST Version: %d Bigram : %d \n", mVersion, mBigram); +} + +// Checks whether it has the latest dictionary or the old dictionary +bool +Dictionary::checkIfDictVersionIsLatest() +{ + return (mVersion >= DICTIONARY_VERSION_MIN) && (mBigram == 1 || mBigram == 0); +} + +unsigned short +Dictionary::getChar(int *pos) +{ + unsigned short ch = (unsigned short) (mDict[(*pos)++] & 0xFF); + // If the code is 255, then actual 16 bit code follows (in big endian) + if (ch == 0xFF) { + ch = ((mDict[*pos] & 0xFF) << 8) | (mDict[*pos + 1] & 0xFF); + (*pos) += 2; + } + return ch; +} + +int +Dictionary::getAddress(int *pos) +{ + int address = 0; + if ((mDict[*pos] & FLAG_ADDRESS_MASK) == 0) { + *pos += 1; + } else { + address += (mDict[*pos] & (ADDRESS_MASK >> 16)) << 16; + address += (mDict[*pos + 1] & 0xFF) << 8; + address += (mDict[*pos + 2] & 0xFF); + *pos += 3; + } + return address; +} + +int +Dictionary::getFreq(int *pos) +{ + int freq = mDict[(*pos)++] & 0xFF; + + if (checkIfDictVersionIsLatest()) { + // skipping bigram + int bigramExist = (mDict[*pos] & FLAG_BIGRAM_READ); + if (bigramExist > 0) { + int nextBigramExist = 1; + while (nextBigramExist > 0) { + (*pos) += 3; + nextBigramExist = (mDict[(*pos)++] & FLAG_BIGRAM_CONTINUED); + } + } else { + (*pos)++; + } + } + + return freq; +} + +int +Dictionary::wideStrLen(unsigned short *str) +{ + if (!str) return 0; + unsigned short *end = str; + while (*end) + end++; + return end - str; +} + +bool +Dictionary::addWord(unsigned short *word, int length, int frequency) +{ + word[length] = 0; + if (DEBUG_DICT) { + char s[length + 1]; + for (int i = 0; i <= length; i++) s[i] = word[i]; + LOGI("Found word = %s, freq = %d : \n", s, frequency); + } + + // Find the right insertion point + int insertAt = 0; + while (insertAt < mMaxWords) { + if (frequency > mFrequencies[insertAt] + || (mFrequencies[insertAt] == frequency + && length < wideStrLen(mOutputChars + insertAt * mMaxWordLength))) { + break; + } + insertAt++; + } + if (insertAt < mMaxWords) { + memmove((char*) mFrequencies + (insertAt + 1) * sizeof(mFrequencies[0]), + (char*) mFrequencies + insertAt * sizeof(mFrequencies[0]), + (mMaxWords - insertAt - 1) * sizeof(mFrequencies[0])); + mFrequencies[insertAt] = frequency; + memmove((char*) mOutputChars + (insertAt + 1) * mMaxWordLength * sizeof(short), + (char*) mOutputChars + (insertAt ) * mMaxWordLength * sizeof(short), + (mMaxWords - insertAt - 1) * sizeof(short) * mMaxWordLength); + unsigned short *dest = mOutputChars + (insertAt ) * mMaxWordLength; + while (length--) { + *dest++ = *word++; + } + *dest = 0; // NULL terminate + if (DEBUG_DICT) LOGI("Added word at %d\n", insertAt); + return true; + } + return false; +} + +bool +Dictionary::addWordBigram(unsigned short *word, int length, int frequency) +{ + word[length] = 0; + if (DEBUG_DICT) { + char s[length + 1]; + for (int i = 0; i <= length; i++) s[i] = word[i]; + LOGI("Bigram: Found word = %s, freq = %d : \n", s, frequency); + } + + // Find the right insertion point + int insertAt = 0; + while (insertAt < mMaxBigrams) { + if (frequency > mBigramFreq[insertAt] + || (mBigramFreq[insertAt] == frequency + && length < wideStrLen(mBigramChars + insertAt * mMaxWordLength))) { + break; + } + insertAt++; + } + LOGI("Bigram: InsertAt -> %d maxBigrams: %d\n", insertAt, mMaxBigrams); + if (insertAt < mMaxBigrams) { + memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]), + (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]), + (mMaxBigrams - insertAt - 1) * sizeof(mBigramFreq[0])); + mBigramFreq[insertAt] = frequency; + memmove((char*) mBigramChars + (insertAt + 1) * mMaxWordLength * sizeof(short), + (char*) mBigramChars + (insertAt ) * mMaxWordLength * sizeof(short), + (mMaxBigrams - insertAt - 1) * sizeof(short) * mMaxWordLength); + unsigned short *dest = mBigramChars + (insertAt ) * mMaxWordLength; + while (length--) { + *dest++ = *word++; + } + *dest = 0; // NULL terminate + if (DEBUG_DICT) LOGI("Bigram: Added word at %d\n", insertAt); + return true; + } + return false; +} + +unsigned short +Dictionary::toLowerCase(unsigned short c) { + if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) { + c = BASE_CHARS[c]; + } + if (c >='A' && c <= 'Z') { + c |= 32; + } else if (c > 127) { + c = latin_tolower(c); + } + return c; +} + +bool +Dictionary::sameAsTyped(unsigned short *word, int length) +{ + if (length != mInputLength) { + return false; + } + int *inputCodes = mInputCodes; + while (length--) { + if ((unsigned int) *inputCodes != (unsigned int) *word) { + return false; + } + inputCodes += mMaxAlternatives; + word++; + } + return true; +} + +static char QUOTE = '\''; + +void +Dictionary::getWordsRec(int pos, int depth, int maxDepth, bool completion, int snr, int inputIndex, + int diffs) +{ + // Optimization: Prune out words that are too long compared to how much was typed. + if (depth > maxDepth) { + return; + } + if (diffs > mMaxEditDistance) { + return; + } + int count = getCount(&pos); + int *currentChars = NULL; + if (mInputLength <= inputIndex) { + completion = true; + } else { + currentChars = mInputCodes + (inputIndex * mMaxAlternatives); + } + + for (int i = 0; i < count; i++) { + // -- at char + unsigned short c = getChar(&pos); + // -- at flag/add + unsigned short lowerC = toLowerCase(c); + bool terminal = getTerminal(&pos); + int childrenAddress = getAddress(&pos); + // -- after address or flag + int freq = 1; + if (terminal) freq = getFreq(&pos); + // -- after add or freq + + // If we are only doing completions, no need to look at the typed characters. + if (completion) { + mWord[depth] = c; + if (terminal) { + addWord(mWord, depth + 1, freq * snr); + if (depth >= mInputLength && mSkipPos < 0) { + registerNextLetter(mWord[mInputLength]); + } + } + if (childrenAddress != 0) { + getWordsRec(childrenAddress, depth + 1, maxDepth, + completion, snr, inputIndex, diffs); + } + } else if ((c == QUOTE && currentChars[0] != QUOTE) || mSkipPos == depth) { + // Skip the ' or other letter and continue deeper + mWord[depth] = c; + if (childrenAddress != 0) { + getWordsRec(childrenAddress, depth + 1, maxDepth, false, snr, inputIndex, diffs); + } + } else { + int j = 0; + while (currentChars[j] > 0) { + if (currentChars[j] == lowerC || currentChars[j] == c) { + int addedWeight = j == 0 ? mTypedLetterMultiplier : 1; + mWord[depth] = c; + if (mInputLength == inputIndex + 1) { + if (terminal) { + if (//INCLUDE_TYPED_WORD_IF_VALID || + !sameAsTyped(mWord, depth + 1)) { + int finalFreq = freq * snr * addedWeight; + if (mSkipPos < 0) finalFreq *= mFullWordMultiplier; + addWord(mWord, depth + 1, finalFreq); + } + } + if (childrenAddress != 0) { + getWordsRec(childrenAddress, depth + 1, + maxDepth, true, snr * addedWeight, inputIndex + 1, + diffs + (j > 0)); + } + } else if (childrenAddress != 0) { + getWordsRec(childrenAddress, depth + 1, maxDepth, + false, snr * addedWeight, inputIndex + 1, diffs + (j > 0)); + } + } + j++; + if (mSkipPos >= 0) break; + } + } + } +} + +int +Dictionary::getBigramAddress(int *pos, bool advance) +{ + int address = 0; + + address += (mDict[*pos] & 0x3F) << 16; + address += (mDict[*pos + 1] & 0xFF) << 8; + address += (mDict[*pos + 2] & 0xFF); + + if (advance) { + *pos += 3; + } + + return address; +} + +int +Dictionary::getBigramFreq(int *pos) +{ + int freq = mDict[(*pos)++] & FLAG_BIGRAM_FREQ; + + return freq; +} + + +int +Dictionary::getBigrams(unsigned short *prevWord, int prevWordLength, int *codes, int codesSize, + unsigned short *bigramChars, int *bigramFreq, int maxWordLength, int maxBigrams, + int maxAlternatives) +{ + mBigramFreq = bigramFreq; + mBigramChars = bigramChars; + mInputCodes = codes; + mInputLength = codesSize; + mMaxWordLength = maxWordLength; + mMaxBigrams = maxBigrams; + mMaxAlternatives = maxAlternatives; + + if (mBigram == 1 && checkIfDictVersionIsLatest()) { + int pos = isValidWordRec(DICTIONARY_HEADER_SIZE, prevWord, 0, prevWordLength); + LOGI("Pos -> %d\n", pos); + if (pos < 0) { + return 0; + } + + int bigramCount = 0; + int bigramExist = (mDict[pos] & FLAG_BIGRAM_READ); + if (bigramExist > 0) { + int nextBigramExist = 1; + while (nextBigramExist > 0 && bigramCount < maxBigrams) { + int bigramAddress = getBigramAddress(&pos, true); + int frequency = (FLAG_BIGRAM_FREQ & mDict[pos]); + // search for all bigrams and store them + searchForTerminalNode(bigramAddress, frequency); + nextBigramExist = (mDict[pos++] & FLAG_BIGRAM_CONTINUED); + bigramCount++; + } + } + + return bigramCount; + } + return 0; +} + +void +Dictionary::searchForTerminalNode(int addressLookingFor, int frequency) +{ + // track word with such address and store it in an array + unsigned short word[mMaxWordLength]; + + int pos; + int followDownBranchAddress = DICTIONARY_HEADER_SIZE; + bool found = false; + char followingChar = ' '; + int depth = -1; + + while(!found) { + bool followDownAddressSearchStop = false; + bool firstAddress = true; + bool haveToSearchAll = true; + + if (depth >= 0) { + word[depth] = (unsigned short) followingChar; + } + pos = followDownBranchAddress; // pos start at count + int count = mDict[pos] & 0xFF; + LOGI("count - %d\n",count); + pos++; + for (int i = 0; i < count; i++) { + // pos at data + pos++; + // pos now at flag + if (!getFirstBitOfByte(&pos)) { // non-terminal + if (!followDownAddressSearchStop) { + int addr = getBigramAddress(&pos, false); + if (addr > addressLookingFor) { + followDownAddressSearchStop = true; + if (firstAddress) { + firstAddress = false; + haveToSearchAll = true; + } else if (!haveToSearchAll) { + break; + } + } else { + followDownBranchAddress = addr; + followingChar = (char)(0xFF & mDict[pos-1]); + if (firstAddress) { + firstAddress = false; + haveToSearchAll = false; + } + } + } + pos += 3; + } else if (getFirstBitOfByte(&pos)) { // terminal + if (addressLookingFor == (pos-1)) { // found !! + depth++; + word[depth] = (0xFF & mDict[pos-1]); + found = true; + break; + } + if (getSecondBitOfByte(&pos)) { // address + freq (4 byte) + if (!followDownAddressSearchStop) { + int addr = getBigramAddress(&pos, false); + if (addr > addressLookingFor) { + followDownAddressSearchStop = true; + if (firstAddress) { + firstAddress = false; + haveToSearchAll = true; + } else if (!haveToSearchAll) { + break; + } + } else { + followDownBranchAddress = addr; + followingChar = (char)(0xFF & mDict[pos-1]); + if (firstAddress) { + firstAddress = false; + haveToSearchAll = true; + } + } + } + pos += 4; + } else { // freq only (2 byte) + pos += 2; + } + + // skipping bigram + int bigramExist = (mDict[pos] & FLAG_BIGRAM_READ); + if (bigramExist > 0) { + int nextBigramExist = 1; + while (nextBigramExist > 0) { + pos += 3; + nextBigramExist = (mDict[pos++] & FLAG_BIGRAM_CONTINUED); + } + } else { + pos++; + } + } + } + depth++; + if (followDownBranchAddress == 0) { + LOGI("ERROR!!! Cannot find bigram!!"); + break; + } + } + if (checkFirstCharacter(word)) { + addWordBigram(word, depth, frequency); + } +} + +bool +Dictionary::checkFirstCharacter(unsigned short *word) +{ + // Checks whether this word starts with same character or neighboring characters of + // what user typed. + + int *inputCodes = mInputCodes; + int maxAlt = mMaxAlternatives; + while (maxAlt > 0) { + if ((unsigned int) *inputCodes == (unsigned int) *word) { + return true; + } + inputCodes++; + maxAlt--; + } + return false; +} + +bool +Dictionary::isValidWord(unsigned short *word, int length) +{ + if (checkIfDictVersionIsLatest()) { + return (isValidWordRec(DICTIONARY_HEADER_SIZE, word, 0, length) != NOT_VALID_WORD); + } else { + return (isValidWordRec(0, word, 0, length) != NOT_VALID_WORD); + } +} + +int +Dictionary::isValidWordRec(int pos, unsigned short *word, int offset, int length) { + // returns address of bigram data of that word + // return -99 if not found + + int count = getCount(&pos); + unsigned short currentChar = (unsigned short) word[offset]; + for (int j = 0; j < count; j++) { + unsigned short c = getChar(&pos); + int terminal = getTerminal(&pos); + int childPos = getAddress(&pos); + if (c == currentChar) { + if (offset == length - 1) { + if (terminal) { + return (pos+1); + } + } else { + if (childPos != 0) { + int t = isValidWordRec(childPos, word, offset + 1, length); + if (t > 0) { + return t; + } + } + } + } + if (terminal) { + getFreq(&pos); + } + // There could be two instances of each alphabet - upper and lower case. So continue + // looking ... + } + return NOT_VALID_WORD; +} + + +} // namespace latinime diff --git a/src/java/KP2ASoftKeyboard2/native/jni/dictionary.h b/src/java/KP2ASoftKeyboard2/native/jni/dictionary.h new file mode 100644 index 00000000..d13496e0 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/dictionary.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_DICTIONARY_H +#define LATINIME_DICTIONARY_H + +namespace latinime { + +// 22-bit address = ~4MB dictionary size limit, which on average would be about 200k-300k words +#define ADDRESS_MASK 0x3FFFFF + +// The bit that decides if an address follows in the next 22 bits +#define FLAG_ADDRESS_MASK 0x40 +// The bit that decides if this is a terminal node for a word. The node could still have children, +// if the word has other endings. +#define FLAG_TERMINAL_MASK 0x80 + +#define FLAG_BIGRAM_READ 0x80 +#define FLAG_BIGRAM_CHILDEXIST 0x40 +#define FLAG_BIGRAM_CONTINUED 0x80 +#define FLAG_BIGRAM_FREQ 0x7F + +class Dictionary { +public: + Dictionary(void *dict, int typedLetterMultipler, int fullWordMultiplier); + int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies, + int maxWordLength, int maxWords, int maxAlternatives, int skipPos, + int *nextLetters, int nextLettersSize); + int getBigrams(unsigned short *word, int length, int *codes, int codesSize, + unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams, + int maxAlternatives); + bool isValidWord(unsigned short *word, int length); + void setAsset(void *asset) { mAsset = asset; } + void *getAsset() { return mAsset; } + ~Dictionary(); + +private: + + void getVersionNumber(); + bool checkIfDictVersionIsLatest(); + int getAddress(int *pos); + int getBigramAddress(int *pos, bool advance); + int getFreq(int *pos); + int getBigramFreq(int *pos); + void searchForTerminalNode(int address, int frequency); + + bool getFirstBitOfByte(int *pos) { return (mDict[*pos] & 0x80) > 0; } + bool getSecondBitOfByte(int *pos) { return (mDict[*pos] & 0x40) > 0; } + bool getTerminal(int *pos) { return (mDict[*pos] & FLAG_TERMINAL_MASK) > 0; } + int getCount(int *pos) { return mDict[(*pos)++] & 0xFF; } + unsigned short getChar(int *pos); + int wideStrLen(unsigned short *str); + + bool sameAsTyped(unsigned short *word, int length); + bool checkFirstCharacter(unsigned short *word); + bool addWord(unsigned short *word, int length, int frequency); + bool addWordBigram(unsigned short *word, int length, int frequency); + unsigned short toLowerCase(unsigned short c); + void getWordsRec(int pos, int depth, int maxDepth, bool completion, int frequency, + int inputIndex, int diffs); + int isValidWordRec(int pos, unsigned short *word, int offset, int length); + void registerNextLetter(unsigned short c); + + unsigned char *mDict; + void *mAsset; + + int *mFrequencies; + int *mBigramFreq; + int mMaxWords; + int mMaxBigrams; + int mMaxWordLength; + unsigned short *mOutputChars; + unsigned short *mBigramChars; + int *mInputCodes; + int mInputLength; + int mMaxAlternatives; + unsigned short mWord[128]; + int mSkipPos; + int mMaxEditDistance; + + int mFullWordMultiplier; + int mTypedLetterMultiplier; + int *mNextLettersFrequencies; + int mNextLettersSize; + int mVersion; + int mBigram; +}; + +// ---------------------------------------------------------------------------- + +}; // namespace latinime + +#endif // LATINIME_DICTIONARY_H diff --git a/src/java/KP2ASoftKeyboard2/native/jni/keepass2android_softkeyboard_BinaryDictionary.cpp b/src/java/KP2ASoftKeyboard2/native/jni/keepass2android_softkeyboard_BinaryDictionary.cpp new file mode 100644 index 00000000..e5799130 --- /dev/null +++ b/src/java/KP2ASoftKeyboard2/native/jni/keepass2android_softkeyboard_BinaryDictionary.cpp @@ -0,0 +1,191 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +#include + +#include +#include "dictionary.h" + +// ---------------------------------------------------------------------------- + +using namespace latinime; + +// +// helper function to throw an exception +// +static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) +{ + if (jclass cls = env->FindClass(ex)) { + char msg[1000]; + sprintf(msg, fmt, data); + env->ThrowNew(cls, msg); + env->DeleteLocalRef(cls); + } +} + +static jint latinime_BinaryDictionary_open + (JNIEnv *env, jobject object, jobject dictDirectBuffer, + jint typedLetterMultiplier, jint fullWordMultiplier) +{ + void *dict = env->GetDirectBufferAddress(dictDirectBuffer); + if (dict == NULL) { + fprintf(stderr, "DICT: Dictionary buffer is null\n"); + return 0; + } + Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier); + return (jint) dictionary; +} + +static int latinime_BinaryDictionary_getSuggestions( + JNIEnv *env, jobject object, jint dict, jintArray inputArray, jint arraySize, + jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxWords, + jint maxAlternatives, jint skipPos, jintArray nextLettersArray, jint nextLettersSize) +{ + Dictionary *dictionary = (Dictionary*) dict; + if (dictionary == NULL) return 0; + + int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); + int *inputCodes = env->GetIntArrayElements(inputArray, NULL); + jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); + int *nextLetters = nextLettersArray != NULL ? env->GetIntArrayElements(nextLettersArray, NULL) + : NULL; + + int count = dictionary->getSuggestions(inputCodes, arraySize, (unsigned short*) outputChars, + frequencies, maxWordLength, maxWords, maxAlternatives, skipPos, nextLetters, + nextLettersSize); + + env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); + env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); + env->ReleaseCharArrayElements(outputArray, outputChars, 0); + if (nextLetters) { + env->ReleaseIntArrayElements(nextLettersArray, nextLetters, 0); + } + + return count; +} + +static int latinime_BinaryDictionary_getBigrams + (JNIEnv *env, jobject object, jint dict, jcharArray prevWordArray, jint prevWordLength, + jintArray inputArray, jint inputArraySize, jcharArray outputArray, + jintArray frequencyArray, jint maxWordLength, jint maxBigrams, jint maxAlternatives) +{ + Dictionary *dictionary = (Dictionary*) dict; + if (dictionary == NULL) return 0; + + jchar *prevWord = env->GetCharArrayElements(prevWordArray, NULL); + int *inputCodes = env->GetIntArrayElements(inputArray, NULL); + jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); + int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); + + int count = dictionary->getBigrams((unsigned short*) prevWord, prevWordLength, inputCodes, + inputArraySize, (unsigned short*) outputChars, frequencies, maxWordLength, maxBigrams, + maxAlternatives); + + env->ReleaseCharArrayElements(prevWordArray, prevWord, JNI_ABORT); + env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); + env->ReleaseCharArrayElements(outputArray, outputChars, 0); + env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); + + return count; +} + + +static jboolean latinime_BinaryDictionary_isValidWord + (JNIEnv *env, jobject object, jint dict, jcharArray wordArray, jint wordLength) +{ + Dictionary *dictionary = (Dictionary*) dict; + if (dictionary == NULL) return (jboolean) false; + + jchar *word = env->GetCharArrayElements(wordArray, NULL); + jboolean result = dictionary->isValidWord((unsigned short*) word, wordLength); + env->ReleaseCharArrayElements(wordArray, word, JNI_ABORT); + + return result; +} + +static void latinime_BinaryDictionary_close + (JNIEnv *env, jobject object, jint dict) +{ + Dictionary *dictionary = (Dictionary*) dict; + delete (Dictionary*) dict; +} + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gMethods[] = { + {"openNative", "(Ljava/nio/ByteBuffer;II)I", + (void*)latinime_BinaryDictionary_open}, + {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close}, + {"getSuggestionsNative", "(I[II[C[IIIII[II)I", (void*)latinime_BinaryDictionary_getSuggestions}, + {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, + {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams} +}; + +static int registerNativeMethods(JNIEnv* env, const char* className, + JNINativeMethod* gMethods, int numMethods) +{ + jclass clazz; + + clazz = env->FindClass(className); + if (clazz == NULL) { + fprintf(stderr, + "Native registration unable to find class '%s'\n", className); + return JNI_FALSE; + } + if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { + fprintf(stderr, "RegisterNatives failed for '%s'\n", className); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static int registerNatives(JNIEnv *env) +{ + const char* const kClassPathName = "keepass2android/softkeyboard/BinaryDictionary"; + return registerNativeMethods(env, + kClassPathName, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); +} + +/* + * Returns the JNI version on success, -1 on failure. + */ +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + fprintf(stderr, "ERROR: GetEnv failed\n"); + goto bail; + } + assert(env != NULL); + + if (!registerNatives(env)) { + fprintf(stderr, "ERROR: BinaryDictionary native registration failed\n"); + goto bail; + } + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + return result; +}