fix(输入法): 消除RTOS和Android文字键盘间距

这个提交包含在:
sydxky 于 2026-11-14 17:38:11 +08:00 提交
1 父节点 87aa966a51
当前提交 bce6f8083b
27 个文件已更改
+259 -106

没有与搜索条件相匹配的文件

+46 -36
查看文件
@@ -1,36 +1,30 @@
{ {
"project": "蟹蟹输入 RTOS / Android手表适配改版", "project": "蟹蟹输入 RTOS / Android手表适配改版",
"version": "1.2.0", "version": "1.2.2",
"license": "MIT", "license": "MIT",
"android": true, "android": true,
"independent_history": true, "independent_history": true,
"sensitive_findings": [], "sensitive_findings": [],
"files": { "files": {
".gitattributes": "8e689518e5810501eb34583fa369475902805d8dd6c3ea78699469de4fa22932",
".gitignore": "cf35fe4d5c1c2ca6ae6bd343642fee3d04cd8d3799510a02ca94df73a2d4daad", ".gitignore": "cf35fe4d5c1c2ca6ae6bd343642fee3d04cd8d3799510a02ca94df73a2d4daad",
"LICENSE": "4f3547e23d7fd227a33aaa6a075185be8299403b03e534627bbb3bc3bdcf97af",
"NOTICE.md": "eb75c7be9055410bec57688b363be4761c2ee6f2ae4cfba4ab908d0b9ce68999",
"README.md": "e7d8def19bd47065776b4f9fe772585aa4a98212a1884d4f6c0efb849cfabd5c",
"android/.gitignore": "9907f78ab6ad68ac162f15ed5554c0ea9bafecf6eb25f2388ba0c11d40fab35d", "android/.gitignore": "9907f78ab6ad68ac162f15ed5554c0ea9bafecf6eb25f2388ba0c11d40fab35d",
"android/LICENSE": "4f3547e23d7fd227a33aaa6a075185be8299403b03e534627bbb3bc3bdcf97af", "android/app/build.gradle": "c87ab8f2b5fd4dee8faa613d9f82fbae92d3a4496d9a54eae6980d2380546784",
"android/NOTICE.md": "bba74020843ad841f979d346d13625e26a2cb1c0e9a2031f1a45e62957f132ab",
"android/README.md": "6457b0ef705b4dcaa7fc7d50e98462d48986aaef373f00ef4178abde74f12661",
"android/VALIDATION_1.2.0.md": "7ce04837f631f9e491ecfb96e8e056c4b01c4aa2f24a061d540c5280201848e6",
"android/app/build.gradle": "c6515cb16458dafba126be6c67c65ee2814da542359edf2a5fe69baf8e6fe919",
"android/app/proguard-rules.pro": "41e72ccc70b31f2da13fc597d5196590ec25e0422c2766e1555f3348d64ac6ed", "android/app/proguard-rules.pro": "41e72ccc70b31f2da13fc597d5196590ec25e0422c2766e1555f3348d64ac6ed",
"android/app/proguard-test.pro": "dc5f87f1ec90eb24823174f80d19e93d3e69919af70891529e4c54a744988aa4", "android/app/proguard-test.pro": "dc5f87f1ec90eb24823174f80d19e93d3e69919af70891529e4c54a744988aa4",
"android/app/src/androidTest/java/com/sydxky/crabinput/ImeDeviceTest.java": "1d7e8eff090e77212aa465bcc97df8698444ace92d85094cb878a3a2d286c8e6", "android/app/src/androidTest/java/com/sydxky/crabinput/ImeDeviceTest.java": "d5a7284b6693ee116a9e5450b4c0e38df2a71812c79664ee04311d8088db33ac",
"android/app/src/main/AndroidManifest.xml": "cd096a1f1bd560114c865260bbdc50f43971089598968b065581cf07f1dbee69", "android/app/src/main/AndroidManifest.xml": "cd096a1f1bd560114c865260bbdc50f43971089598968b065581cf07f1dbee69",
"android/app/src/main/java/com/sydxky/crabinput/MainActivity.java": "ee17c3d9f20509f382a9d2d9475d4dbddd7b57cea690bd6577a396b174400b7f", "android/app/src/main/java/com/sydxky/crabinput/MainActivity.java": "ee17c3d9f20509f382a9d2d9475d4dbddd7b57cea690bd6577a396b174400b7f",
"android/app/src/main/res/drawable/ic_launcher.xml": "9f22878890b584bb6151223cc280e542f82f354cc69e1d47f2dc6093a606c071", "android/app/src/main/res/drawable/ic_launcher.xml": "9f22878890b584bb6151223cc280e542f82f354cc69e1d47f2dc6093a606c071",
"android/app/src/main/res/values/styles.xml": "37c2bd1bbf1017e84448c0177f8999fd44f5cbca8c0afde5478594dc7be55279", "android/app/src/main/res/values/styles.xml": "37c2bd1bbf1017e84448c0177f8999fd44f5cbca8c0afde5478594dc7be55279",
"android/build.gradle": "79f56a485c696a3b800776255c37729515464340f568bf5163e5f81b60086198", "android/build.gradle": "79f56a485c696a3b800776255c37729515464340f568bf5163e5f81b60086198",
"android/build.ps1": "3dc3c31675d3cf946f1cfce6d6e2a17493416be9fce4565cdcc78515345006b5", "android/build.ps1": "3dc3c31675d3cf946f1cfce6d6e2a17493416be9fce4565cdcc78515345006b5",
"android/gradle.properties": "1a62f4c0a2a08044c706c378451342a11b307842b6b2ad434a86d6f970acc201",
"android/gradle/wrapper/gradle-wrapper.jar": "e996d452d2645e70c01c11143ca2d3742734a28da2bf61f25c82bdc288c9e637", "android/gradle/wrapper/gradle-wrapper.jar": "e996d452d2645e70c01c11143ca2d3742734a28da2bf61f25c82bdc288c9e637",
"android/gradle/wrapper/gradle-wrapper.properties": "f22c1dc156f94b33fa7706633e18a7ea6e87038bfc8ac0f6f4785cb1511700f0", "android/gradle/wrapper/gradle-wrapper.properties": "f22c1dc156f94b33fa7706633e18a7ea6e87038bfc8ac0f6f4785cb1511700f0",
"android/gradle.properties": "1a62f4c0a2a08044c706c378451342a11b307842b6b2ad434a86d6f970acc201",
"android/gradlew": "80a4c62723bb67cbabe92c37606d380089c647184afa1bf2b8c136f0e15d2cd6", "android/gradlew": "80a4c62723bb67cbabe92c37606d380089c647184afa1bf2b8c136f0e15d2cd6",
"android/gradlew.bat": "0e82fa239f8f4dca4efc83863c16c3b143cb6faab6f50cbefab4ee0bd03e5b5f", "android/gradlew.bat": "0e82fa239f8f4dca4efc83863c16c3b143cb6faab6f50cbefab4ee0bd03e5b5f",
"android/host/build.gradle": "6a47b08a172355e6e3a162b1b49617363bbc85db1c8b259d4f5a2d9279fcf484", "android/host/build.gradle": "56d136fa6600a94cbcb3eaca1c9a8ce68451b3500aef386af2d5783307f808f5",
"android/host/src/main/AndroidManifest.xml": "2013ca2761bc091216dca86d6b14987147e169902c4e784a2a047d473a7c6c95", "android/host/src/main/AndroidManifest.xml": "2013ca2761bc091216dca86d6b14987147e169902c4e784a2a047d473a7c6c95",
"android/host/src/main/java/com/sydxky/crabinput/host/HostActivity.java": "0b73b7b5b6286e0a00636a13ec14b81efe37898d68d8f89cd74db266aa34da83", "android/host/src/main/java/com/sydxky/crabinput/host/HostActivity.java": "0b73b7b5b6286e0a00636a13ec14b81efe37898d68d8f89cd74db266aa34da83",
"android/keyboard/build.gradle": "e0c80feef0b7434ed4fa9889c5d2fbd373aa1634f9ef63229e98e7aed4df8d36", "android/keyboard/build.gradle": "e0c80feef0b7434ed4fa9889c5d2fbd373aa1634f9ef63229e98e7aed4df8d36",
@@ -39,22 +33,27 @@
"android/keyboard/src/main/assets/dictionary-manifest.json": "2b3d4d5564164700b46729394bfbd94349ee4a2cc949f608ec87446a7c613da3", "android/keyboard/src/main/assets/dictionary-manifest.json": "2b3d4d5564164700b46729394bfbd94349ee4a2cc949f608ec87446a7c613da3",
"android/keyboard/src/main/assets/licenses/CrabInput-LICENSE": "027e84ad11fd2992040da0aad2ece7a74fdf61540dc2d74cc8a281fd76eb942c", "android/keyboard/src/main/assets/licenses/CrabInput-LICENSE": "027e84ad11fd2992040da0aad2ece7a74fdf61540dc2d74cc8a281fd76eb942c",
"android/keyboard/src/main/assets/licenses/CrabInput-NOTICE.txt": "bba74020843ad841f979d346d13625e26a2cb1c0e9a2031f1a45e62957f132ab", "android/keyboard/src/main/assets/licenses/CrabInput-NOTICE.txt": "bba74020843ad841f979d346d13625e26a2cb1c0e9a2031f1a45e62957f132ab",
"android/keyboard/src/main/assets/licenses/Gradle-LICENSE.txt": "cf234c4188d773406f640bf89be680d9288f40ff96901c70d643fcea96ad46df",
"android/keyboard/src/main/assets/licenses/crabKeyboard-LICENSE.txt": "b140337f94481310f35abfd2210fde308ba30411899095fd961a77b94e022775", "android/keyboard/src/main/assets/licenses/crabKeyboard-LICENSE.txt": "b140337f94481310f35abfd2210fde308ba30411899095fd961a77b94e022775",
"android/keyboard/src/main/assets/licenses/Gradle-LICENSE.txt": "cf234c4188d773406f640bf89be680d9288f40ff96901c70d643fcea96ad46df",
"android/keyboard/src/main/assets/licenses/jieba-LICENSE.txt": "18ba0984839f85853b29fadaf992f7dba8fd0ca0fbeae34de2b8735222dc7a37", "android/keyboard/src/main/assets/licenses/jieba-LICENSE.txt": "18ba0984839f85853b29fadaf992f7dba8fd0ca0fbeae34de2b8735222dc7a37",
"android/keyboard/src/main/java/com/sydxky/crabinput/Candidate.java": "9b14e96b13150b5ced15188d0eb1b6e09939f8c2c4affc8aa52147aebacf0415", "android/keyboard/src/main/java/com/sydxky/crabinput/Candidate.java": "9b14e96b13150b5ced15188d0eb1b6e09939f8c2c4affc8aa52147aebacf0415",
"android/keyboard/src/main/java/com/sydxky/crabinput/CandidatePager.java": "a5071ddec3cee9899b80181ef1f35c6896cdd1455df37839b600a33c29ea640e", "android/keyboard/src/main/java/com/sydxky/crabinput/CandidatePager.java": "a5071ddec3cee9899b80181ef1f35c6896cdd1455df37839b600a33c29ea640e",
"android/keyboard/src/main/java/com/sydxky/crabinput/CrabKeyboard.java": "1f03cda3833ba282d12eaf66ddcbb5f4354bb8b99a1d2c9de1b4f430c9effcac", "android/keyboard/src/main/java/com/sydxky/crabinput/CrabKeyboard.java": "1f03cda3833ba282d12eaf66ddcbb5f4354bb8b99a1d2c9de1b4f430c9effcac",
"android/keyboard/src/main/java/com/sydxky/crabinput/KeyboardController.java": "014dcf83e2d1982299558204893cbd444db424ada4c2b2216585a46e7eaab47d", "android/keyboard/src/main/java/com/sydxky/crabinput/KeyboardController.java": "014dcf83e2d1982299558204893cbd444db424ada4c2b2216585a46e7eaab47d",
"android/keyboard/src/main/java/com/sydxky/crabinput/KeyboardState.java": "d11bc8a3ce09980eee77a4258a858ff0c38292ce55900f00d29afb20f2fd7715", "android/keyboard/src/main/java/com/sydxky/crabinput/KeyboardState.java": "d11bc8a3ce09980eee77a4258a858ff0c38292ce55900f00d29afb20f2fd7715",
"android/keyboard/src/main/java/com/sydxky/crabinput/KeyboardSurface.java": "30820264a67e5294afe188349ac78a8e61ead4c1d0e68d353585c61cb359967e", "android/keyboard/src/main/java/com/sydxky/crabinput/KeyboardSurface.java": "75fcfd7d96b8d34445d233144063893d331abe0cc1fb0b9debf9866a461e4d22",
"android/keyboard/src/main/java/com/sydxky/crabinput/Lexicon.java": "9c21767b579f6f0436175d29bb2c2244958e214d76a1b6e43ccf986dee4c7f02", "android/keyboard/src/main/java/com/sydxky/crabinput/Lexicon.java": "9c21767b579f6f0436175d29bb2c2244958e214d76a1b6e43ccf986dee4c7f02",
"android/keyboard/src/test/java/com/sydxky/crabinput/CandidatePagerTest.java": "7c0447f5eebea944df38179aafd789c4f2eae25ba53aff5ba9e92a2d46044c64", "android/keyboard/src/test/java/com/sydxky/crabinput/CandidatePagerTest.java": "7c0447f5eebea944df38179aafd789c4f2eae25ba53aff5ba9e92a2d46044c64",
"android/LICENSE": "4f3547e23d7fd227a33aaa6a075185be8299403b03e534627bbb3bc3bdcf97af",
"android/NOTICE.md": "bba74020843ad841f979d346d13625e26a2cb1c0e9a2031f1a45e62957f132ab",
"android/README.md": "f559f361489b20cc33cdbbb7e9930a9b13c2f0f8afc57508e7f9040b3ab0b76c",
"android/scripts/build-dictionary.py": "a8c29b57e42e53c5cc1e5ca6471db2ee19892db424701b1ae1cd523d2dfd0e62", "android/scripts/build-dictionary.py": "a8c29b57e42e53c5cc1e5ca6471db2ee19892db424701b1ae1cd523d2dfd0e62",
"android/scripts/capture-device.py": "34023ff4fb0ff80a8811b1222aad3b58c70b628333edb56efffa3e6adaf05ace", "android/scripts/capture-device.py": "34023ff4fb0ff80a8811b1222aad3b58c70b628333edb56efffa3e6adaf05ace",
"android/scripts/validate-device.py": "cd3fd2d6455eba4c560612a157678d374d43005bc8e8329fd3a206e21d087cd0", "android/scripts/validate-device.py": "f07227f15c8779666cc59ad0f598f286714e5251d59ec506b594348cf3622fb9",
"android/settings.gradle": "73a5f1e8c25c44b0c5f983ed822c4256dea33b14b8d53115ed3be118aeaaee1d", "android/settings.gradle": "73a5f1e8c25c44b0c5f983ed822c4256dea33b14b8d53115ed3be118aeaaee1d",
"build-rtos-game.ps1": "069ebe54e3f0563ef26eca1cfa9e3552c61f50f02704b57bc513c5829ced7d8b", "android/VALIDATION_1.2.0.md": "7ce04837f631f9e491ecfb96e8e056c4b01c4aa2f24a061d540c5280201848e6",
"android/VALIDATION_1.2.2.md": "6d3ebe3f107099516d2dbcae025e41d516ba8d4de4a40fc9af3342ba9ac9d345",
"build-rtos-game.ps1": "a0cf9d6fa5ba1ecc22e768373dcca2f87e1e58fc44f0a612b59c7215fb064df8",
"com.sydxky.rtos.imefixture/build.ps1": "37cd2f3af83d9c1cb2f1d855d0d95cf2e822ac9e743c8370237c48c4a4d8c0a0", "com.sydxky.rtos.imefixture/build.ps1": "37cd2f3af83d9c1cb2f1d855d0d95cf2e822ac9e743c8370237c48c4a4d8c0a0",
"com.sydxky.rtos.imefixture/glyphix.config.js": "d53b4b0e8597d9f7fb5fd3d53063d285b245669021527a1bfc3bc054c5122514", "com.sydxky.rtos.imefixture/glyphix.config.js": "d53b4b0e8597d9f7fb5fd3d53063d285b245669021527a1bfc3bc054c5122514",
"com.sydxky.rtos.imefixture/src/app.js": "abde5172a3f0254b611346598b6f9ce9e15a01ffcf6d770ce9e5fe095a781334", "com.sydxky.rtos.imefixture/src/app.js": "abde5172a3f0254b611346598b6f9ce9e15a01ffcf6d770ce9e5fe095a781334",
@@ -62,23 +61,20 @@
"com.sydxky.rtos.imefixture/src/main/index.ux": "7a38495cbc36f6ce23dcf45ac7ddbce70c92246749e4963efddbfb2aa9ebe269", "com.sydxky.rtos.imefixture/src/main/index.ux": "7a38495cbc36f6ce23dcf45ac7ddbce70c92246749e4963efddbfb2aa9ebe269",
"com.sydxky.rtos.imefixture/src/manifest.json": "3d6ba4288a0653bc8db541ca03999240bc99ece9ea1d056b7ad8cf46a6039bbf", "com.sydxky.rtos.imefixture/src/manifest.json": "3d6ba4288a0653bc8db541ca03999240bc99ece9ea1d056b7ad8cf46a6039bbf",
"com.sydxky.rtos.inputmethod/.gitignore": "0f139de1ca71ff6aa1e6f02974b5e38d219d7781d4184d524845dce12d947454", "com.sydxky.rtos.inputmethod/.gitignore": "0f139de1ca71ff6aa1e6f02974b5e38d219d7781d4184d524845dce12d947454",
"com.sydxky.rtos.inputmethod/build.ps1": "32168e753699f48274fe2492e53b7285e4b62c15dc928f3aeb366a11150ebf5a",
"com.sydxky.rtos.inputmethod/DESIGN.md": "ea248cc86069dceaf51c834935a8233501f6855aeaff6e89f432357c17ec5848", "com.sydxky.rtos.inputmethod/DESIGN.md": "ea248cc86069dceaf51c834935a8233501f6855aeaff6e89f432357c17ec5848",
"com.sydxky.rtos.inputmethod/glyphix.config.js": "43beae1f2a61eed010149ae6ad77223ba084117ea5aee3cb3fcd48bfc0a4a32b",
"com.sydxky.rtos.inputmethod/KEYBOARD_14.md": "27ae1fa73dd8fa8fce70743fa1e418b4a4ff71ba610e735f009344896adfa754", "com.sydxky.rtos.inputmethod/KEYBOARD_14.md": "27ae1fa73dd8fa8fce70743fa1e418b4a4ff71ba610e735f009344896adfa754",
"com.sydxky.rtos.inputmethod/LICENSE": "4f3547e23d7fd227a33aaa6a075185be8299403b03e534627bbb3bc3bdcf97af", "com.sydxky.rtos.inputmethod/LICENSE": "4f3547e23d7fd227a33aaa6a075185be8299403b03e534627bbb3bc3bdcf97af",
"com.sydxky.rtos.inputmethod/NOTICE.md": "eb75c7be9055410bec57688b363be4761c2ee6f2ae4cfba4ab908d0b9ce68999", "com.sydxky.rtos.inputmethod/NOTICE.md": "eb75c7be9055410bec57688b363be4761c2ee6f2ae4cfba4ab908d0b9ce68999",
"com.sydxky.rtos.inputmethod/PRIVACY.md": "c3062d8434db2fad3b6824cf2c41561a0bf6ae05e62f05d7c6316efd64d74af9", "com.sydxky.rtos.inputmethod/PRIVACY.md": "c3062d8434db2fad3b6824cf2c41561a0bf6ae05e62f05d7c6316efd64d74af9",
"com.sydxky.rtos.inputmethod/README.md": "8ffdcdd0bcf669908da59615f98208cca2807f6c6f8b28499d332c5130aa477b", "com.sydxky.rtos.inputmethod/README.md": "a22425e93ad54ffa426a35883035bc70284e7f066b7c8eb452d403f0dec9d35b",
"com.sydxky.rtos.inputmethod/VALIDATION_1.1.0.md": "3b7346853bf6679c4efeda0568caece9ecb28dfde6347c96a67dc245a1e08ab9",
"com.sydxky.rtos.inputmethod/VALIDATION_1.2.0.md": "db7cf247579c3f6be73eaecf75fc9553214df8120ee25dc7d51c402a34ea89d6",
"com.sydxky.rtos.inputmethod/build.ps1": "32168e753699f48274fe2492e53b7285e4b62c15dc928f3aeb366a11150ebf5a",
"com.sydxky.rtos.inputmethod/glyphix.config.js": "43beae1f2a61eed010149ae6ad77223ba084117ea5aee3cb3fcd48bfc0a4a32b",
"com.sydxky.rtos.inputmethod/scripts/build-icons.py": "51f859a9517e7dd2e5e4bf9f688ce41dc79d4bc491fc66066dfe2db4aae4d704", "com.sydxky.rtos.inputmethod/scripts/build-icons.py": "51f859a9517e7dd2e5e4bf9f688ce41dc79d4bc491fc66066dfe2db4aae4d704",
"com.sydxky.rtos.inputmethod/scripts/convert-dictionary.py": "83eea8c7adae0254eb69170dec905c285c09c43ffcf10e8e553beb108acf43b3", "com.sydxky.rtos.inputmethod/scripts/convert-dictionary.py": "83eea8c7adae0254eb69170dec905c285c09c43ffcf10e8e553beb108acf43b3",
"com.sydxky.rtos.inputmethod/scripts/install.mjs": "46c7d95b25c312734c0ca8387f4a782becd4723f21d01492d074da22ca05432d", "com.sydxky.rtos.inputmethod/scripts/install.mjs": "436a5560a54a56fbf923a370b7ec40b9d9670b1a8d3ef5d9b10e3603d71779ba",
"com.sydxky.rtos.inputmethod/src/app.js": "e51c7e0a67563bd64b6bc04aedde22842295824432942bc8f1ab0d4731cc3ed3", "com.sydxky.rtos.inputmethod/src/app.js": "e51c7e0a67563bd64b6bc04aedde22842295824432942bc8f1ab0d4731cc3ed3",
"com.sydxky.rtos.inputmethod/src/assets/crab-keyboard-license.txt": "b140337f94481310f35abfd2210fde308ba30411899095fd961a77b94e022775", "com.sydxky.rtos.inputmethod/src/assets/crab-keyboard-license.txt": "b140337f94481310f35abfd2210fde308ba30411899095fd961a77b94e022775",
"com.sydxky.rtos.inputmethod/src/assets/icon.png": "f712ac5f8c500a33dd72cc1f15f9ad467e6043c284fb6ece1f1683e54d40e683", "com.sydxky.rtos.inputmethod/src/assets/icon.png": "f712ac5f8c500a33dd72cc1f15f9ad467e6043c284fb6ece1f1683e54d40e683",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/LICENSE.txt": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/arrow-down-s-line.png": "69bb846769721ed4ad056ed0136da59d4aa6873edccd1e38a7ebd783cb94ed1e", "com.sydxky.rtos.inputmethod/src/assets/ime-icons/arrow-down-s-line.png": "69bb846769721ed4ad056ed0136da59d4aa6873edccd1e38a7ebd783cb94ed1e",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/arrow-left-s-line.png": "68d8920081fb883f4c59af47549d6b41a9b0a3748383b814e4480bfab0e711ed", "com.sydxky.rtos.inputmethod/src/assets/ime-icons/arrow-left-s-line.png": "68d8920081fb883f4c59af47549d6b41a9b0a3748383b814e4480bfab0e711ed",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/arrow-right-s-line.png": "c6bffa0a51254c60c92e276e4d21ae8a1595d82c77d9d6a1064afbf534ea3562", "com.sydxky.rtos.inputmethod/src/assets/ime-icons/arrow-right-s-line.png": "c6bffa0a51254c60c92e276e4d21ae8a1595d82c77d9d6a1064afbf534ea3562",
@@ -87,20 +83,20 @@
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/delete-back-2-line.png": "a83002ddc7ba1f1a86b361c0c672ec63205393cae2df275a9ff2d49501fd6b9d", "com.sydxky.rtos.inputmethod/src/assets/ime-icons/delete-back-2-line.png": "a83002ddc7ba1f1a86b361c0c672ec63205393cae2df275a9ff2d49501fd6b9d",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/edit-2-line.png": "6161624226e2b62b24da7244d86564d6d0856533c2149d3b347e17013c562497", "com.sydxky.rtos.inputmethod/src/assets/ime-icons/edit-2-line.png": "6161624226e2b62b24da7244d86564d6d0856533c2149d3b347e17013c562497",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/keyboard-box-line.png": "bf4b45e2e54b4fd7e901068df1de865334f7e4616583dc5358d35d14890948af", "com.sydxky.rtos.inputmethod/src/assets/ime-icons/keyboard-box-line.png": "bf4b45e2e54b4fd7e901068df1de865334f7e4616583dc5358d35d14890948af",
"com.sydxky.rtos.inputmethod/src/assets/ime-icons/LICENSE.txt": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"com.sydxky.rtos.inputmethod/src/assets/jieba-license.txt": "18ba0984839f85853b29fadaf992f7dba8fd0ca0fbeae34de2b8735222dc7a37", "com.sydxky.rtos.inputmethod/src/assets/jieba-license.txt": "18ba0984839f85853b29fadaf992f7dba8fd0ca0fbeae34de2b8735222dc7a37",
"com.sydxky.rtos.inputmethod/src/common/ime-engine.js": "80e70d69561e424f4e42d5b3f33880bfa87df4d04119eb4f49b46b2dde4dce3d", "com.sydxky.rtos.inputmethod/src/common/ime-engine.js": "80e70d69561e424f4e42d5b3f33880bfa87df4d04119eb4f49b46b2dde4dce3d",
"com.sydxky.rtos.inputmethod/src/common/ime-lifecycle.js": "93525dffabcca0620acc36defd077ab6677b1032ef67faf695f3fbf3116b8a64", "com.sydxky.rtos.inputmethod/src/common/ime-lifecycle.js": "93525dffabcca0620acc36defd077ab6677b1032ef67faf695f3fbf3116b8a64",
"com.sydxky.rtos.inputmethod/src/keyboard/index.ux": "d7b4849824cb31882bce496aaecbbe26b82b772820c54327a263f6758ec5b217", "com.sydxky.rtos.inputmethod/src/common/ime-theme.js": "cd4fb2392585c1c93cab1077d37fcced34ecb67449becfffbc0be3a3833f8538",
"com.sydxky.rtos.inputmethod/src/keyboard/index.ux": "a845000679353d243381c91d65108d895f87ae931bb02a4bee3f1ea3451974ee",
"com.sydxky.rtos.inputmethod/src/main/index.ux": "f763f0dc80b9fd46e00830d6ec0de8683063f98c1edee94ee522c2605b695fca", "com.sydxky.rtos.inputmethod/src/main/index.ux": "f763f0dc80b9fd46e00830d6ec0de8683063f98c1edee94ee522c2605b695fca",
"com.sydxky.rtos.inputmethod/src/manifest.json": "4520f786d4159d1cf8aedd0bad73a66bf3494729ca1de69ea66e2c9fad3fba64", "com.sydxky.rtos.inputmethod/src/manifest.json": "065e5fb6e1e5898195fd117bcf905f002ee54ffd1d72e02dc0f9e4c50924bfab",
"com.sydxky.rtos.inputmethod/tests/client.test.mjs": "01bb6191f26d0f50496f1e032a39bf3bcce567bbbc33727491c5246dc6bf9900", "com.sydxky.rtos.inputmethod/tests/client.test.mjs": "a1c524b3d4ff5c49cfd599d2b1111e585a67dfdccf9612fd3f4a312fc1841076",
"com.sydxky.rtos.inputmethod/tests/engine.test.mjs": "86408d7629f189a11327ee801e75e472414d3a7979db60c12772debcf447ce23", "com.sydxky.rtos.inputmethod/tests/engine.test.mjs": "86408d7629f189a11327ee801e75e472414d3a7979db60c12772debcf447ce23",
"com.sydxky.rtos.inputmethod/tests/layout.py": "b632411cd593d369180abaeedbf036002e986e3e5e2c2f15b4e5ff157588aa78", "com.sydxky.rtos.inputmethod/tests/layout.py": "9b1fc238cae2f39e5385611cb3d5d636e40941cd4566c51d1407cfb72d6dbcff",
"com.sydxky.rtos.inputmethod/tests/native.py": "307d14506af92388c044e30e8095ac4640b710d988ec10d31f3eecd1c9a9a093", "com.sydxky.rtos.inputmethod/tests/native.py": "307d14506af92388c044e30e8095ac4640b710d988ec10d31f3eecd1c9a9a093",
"com.sydxky.rtos.inputmethod/tests/visual.py": "25bb14687278b6961e1e4957dafdb28b95d1056fdbe58e6506bca853cd5f1fec", "com.sydxky.rtos.inputmethod/tests/visual.py": "25bb14687278b6961e1e4957dafdb28b95d1056fdbe58e6506bca853cd5f1fec",
"com.sydxky.rtos.inputmethod/third_party/UPSTREAM.md": "e8311679981a318fef7142f7a2ecb2b1a7860f5fee32282729cab6af2a41d640",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/LICENSE": "b140337f94481310f35abfd2210fde308ba30411899095fd961a77b94e022775", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/LICENSE": "b140337f94481310f35abfd2210fde308ba30411899095fd961a77b94e022775",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/README.md": "88c2f96be16dc5d80677745072940c8a1cbc7aab40e554de50ec11bc22339b75",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/lookupDictV5.original.js": "915605439ebc404d808ccce6cb18abfff3981f1cdf53a78e9a743c78c4a6ddc9", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/lookupDictV5.original.js": "915605439ebc404d808ccce6cb18abfff3981f1cdf53a78e9a743c78c4a6ddc9",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/key0.dat": "795a5316089b67a7bffabf87080bd61f3720f9e0fd2f2866a092901f99b794e8", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/key0.dat": "795a5316089b67a7bffabf87080bd61f3720f9e0fd2f2866a092901f99b794e8",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/key1.dat": "a4bcae2b6eb30084d3cf2ac64e5d9ca71eb94e8ac1f7c8fc8b38a5d478982be2", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/key1.dat": "a4bcae2b6eb30084d3cf2ac64e5d9ca71eb94e8ac1f7c8fc8b38a5d478982be2",
@@ -143,10 +139,9 @@
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/value7.dat": "b9f6e109ba5f1b5bca758613cb5cccfecf358915ce6415525c333b19515d6428", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/value7.dat": "b9f6e109ba5f1b5bca758613cb5cccfecf358915ce6415525c333b19515d6428",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/value8.dat": "3d1622d4717680b31a6e037c88e7f046fecfe2339e521272e1d1eae0a7094606", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/value8.dat": "3d1622d4717680b31a6e037c88e7f046fecfe2339e521272e1d1eae0a7094606",
"com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/value9.dat": "1c0caab370f1f14048ab6dd2da0011bedcddfed0ed0378b5c98171b6b22caf35", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/pinyinDictV5_20260416/value9.dat": "1c0caab370f1f14048ab6dd2da0011bedcddfed0ed0378b5c98171b6b22caf35",
"com.sydxky.rtos.inputmethod/third_party/jieba/LICENSE": "18ba0984839f85853b29fadaf992f7dba8fd0ca0fbeae34de2b8735222dc7a37", "com.sydxky.rtos.inputmethod/third_party/crabKeyboard/README.md": "88c2f96be16dc5d80677745072940c8a1cbc7aab40e554de50ec11bc22339b75",
"com.sydxky.rtos.inputmethod/third_party/jieba/dict.txt": "7197c3211ddd98962b036cdf40324d1ea2bfaa12bd028e68faa70111a88e12a8", "com.sydxky.rtos.inputmethod/third_party/jieba/dict.txt": "7197c3211ddd98962b036cdf40324d1ea2bfaa12bd028e68faa70111a88e12a8",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", "com.sydxky.rtos.inputmethod/third_party/jieba/LICENSE": "18ba0984839f85853b29fadaf992f7dba8fd0ca0fbeae34de2b8735222dc7a37",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/README.md": "6a7bee86ad1942d01be10b556dd3036e43a59d708fc94fd2f5f3e3fcfcf84b0b",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/arrow-down-s-line.iconfont.svg": "1efa1c713b710c0e9ef5eb47bec762a4b5ce21ffb454d44a3bbb118a8bec3e83", "com.sydxky.rtos.inputmethod/third_party/remix-icon/arrow-down-s-line.iconfont.svg": "1efa1c713b710c0e9ef5eb47bec762a4b5ce21ffb454d44a3bbb118a8bec3e83",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/arrow-down-s-line.upstream.svg": "4b0bf8a45d554ba97d8115ef2713010f196ad49d57eeecb8a42d4839a5ba8f9e", "com.sydxky.rtos.inputmethod/third_party/remix-icon/arrow-down-s-line.upstream.svg": "4b0bf8a45d554ba97d8115ef2713010f196ad49d57eeecb8a42d4839a5ba8f9e",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/arrow-left-s-line.iconfont.svg": "ccf02486d37383bbdc3319d9b348c5daef43693526d41aff6ad409d04e0664ef", "com.sydxky.rtos.inputmethod/third_party/remix-icon/arrow-left-s-line.iconfont.svg": "ccf02486d37383bbdc3319d9b348c5daef43693526d41aff6ad409d04e0664ef",
@@ -164,20 +159,35 @@
"com.sydxky.rtos.inputmethod/third_party/remix-icon/icons.json": "c556c01eed73d0671f93cbeaeed8d3a628395213ef0b951bd5eb7c3d1c1618db", "com.sydxky.rtos.inputmethod/third_party/remix-icon/icons.json": "c556c01eed73d0671f93cbeaeed8d3a628395213ef0b951bd5eb7c3d1c1618db",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/keyboard-box-line.iconfont.svg": "813d79347c357a919317edf84252a505dbdc441c1144076b4e8389a8ce217de0", "com.sydxky.rtos.inputmethod/third_party/remix-icon/keyboard-box-line.iconfont.svg": "813d79347c357a919317edf84252a505dbdc441c1144076b4e8389a8ce217de0",
"com.sydxky.rtos.inputmethod/third_party/remix-icon/keyboard-box-line.upstream.svg": "e39f28cbf418269405f517126a64cbf4b3332b3295cc8a3af670f77344a669c4", "com.sydxky.rtos.inputmethod/third_party/remix-icon/keyboard-box-line.upstream.svg": "e39f28cbf418269405f517126a64cbf4b3332b3295cc8a3af670f77344a669c4",
"docs/SCREENSHOTS.md": "c38fcb14f6140a392b2a044b4e98cc625798a4579cce830075fd7f83aaf882ca", "com.sydxky.rtos.inputmethod/third_party/remix-icon/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"docs/UI_PREVIEW.png": "ef7767cd8c38051d332f045ff879d343ebc9966a2a94d2468b8d19604bff7ce1", "com.sydxky.rtos.inputmethod/third_party/remix-icon/README.md": "6a7bee86ad1942d01be10b556dd3036e43a59d708fc94fd2f5f3e3fcfcf84b0b",
"com.sydxky.rtos.inputmethod/third_party/UPSTREAM.md": "e8311679981a318fef7142f7a2ecb2b1a7860f5fee32282729cab6af2a41d640",
"com.sydxky.rtos.inputmethod/VALIDATION_1.1.0.md": "3b7346853bf6679c4efeda0568caece9ecb28dfde6347c96a67dc245a1e08ab9",
"com.sydxky.rtos.inputmethod/VALIDATION_1.2.0.md": "db7cf247579c3f6be73eaecf75fc9553214df8120ee25dc7d51c402a34ea89d6",
"com.sydxky.rtos.inputmethod/VALIDATION_1.2.2.md": "21792c32b065505b2b81ebbbcf7127958fbbb0d791fa121b84cd4e384ac05221",
"docs/screenshots/android-candidates-16.png": "d244a3fb41300a7e8c478930307cfb3d4e781f016be53a9e93615bb79717ae73", "docs/screenshots/android-candidates-16.png": "d244a3fb41300a7e8c478930307cfb3d4e781f016be53a9e93615bb79717ae73",
"docs/screenshots/android-english.png": "adbc1ede8f2103a6435aa04efe604737895365ff3f53e75fcb9511b9a1f4f551",
"docs/screenshots/android-fourteen.png": "88b06bdd1e6a6dc6f45722e01ce7930c94845062b8bf237aad5c5d086f37641c", "docs/screenshots/android-fourteen.png": "88b06bdd1e6a6dc6f45722e01ce7930c94845062b8bf237aad5c5d086f37641c",
"docs/screenshots/android-home.png": "b6823a0bcfb995d6ac771252f31f7ed1d85da12e9b4b98b5ba07e801c5d6e41e", "docs/screenshots/android-home.png": "b6823a0bcfb995d6ac771252f31f7ed1d85da12e9b4b98b5ba07e801c5d6e41e",
"docs/screenshots/android-host.png": "06a770510a2802d2d7b74b2410003b3851a98b247f98fcd0dd2e4893610b456b", "docs/screenshots/android-host.png": "06a770510a2802d2d7b74b2410003b3851a98b247f98fcd0dd2e4893610b456b",
"docs/screenshots/android-number.png": "c445219577c4288f351b8026cf4e42944a28b2692770ad942acda25148c04614",
"docs/screenshots/android-phrases.png": "144be16bc2d9252a711af0a57b57ba6cb624ac9e7900fadeb31447fa8060fe9e", "docs/screenshots/android-phrases.png": "144be16bc2d9252a711af0a57b57ba6cb624ac9e7900fadeb31447fa8060fe9e",
"docs/screenshots/android-qwerty.png": "17c9a50782be31225ba8360fb73923a90ac7a98b8ca656fcc2d2cdab2e368e8b", "docs/screenshots/android-qwerty.png": "17c9a50782be31225ba8360fb73923a90ac7a98b8ca656fcc2d2cdab2e368e8b",
"docs/screenshots/android-result.png": "65d50c4e6672f26e5f156fa52cadb9b4f4d0282ad71af71fcc1fdb5a738e5a24", "docs/screenshots/android-result.png": "65d50c4e6672f26e5f156fa52cadb9b4f4d0282ad71af71fcc1fdb5a738e5a24",
"docs/screenshots/android-symbols.png": "9025f60c6f24a09a5aabd20943ec3c2d47b4b172053317f7188b94bf5f0fe65b",
"docs/screenshots/rtos-rect-candidates.png": "fd2342bd5e6b05390097b6b55614db67442ff797afc8e3ae8b2999a478fab232", "docs/screenshots/rtos-rect-candidates.png": "fd2342bd5e6b05390097b6b55614db67442ff797afc8e3ae8b2999a478fab232",
"docs/screenshots/rtos-rect-en.png": "fe7e63f68d12d2f0eea41525927ec5e15f61032e208d89602c5c5371950268f0",
"docs/screenshots/rtos-rect-num.png": "1b7a7e904be5d267cb08d15076dca69acbb5922e375c588d93dcf8d5e950e3fa",
"docs/screenshots/rtos-round-14-key.png": "65749bb8197992a331efc2484ce8e425f5958e50fadb6d6c509b0749aa684585", "docs/screenshots/rtos-round-14-key.png": "65749bb8197992a331efc2484ce8e425f5958e50fadb6d6c509b0749aa684585",
"docs/screenshots/rtos-round-candidates.png": "ab4f686aaece5abde52b3a7a57a3da10573eb95d56e4664ac03a4fe12267705d", "docs/screenshots/rtos-round-candidates.png": "ab4f686aaece5abde52b3a7a57a3da10573eb95d56e4664ac03a4fe12267705d",
"docs/screenshots/rtos-round-en.png": "b94f17f121d165c33f84b0eaa4c1ca48b2dbf9890bd1ab77147965fc138de6c2",
"docs/screenshots/rtos-round-num.png": "d7fcf451229861fb564b45b6ada03501aed57cf9ca5c058833b9b65dbace06eb",
"docs/screenshots/rtos-round-phrase-candidates.png": "507d09901681bbeae4da39fa0a700663d89b7149f7fab01dd603630c932b4dc4", "docs/screenshots/rtos-round-phrase-candidates.png": "507d09901681bbeae4da39fa0a700663d89b7149f7fab01dd603630c932b4dc4",
"tests/emulator-validate.py": "2a549e3c7bc177b942826425e548f68db39a32d8a55ade080f0d8ab3e9c00060", "docs/SCREENSHOTS.md": "b2b1af7717990312fe6aa56d5a75653a533bc695c5f048888dce64fb0d576c56",
".gitattributes": "8e689518e5810501eb34583fa369475902805d8dd6c3ea78699469de4fa22932" "docs/UI_PREVIEW.png": "a8fe477bfbc7efba2affdaa7f7314c773c123191a1fc0d04c2eae294b4aaa492",
"LICENSE": "4f3547e23d7fd227a33aaa6a075185be8299403b03e534627bbb3bc3bdcf97af",
"NOTICE.md": "eb75c7be9055410bec57688b363be4761c2ee6f2ae4cfba4ab908d0b9ce68999",
"README.md": "32458e78cde7c95ffd91acde24c15f3d41a5b116b5d52682c4b883c3a0b7f176",
"tests/emulator-validate.py": "2a549e3c7bc177b942826425e548f68db39a32d8a55ade080f0d8ab3e9c00060"
} }
} }
+12 -6
查看文件
@@ -4,9 +4,15 @@
**MIT 开源,允许商用、修改、再分发和闭源集成。** 使用时请保留 [LICENSE](LICENSE) 和 [第三方许可](NOTICE.md)。厂商 SDK、运行时与设备固件不包含在本项目授权中。 **MIT 开源,允许商用、修改、再分发和闭源集成。** 使用时请保留 [LICENSE](LICENSE) 和 [第三方许可](NOTICE.md)。厂商 SDK、运行时与设备固件不包含在本项目授权中。
![1.2.0 实际模拟器与手表界面](docs/UI_PREVIEW.png) ![1.2.2 实际模拟器与手表界面](docs/UI_PREVIEW.png)
## 1.2.0 带来了什么 ## 1.2.2 间距修复
RTOS 去掉文字与键盘之间自动居中产生的空隙;Android 英文、数字、符号模式去掉未使用的候选栏空位。圆屏同步修正按键边角和工具页末排边界。四配置构建、普通圆/方24个原生视觉状态、Android新间距检查通过;Android整组测试6/9通过,三项受共享设备切换干扰,按用户要求不重跑。QuickApp原生视觉未完成,RTOS真机未验收。
[本版RTOS验收](com.sydxky.rtos.inputmethod/VALIDATION_1.2.2.md) · [本版Android验收](android/VALIDATION_1.2.2.md)
## 1.2.0 已有功能
- 完整候选采用 **4×4 网格,单字 16 项一页**;词组占用更多列,长词增加行高,显示完整文字;展开页不显示拼音。 - 完整候选采用 **4×4 网格,单字 16 项一页**;词组占用更多列,长词增加行高,显示完整文字;展开页不显示拼音。
- 标准 **QWERTY 26 键**,排列为 `qwertyuiop / asdfghjkl / zxcvbnm`;同时提供九宫和 14 键双字母模式。 - 标准 **QWERTY 26 键**,排列为 `qwertyuiop / asdfghjkl / zxcvbnm`;同时提供九宫和 14 键双字母模式。
@@ -19,8 +25,8 @@
| 平台 | 接入与产物 | 已完成的验证 | | 平台 | 接入与产物 | 已完成的验证 |
| --- | --- | --- | | --- | --- | --- |
| Glyphix RTOS | 原生 `.ux` 页面;圆屏 466×466、方屏 390×450 两屏 QuickApp 完整 ZIP | 普通/QuickApp 四配置构建;84 项原生操作、84 项布局、48 个视觉状态 | | Glyphix RTOS | 原生 `.ux` 页面;圆屏 466×466、方屏 390×450 两屏 QuickApp 完整 ZIP | 普通/QuickApp 四配置构建;普通圆/方 24 个原生视觉状态及间距/边界检查 |
| Android 8.1 / API 27+ | 原生 AAR;演示 APK;独立 `host/` 示例 | OWW261 Android 11 真机 8 项交互测试,系统默认输入法保持不变 | | Android 8.1 / API 27+ | 原生 AAR;演示 APK;独立 `host/` 示例 | OWW261 新间距测试通过;整组6/9,三项受共享设备切换干扰;系统默认输入法保持不变 |
Android 版本作为**应用内公开组件**,由每个应用自行接入;组件不注册系统输入法。RTOS 页面也需宿主接入,系统级注册依赖厂商支持。 Android 版本作为**应用内公开组件**,由每个应用自行接入;组件不注册系统输入法。RTOS 页面也需宿主接入,系统级注册依赖厂商支持。
@@ -28,7 +34,7 @@ Android 版本作为**应用内公开组件**,由每个应用自行接入;
## 下载、源码与反馈 ## 下载、源码与反馈
- [v1.2.0 发行包与更新说明](https://git2.sydxky.cn/sydxky/crab-input-rtos/releases/tag/v1.2.0):AAR、演示 APK、两屏 RTOS QuickApp、验收截图及 SHA-256。 - [v1.2.2 发行包与更新说明](https://git2.sydxky.cn/sydxky/crab-input-rtos/releases/tag/v1.2.2):AAR、演示 APK、两屏 RTOS QuickApp、验收截图及 SHA-256。
- [Android 接入文档](android/README.md) · [RTOS 接入文档](com.sydxky.rtos.inputmethod/README.md) - [Android 接入文档](android/README.md) · [RTOS 接入文档](com.sydxky.rtos.inputmethod/README.md)
- [实际界面截图](docs/SCREENSHOTS.md) · [RTOS 验收](com.sydxky.rtos.inputmethod/VALIDATION_1.2.0.md) · [Android 真机验收](android/VALIDATION_1.2.0.md) - [实际界面截图](docs/SCREENSHOTS.md) · [RTOS 验收](com.sydxky.rtos.inputmethod/VALIDATION_1.2.0.md) · [Android 真机验收](android/VALIDATION_1.2.0.md)
- [已有问题](https://git2.sydxky.cn/sydxky/crab-input-rtos/issues) · [免注册提交问题与建议](https://git2.sydxky.cn/feedback/sydxky/crab-input-rtos) - [已有问题](https://git2.sydxky.cn/sydxky/crab-input-rtos/issues) · [免注册提交问题与建议](https://git2.sydxky.cn/feedback/sydxky/crab-input-rtos)
@@ -82,4 +88,4 @@ python .\com.sydxky.rtos.inputmethod\tests\native.py --work work/native --output
python .\com.sydxky.rtos.inputmethod\tests\visual.py --work work/visual --output work/evidence/visual python .\com.sydxky.rtos.inputmethod\tests\visual.py --work work/visual --output work/evidence/visual
``` ```
视觉脚本依赖 Pillow。RTOS 运行时内存配置保持 8192 KiB。本版本完成模拟器、Android 真机组件及提交包验收;RTOS 真机、长期性能/续航和商店审核尚未验收。 视觉脚本依赖 Pillow。RTOS 运行时内存配置保持 8192 KiB。本版本已完成上述间距与构建检查;未完成的交互、QuickApp原生视觉、RTOS真机、长期性能/续航和商店审核范围见本版验收记录。
+5 -3
查看文件
@@ -1,17 +1,19 @@
# 蟹蟹输入 Android应用内键盘组件 # 蟹蟹输入 Android应用内键盘组件
基于CrabKeyboard MIT词库,由herry重写的Android手表原生键盘组件,1.2.0 / 10200。提供可集成的 **AAR**、演示APK和独立接入示例;适用Android 8.1 / API 27及以上。 基于CrabKeyboard MIT词库,由herry重写的Android手表原生键盘组件,1.2.2 / 10202。提供可集成的 **AAR**、演示APK和独立接入示例;适用Android 8.1 / API 27及以上。
应用接入后,点击自己的输入框自动展开内置键盘。**不注册系统输入法、不要求用户切换输入法、不改变系统默认输入法。** 圆屏按每行所在高度计算安全弦宽;4×4完整候选,单字16个一页,词组扩宽或增加行高,候选不显示拼音。九宫、标准QWERTY全拼/英文、14键、数字、三页符号、Unicode删除、按住连删及光标编辑。 应用接入后,点击自己的输入框自动展开内置键盘。**不注册系统输入法、不要求用户切换输入法、不改变系统默认输入法。** 圆屏按每行所在高度计算安全弦宽;4×4完整候选,单字16个一页,词组扩宽或增加行高,候选不显示拼音。九宫、标准QWERTY全拼/英文、14键、数字、三页符号、Unicode删除、按住连删及光标编辑。
完全离线,无网络或外部存储权限;组件不持久化输入内容,不启用学习。密码输入默认英文并遮蔽预览。页面隐藏/销毁时清除组件会话与候选,宿主输入框中的内容仍由宿主决定如何处理。异步查询按会话序号隔离,旧结果不能回填新的输入框。 完全离线,无网络或外部存储权限;组件不持久化输入内容,不启用学习。密码输入默认英文并遮蔽预览。页面隐藏/销毁时清除组件会话与候选,宿主输入框中的内容仍由宿主决定如何处理。异步查询按会话序号隔离,旧结果不能回填新的输入框。
1.2.2 去掉英文、数字、符号模式未使用的候选栏空位,文字与键盘紧密相接。本版真机间距检查通过;完整测试的限制见[验收记录](./VALIDATION_1.2.2.md)。
## 一分钟接入 ## 一分钟接入
将发行版`crab-keyboard-1.2.0.aar`放入宿主`app/libs/`: 将发行版`crab-keyboard-1.2.2.aar`放入宿主`app/libs/`:
```groovy ```groovy
dependencies { implementation files('libs/crab-keyboard-1.2.0.aar') } dependencies { implementation files('libs/crab-keyboard-1.2.2.aar') }
``` ```
```java ```java
+13
查看文件
@@ -0,0 +1,13 @@
# Android 输入组件 1.2.2 间距修复
2026-11-14,演示包 `com.sydxky.crabinput`,版本 `1.2.2 / 10202`;最低API27。
英文、数字、符号模式现在由编码标题直接定位首排按键,不再先分配候选区域再局部抵消高度,去掉12逻辑像素的空位。中文候选栏与九宫、全拼、14键行为保持原逻辑。
4项Java单元测试通过;组件及演示Release构建和lint通过(组件无问题,演示0错误/1警告)。全量词库104,837组索引、163,238候选无损回读与SQLite完整性检查通过。正式演示APK为原生产证书、单签名者、APK v2有效,AAR不需要应用签名。
实体OWW261,Android11/API30、466×466。UiAutomator新增的 `directModesHaveNoUnusedCandidateGap` 已通过:实际打开内置键盘,分别点击英文、数字、符号模式,测得编码标题到首排按键间距在0–5物理像素内,预览到编码标题在0–4像素内;同场检查全部可见按钮的圆屏安全边界,并保留三张真机截图。
整组9项测试为6项通过、3项未通过。通过项包括新间距检查、全量词库、安全输入模式、14键词组、全拼连续输入、完整候选分页。另三项(Unicode/长按删除、独立宿主接入、九宫词组)执行期间,同一手表被另一任务切换到弹球界面,造成找不到目标输入框;未将它们记为通过。按用户明确选择“仅完成现有验证并发布”,停止争用设备且未重跑。测试前后系统默认输入法一致。
本次没有领取账号奖励、执行支付或修改其他应用数据。RTOS真机、另一款方表、长期性能/功耗和商店审核未验收。
+2 -2
查看文件
@@ -12,8 +12,8 @@ android {
applicationId 'com.sydxky.crabinput' applicationId 'com.sydxky.crabinput'
minSdk 27 minSdk 27
targetSdk 35 targetSdk 35
versionCode 10200 versionCode 10202
versionName '1.2.0' versionName '1.2.2'
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
} }
signingConfigs { signingConfigs {
@@ -113,4 +113,24 @@ public class ImeDeviceTest {
UiObject2 delete=device.wait(Until.findObject(By.desc("删除")),5000);Rect bounds=delete.getVisibleBounds();device.swipe(bounds.centerX(),bounds.centerY(),bounds.centerX(),bounds.centerY(),160);SystemClock.sleep(150);action("收起键盘"); UiObject2 delete=device.wait(Until.findObject(By.desc("删除")),5000);Rect bounds=delete.getVisibleBounds();device.swipe(bounds.centerX(),bounds.centerY(),bounds.centerX(),bounds.centerY(),160);SystemClock.sleep(150);action("收起键盘");
int count=device.findObject(By.desc("demo_text")).getText().length();assertTrue("Hold repeats deletion",count<14);SystemClock.sleep(300);assertEquals("Release stops repeat",count,device.findObject(By.desc("demo_text")).getText().length()); int count=device.findObject(By.desc("demo_text")).getText().length();assertTrue("Hold repeats deletion",count<14);SystemClock.sleep(300);assertEquals("Release stops repeat",count,device.findObject(By.desc("demo_text")).getText().length());
} }
@Test public void directModesHaveNoUnusedCandidateGap() throws Exception {
editor("demo_text");
Context context=InstrumentationRegistry.getInstrumentation().getTargetContext();
String[][] modes={{"abc","英文","q","english"},{"123","数字","1","number"},{"符号","符号 · 1/3 · 再点符号翻页",",","symbols"}};
for(String[] mode:modes){
tap(mode[0]);
UiObject2 caption=device.findObject(By.pkg(PKG).text(mode[1]));
UiObject2 first=device.findObject(By.pkg(PKG).text(mode[2]));
UiObject2 preview=device.findObject(By.pkg(PKG).desc("编辑光标"));
assertNotNull(caption);assertNotNull(first);assertNotNull(preview);
Rect captionBounds=caption.getVisibleBounds(),keyBounds=first.getVisibleBounds();
int gap=keyBounds.top-captionBounds.bottom;
assertTrue("No blank candidate band: "+mode[3]+" gap="+gap,gap>=0&&gap<=Math.ceil(device.getDisplayHeight()*4/410f));
int previewGap=captionBounds.top-preview.getVisibleBounds().bottom;
assertTrue("Preview joins composition",previewGap>=0&&previewGap<=Math.ceil(device.getDisplayHeight()*3/410f));
for(UiObject2 button:device.findObjects(By.pkg(PKG).clazz("android.widget.Button")))assertRoundSafe(button.getVisibleBounds());
assertTrue(device.takeScreenshot(new java.io.File(context.getExternalFilesDir(null),"gap-"+mode[3]+".png")));
}
action("收起键盘");
}
} }
+1 -1
查看文件
@@ -2,7 +2,7 @@ plugins { id 'com.android.application' }
android { android {
namespace 'com.sydxky.crabinput.host' namespace 'com.sydxky.crabinput.host'
compileSdk 37 compileSdk 37
defaultConfig { applicationId 'com.sydxky.crabinput.host'; minSdk 27; targetSdk 35; versionCode 10200; versionName '1.2.0' } defaultConfig { applicationId 'com.sydxky.crabinput.host'; minSdk 27; targetSdk 35; versionCode 10202; versionName '1.2.2' }
compileOptions { sourceCompatibility JavaVersion.VERSION_11; targetCompatibility JavaVersion.VERSION_11 } compileOptions { sourceCompatibility JavaVersion.VERSION_11; targetCompatibility JavaVersion.VERSION_11 }
} }
dependencies { implementation project(':keyboard') } dependencies { implementation project(':keyboard') }
@@ -110,7 +110,9 @@ final class KeyboardSurface extends ViewGroup {
if(count>0)action("⌄","expand",410-left-35,candidateY,33,32,24,false); if(count>0)action("⌄","expand",410-left-35,candidateY,33,32,24,false);
else place(label(state.busy?"正在查词…":state.message,12,MUTED),left,candidateY,available,32); else place(label(state.busy?"正在查词…":state.message,12,MUTED),left,candidateY,available,32);
} }
float keyY=candidateY+38; // A direct-entry mode has no candidate strip; attach its keys to the
// composition caption instead of reserving an invisible suggestion row.
float keyY=isChinese()?candidateY+38:compositionY+25;
String[][] captions,values; String[][] captions,values;
switch(state.mode) { switch(state.mode) {
case "t9":captions=new String[][]{{"标点","ABC","DEF"},{"GHI","JKL","MNO"},{"PQRS","TUV","WXYZ"}};values=new String[][]{{"mode:sym","key:2","key:3"},{"key:4","key:5","key:6"},{"key:7","key:8","key:9"}};break; case "t9":captions=new String[][]{{"标点","ABC","DEF"},{"GHI","JKL","MNO"},{"PQRS","TUV","WXYZ"}};values=new String[][]{{"mode:sym","key:2","key:3"},{"key:4","key:5","key:6"},{"key:7","key:8","key:9"}};break;
@@ -121,7 +123,7 @@ final class KeyboardSurface extends ViewGroup {
} }
float keyHeight=captions.length==4?36:49; float keyHeight=captions.length==4?36:49;
// Hide an unused suggestion strip in direct entry modes to enlarge the keys. // Hide an unused suggestion strip in direct entry modes to enlarge the keys.
if(!isChinese()){keyY-=27;keyHeight=captions.length==4?43:58;} if(!isChinese()){keyHeight=captions.length==4?43:58;}
for(int i=0;i<captions.length;i++)row(captions[i],values[i],keyY+i*(keyHeight+4),keyHeight,captions[i].length>=7?21:24); for(int i=0;i<captions.length;i++)row(captions[i],values[i],keyY+i*(keyHeight+4),keyHeight,captions[i].length>=7?21:24);
float modeY=keyY+captions.length*(keyHeight+4)+3; float modeY=keyY+captions.length*(keyHeight+4)+3;
row(new String[]{"九宫","26键","14键",state.upper?"ABC":"abc","123","符号"},new String[]{"mode:t9","mode:py","mode:14","mode:en","mode:num","mode:sym"},modeY,27,13); row(new String[]{"九宫","26键","14键",state.upper?"ABC":"abc","123","符号"},new String[]{"mode:t9","mode:py","mode:14","mode:en","mode:num","mode:sym"},modeY,27,13);
+2 -2
查看文件
@@ -28,8 +28,8 @@ def main():
command=['adb','-s',args.serial,'shell','am','instrument','-w','-r','com.sydxky.crabinput.test/androidx.test.runner.AndroidJUnitRunner'] command=['adb','-s',args.serial,'shell','am','instrument','-w','-r','com.sydxky.crabinput.test/androidx.test.runner.AndroidJUnitRunner']
result=subprocess.run(command,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,timeout=240) result=subprocess.run(command,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,timeout=240)
output=result.stdout.decode('utf-8',errors='replace');(args.output/'instrumentation.txt').write_text(output,encoding='utf-8');print(output,flush=True) output=result.stdout.decode('utf-8',errors='replace');(args.output/'instrumentation.txt').write_text(output,encoding='utf-8');print(output,flush=True)
passed=result.returncode==0 and 'OK (8 tests)'in output and 'FAILURES!!!'not in output passed=result.returncode==0 and 'OK (9 tests)'in output and 'FAILURES!!!'not in output
report={'model':model,'sdk':sdk,'version':'1.2.0','apk_sha256':hashlib.sha256(apk.read_bytes()).hexdigest(),'instrumentation_tests':8,'embedded_component':True,'system_ime_unchanged':adb('shell','settings','get','secure','default_input_method')==before,'passed':passed} report={'model':model,'sdk':sdk,'version':'1.2.2','apk_sha256':hashlib.sha256(apk.read_bytes()).hexdigest(),'instrumentation_tests':9,'embedded_component':True,'system_ime_unchanged':adb('shell','settings','get','secure','default_input_method')==before,'passed':passed}
(args.output/'device-validation.json').write_text(json.dumps(report,indent=2)+'\n',encoding='utf-8') (args.output/'device-validation.json').write_text(json.dumps(report,indent=2)+'\n',encoding='utf-8')
assert passed and report['system_ime_unchanged'],'See instrumentation.txt; failed/unfinished cases are not accepted' assert passed and report['system_ime_unchanged'],'See instrumentation.txt; failed/unfinished cases are not accepted'
adb('shell','am','start','-n','com.sydxky.crabinput/.MainActivity');time.sleep(.5) adb('shell','am','start','-n','com.sydxky.crabinput/.MainActivity');time.sleep(.5)
+18 -1
查看文件
@@ -24,7 +24,23 @@ $targets = if ($QuickAppOnly) {
} }
$originalPath = $env:Path $originalPath = $env:Path
Push-Location $ProjectRoot $buildRoot = $ProjectRoot
$mappedDrive = $null
# Bundled pngquant still uses MAX_PATH; keep deeply generated apps buildable.
if ($IsWindows -and $ProjectRoot.Length + $manifest.package.Length + 150 -gt 245) {
$subst = Join-Path $env:SystemRoot 'System32\subst.exe'
foreach ($letter in @('Z','Y','X','W','V','U','T','S','R')) {
if (Test-Path -LiteralPath ($letter + ':\')) { continue }
& $subst ($letter + ':') $ProjectRoot 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
$mappedDrive = $letter + ':'
$buildRoot = $mappedDrive + '\'
break
}
}
if (-not $mappedDrive) { throw 'No temporary drive available for the vendor MAX_PATH workaround; use a shorter ProjectRoot' }
}
Push-Location $buildRoot
try { try {
$env:Path = "$toolBin;$originalPath" $env:Path = "$toolBin;$originalPath"
$availableDevices = @(& $gx list device) $availableDevices = @(& $gx list device)
@@ -77,5 +93,6 @@ try {
} }
} finally { } finally {
Pop-Location Pop-Location
if ($mappedDrive) { & $subst $mappedDrive /D | Out-Null }
$env:Path = $originalPath $env:Path = $originalPath
} }
+3 -1
查看文件
@@ -2,7 +2,9 @@
**蟹蟹输入 RTOS适配改版**:基于CrabKeyboard的独立改版,RTOS适配代码采用[MIT协议](./LICENSE),允许商用、修改及再分发,须保留版权与许可。上游与第三方署名见[NOTICE.md](./NOTICE.md)。公开源码:<https://git2.sydxky.cn/sydxky/crab-input-rtos>;免注册[匿名反馈](https://git2.sydxky.cn/feedback/sydxky/crab-input-rtos)。 **蟹蟹输入 RTOS适配改版**:基于CrabKeyboard的独立改版,RTOS适配代码采用[MIT协议](./LICENSE),允许商用、修改及再分发,须保留版权与许可。上游与第三方署名见[NOTICE.md](./NOTICE.md)。公开源码:<https://git2.sydxky.cn/sydxky/crab-input-rtos>;免注册[匿名反馈](https://git2.sydxky.cn/feedback/sydxky/crab-input-rtos)。
独立应用 `com.sydxky.rtos.inputmethod`,版本 `1.2.0 / 10200`。基于 [CrabKeyboard](https://github.com/crabPangXie/crabKeyboard) 的 MIT 全量词库和拼音前缀消费方式,重写为 Glyphix `.ux` 页面;不依赖 HarmonyOS HML、Android 输入法服务、DOM 或网络。 独立应用 `com.sydxky.rtos.inputmethod`,版本 `1.2.2 / 10202`。基于 [CrabKeyboard](https://github.com/crabPangXie/crabKeyboard) 的 MIT 全量词库和拼音前缀消费方式,重写为 Glyphix `.ux` 页面;不依赖 HarmonyOS HML、Android 输入法服务、DOM 或网络。
1.2.2 修复文字与键盘之间的多余空隙,圆屏按键上移后同步检查安全边界;本版验证范围见[间距修复验收](./VALIDATION_1.2.2.md)。
1.2.0 完整候选重做为 **4×4 网格**:单字每页16个,2~4字词组占两格,长词占整行并可增加行高;保持原有顺序,最后一页可达,不显示候选拼音。圆/方普通及QuickApp四配置已通过84项原生操作、84项布局及48个视觉状态,见[验收记录](./VALIDATION_1.2.0.md)。同源新增[Android应用内键盘组件](../android/README.md),独立包名、无需联网,接入应用的输入框自动弹出,保持系统默认输入法。 1.2.0 完整候选重做为 **4×4 网格**:单字每页16个,2~4字词组占两格,长词占整行并可增加行高;保持原有顺序,最后一页可达,不显示候选拼音。圆/方普通及QuickApp四配置已通过84项原生操作、84项布局及48个视觉状态,见[验收记录](./VALIDATION_1.2.0.md)。同源新增[Android应用内键盘组件](../android/README.md),独立包名、无需联网,接入应用的输入框自动弹出,保持系统默认输入法。
@@ -0,0 +1,11 @@
# 蟹蟹输入 RTOS 1.2.2 间距修复
2026-11-14,包名 `com.sydxky.rtos.inputmethod`,版本 `1.2.2 / 10202`。
键盘主体从纵向居中改为紧接文字与编码区排列,完整候选从上方开始排列。保留可见的中文/符号候选栏;英文、数字模式不预留候选栏,也不把剩余高度分配到文字与键盘之间。圆屏按键区宽度由376调到368逻辑像素,避免上移后英文首排边角越出圆形安全边界;工具页按钮减少1逻辑像素高度,消除末排在父容器内的轻微裁切。
使用厂商 `gx v0.10.1 / 3ed38835`、8192 KiB内存。44项引擎与32项UX脚本断言通过,圆/方普通及QuickApp四配置构建通过。当前普通圆屏和方屏共24个原生视觉状态通过,包括九宫、全拼、14键、英文、数字、两组符号、候选与工具页;新增控件树间距检查,英文/数字编码区到按键区实际为0像素。逐层父容器裁切、圆屏安全边界与背景边缘检查通过。
QuickApp原生视觉检查遇到已有其他应用占用Inspector端口,未接管或终止其他进程;本次不将四配置构建等同于四配置全部原生验收。没有重跑1.2.0的84项原生交互测试,历史结果不冒充本版验收。
RTOS真机、长期性能/功耗与平台审核未验收。Android独立记录见其 `VALIDATION_1.2.2.md`。
@@ -14,7 +14,7 @@ if(fs.existsSync(oldMeta)){
if(!current.includes(name)&&fs.existsSync(old))fs.unlinkSync(old) if(!current.includes(name)&&fs.existsSync(old))fs.unlinkSync(old)
} }
} }
for(const relative of ['keyboard/index.ux','common/ime-engine.js','common/ime-lifecycle.js','assets/ime-dict','assets/ime-icons']){ for(const relative of ['keyboard/index.ux','common/ime-engine.js','common/ime-lifecycle.js','common/ime-theme.js','assets/ime-dict','assets/ime-icons']){
const destination=path.join(target,'src',relative);fs.mkdirSync(path.dirname(destination),{recursive:true});fs.cpSync(path.join(app,'src',relative),destination,{recursive:true}) const destination=path.join(target,'src',relative);fs.mkdirSync(path.dirname(destination),{recursive:true});fs.cpSync(path.join(app,'src',relative),destination,{recursive:true})
} }
const license=path.join(target,'src/assets/crab-keyboard-license.txt') const license=path.join(target,'src/assets/crab-keyboard-license.txt')
@@ -0,0 +1,23 @@
// Shared app/keyboard colors. Dark colors match Android Wrist Star Chat.
export function normalizeTheme(value) { return value === 'blackgreen' ? 'blackgreen' : 'bluewhite' }
export function themeStyles(value) {
const dark = normalizeTheme(value) === 'blackgreen'
const c = dark
? {bg:'#000000',card:'#1C1C1E',raised:'#2C2C2E',text:'#F2F7FA',muted:'#B3B3B8',dim:'#A0A0A7',accent:'#00C777',user:'#0E5C44',line:'#3C3C40',danger:'#FF6978'}
: {bg:'#ECEEF2',card:'#FFFFFF',raised:'#F8F9FB',text:'#20232B',muted:'#737984',dim:'#737984',accent:'#2867D9',user:'#2867D9',line:'#D9DDE4',danger:'#B5424C'}
const ink='color:'+c.text+';',muted='color:'+c.muted+';'
return {
surface:'background-color:'+c.bg+';'+ink,
card:'background-color:'+c.card+';'+ink,
raised:'background-color:'+c.raised+';'+ink,
ink,muted,dim:'color:'+c.dim+';',accent:'color:'+c.accent+';',
primary:'background-color:'+c.accent+';color:'+(dark?'#000000':'#FFFFFF')+';',
secondary:'background-color:'+c.card+';color:'+c.accent+';',
user:'background-color:'+c.user+';color:#FFFFFF;',white:'color:#FFFFFF;',
input:'background-color:'+c.card+';'+ink+'border-bottom:2px solid '+c.line+';',
plain:'background-color:transparent;'+ink,
icon:'background-color:'+(dark?c.accent:'transparent')+';',
danger:'background-color:'+c.card+';color:'+c.danger+';',
selection:'background-color:'+c.raised+';border-bottom:2px solid '+c.accent+';'+ink
}
}
@@ -1,34 +1,34 @@
<template> <template>
<div class="ime-surface"> <div class="ime-surface" :style="themeStyles.surface">
<div class="ime"> <div class="ime" :style="themeStyles.surface">
<div class="top"><button id="ime-cancel" class="cancel icon-button" on:click="cancel"><image class="icon" src="/assets/ime-icons/close-line.png" /></button><p class="title">{{title}}</p><p class="count">{{count}} 字</p></div> <div class="top"><button id="ime-cancel" class="cancel icon-button" :style="themeStyles.icon" on:click="cancel"><image class="icon" src="/assets/ime-icons/close-line.png" /></button><p class="title" :style="themeStyles.muted">{{titleLabel}}</p><p class="count" :style="themeStyles.dim">{{count}} 字</p></div>
<button class="preview" on:click="showTools">{{count ? display : '输入文字…'}}</button> <button id="ime-preview" class="preview" :style="themeStyles.card" on:click="showTools">{{count ? display : '输入文字…'}}</button>
<div if="panel !== 'candidates'" class="composition"><p class="spelling">{{compositionDisplay || modeLabel}}</p><p class="hint">{{hint}}</p></div> <div if="panel !== 'candidates'" id="ime-composition" class="composition"><p class="spelling" :style="themeStyles.accent">{{compositionDisplay || modeLabel}}</p><p class="hint" :style="themeStyles.dim">{{hint}}</p></div>
<div if="panel === 'keys'" class="body"> <div if="panel === 'keys'" class="body">
<div if="mode === 't9' || mode === 'py' || mode === '14' || mode === 'sym' || inputType === 'url'" class="candidates"><button for="item in bar" class="candidate" on:click="choose(item)">{{item.word}}</button><button if="!composition &amp;&amp; inputType === 'url'" class="candidate" on:click="insert('https://')">https://</button><button if="!composition &amp;&amp; inputType === 'url'" class="candidate" on:click="insert('.com')">.com</button><button if="mode === 'sym'" class="candidate" on:click="symbols">下一组符号 {{symbolPage+1}}/2</button><p if="!total &amp;&amp; !busy &amp;&amp; mode !== 'sym' &amp;&amp; inputType !== 'url'" class="candidate-placeholder">{{secret ? '私密输入' : '选择候选词'}}</p><button if="mode !== 'sym' &amp;&amp; total" id="ime-expand" class="more icon-button" on:click="expand"><image class="icon" src="/assets/ime-icons/arrow-down-s-line.png" /></button></div> <div if="mode === 't9' || mode === 'py' || mode === '14' || mode === 'sym' || inputType === 'url'" id="ime-candidate-strip" class="candidates" :style="themeStyles.raised"><button for="item in bar" class="candidate" :style="themeStyles.plain" on:click="choose(item)">{{item.word}}</button><button if="!composition &amp;&amp; inputType === 'url'" class="candidate" :style="themeStyles.plain" on:click="insert('https://')">https://</button><button if="!composition &amp;&amp; inputType === 'url'" class="candidate" :style="themeStyles.plain" on:click="insert('.com')">.com</button><button if="mode === 'sym'" class="candidate" :style="themeStyles.plain" on:click="symbols">下一组符号 {{symbolPage+1}}/2</button><p if="!total &amp;&amp; !busy &amp;&amp; mode !== 'sym' &amp;&amp; inputType !== 'url'" class="candidate-placeholder" :style="themeStyles.dim">{{secret ? '私密输入' : '选择候选词'}}</p><button if="mode !== 'sym' &amp;&amp; total" id="ime-expand" class="more icon-button" :style="themeStyles.icon" on:click="expand"><image class="icon" src="/assets/ime-icons/arrow-down-s-line.png" /></button></div>
<div class="keypad"> <div id="ime-keypad" class="keypad">
<div for="row in layoutRows" class="keyrow" :style="row.style"><button for="key in row.keys" class="key" :style="keyStyle" on:click="press(key.value)"><p class="key-label" :style="labelStyle">{{key.label}}</p><p if="key.sub" class="key-sub">{{key.sub}}</p></button></div> <div for="row in layoutRows" class="keyrow" :style="row.style"><button for="key in row.keys" class="key" :style="keyStyle" on:click="press(key.value)"><p class="key-label" :style="labelStyle">{{key.label}}</p><p if="key.sub" class="key-sub" :style="themeStyles.dim">{{key.sub}}</p></button></div>
</div> </div>
<div class="modes"><button id="ime-chinese" on:click="chinese">{{mode === 't9' ? '26键' : '九宫'}}</button><button id="ime-14" :style="mode === '14' ? 'color:#2867D9' : ''" on:click="fourteen">14键</button><button on:click="english">{{upper ? 'ABC' : 'abc'}}</button><button on:click="numbers">123</button><button on:click="symbols">符号</button><button id="ime-tools" class="icon-button" on:click="showTools"><image class="icon small-icon" src="/assets/ime-icons/edit-2-line.png" /></button></div> <div class="modes"><button id="ime-chinese" :style="themeStyles.plain" on:click="chinese">{{mode === 't9' ? '26键' : '九宫'}}</button><button id="ime-14" :style="mode === '14' ? themeStyles.accent : themeStyles.muted" on:click="fourteen">14键</button><button :style="themeStyles.card" on:click="english">{{upper ? 'ABC' : 'abc'}}</button><button :style="themeStyles.card" on:click="numbers">123</button><button :style="themeStyles.card" on:click="symbols">符号</button><button id="ime-tools" class="icon-button" :style="themeStyles.icon" on:click="showTools"><image class="icon small-icon" src="/assets/ime-icons/edit-2-line.png" /></button></div>
<div class="bottom"><button id="ime-space" on:click="space">空格</button><button id="ime-delete" class="delete icon-button" on:touchstart="startDelete" on:touchend="endDelete"><image class="icon" src="/assets/ime-icons/delete-back-2-line.png" /></button><button id="ime-finish" class="done icon-button" on:click="finish"><image class="icon" src="/assets/ime-icons/check-line.png" /></button></div> <div class="bottom"><button id="ime-space" :style="themeStyles.card" on:click="space">空格</button><button id="ime-delete" class="delete icon-button" :style="themeStyles.icon" on:touchstart="startDelete" on:touchend="endDelete"><image class="icon" src="/assets/ime-icons/delete-back-2-line.png" /></button><button id="ime-finish" class="done icon-button" :style="themeStyles.primary" on:click="finish"><image class="icon" src="/assets/ime-icons/check-line.png" /></button></div>
</div> </div>
<div if="panel === 'candidates'" class="body expanded"> <div if="panel === 'candidates'" class="body expanded">
<p class="page-info">完整候选 · {{total}} 项 · {{candidatePage + 1}}/{{pageCount}}</p> <p class="page-info" :style="themeStyles.dim">完整候选 · {{total}} 项 · {{candidatePage + 1}}/{{pageCount}}</p>
<div class="full-list"><div for="row in candidateRows" class="candidate-grid-row" :style="row.style"><button for="entry in row.items" class="full-candidate" :style="entry.style" on:click="choose(entry.item)"><p class="word" :style="entry.labelStyle">{{entry.item.word}}</p></button></div><p if="total === 0" class="empty">{{busy ? '正在查词…' : '继续输入后查看候选'}}</p></div> <div class="full-list"><div for="row in candidateRows" class="candidate-grid-row" :style="row.style"><button for="entry in row.items" class="full-candidate" :style="entry.style" on:click="choose(entry.item)"><p class="word" :style="entry.labelStyle">{{entry.item.word}}</p></button></div><p if="total === 0" class="empty" :style="themeStyles.dim">{{busy ? '正在查词…' : '继续输入后查看候选'}}</p></div>
<div class="pager"><button id="ime-page-prev" class="icon-button" on:click="previousPage"><image class="icon" src="/assets/ime-icons/arrow-left-s-line.png" /></button><button id="ime-page-next" class="icon-button" on:click="nextPage"><image class="icon" src="/assets/ime-icons/arrow-right-s-line.png" /></button></div> <div class="pager"><button id="ime-page-prev" class="icon-button" :style="themeStyles.icon" on:click="previousPage"><image class="icon" src="/assets/ime-icons/arrow-left-s-line.png" /></button><button id="ime-page-next" class="icon-button" :style="themeStyles.icon" on:click="nextPage"><image class="icon" src="/assets/ime-icons/arrow-right-s-line.png" /></button></div>
<div class="bottom"><button id="ime-back" class="icon-button" on:click="closePanel"><image class="icon" src="/assets/ime-icons/keyboard-box-line.png" /></button><button id="ime-delete" class="delete icon-button" on:click="backspace"><image class="icon" src="/assets/ime-icons/delete-back-2-line.png" /></button><button id="ime-finish" class="done icon-button" on:click="finish"><image class="icon" src="/assets/ime-icons/check-line.png" /></button></div> <div class="bottom"><button id="ime-back" class="icon-button" :style="themeStyles.icon" on:click="closePanel"><image class="icon" src="/assets/ime-icons/keyboard-box-line.png" /></button><button id="ime-delete" class="delete icon-button" :style="themeStyles.icon" on:click="backspace"><image class="icon" src="/assets/ime-icons/delete-back-2-line.png" /></button><button id="ime-finish" class="done icon-button" :style="themeStyles.primary" on:click="finish"><image class="icon" src="/assets/ime-icons/check-line.png" /></button></div>
</div> </div>
<div if="panel === 'tools'" class="body tools"> <div if="panel === 'tools'" class="body tools">
<p class="page-info">{{secret ? '私密输入 · 不学习、不保存' : '光标编辑 · 输入仅保留在本机'}}</p> <p class="page-info" :style="themeStyles.dim">{{secret ? '私密输入 · 不学习、不保存' : '光标编辑 · 输入仅保留在本机'}}</p>
<div class="toolrow"><button on:click="cursorLeft">← 左移</button><button on:click="cursorRight">右移 →</button></div> <div class="toolrow"><button :style="themeStyles.card" on:click="cursorLeft">← 左移</button><button :style="themeStyles.card" on:click="cursorRight">右移 →</button></div>
<div class="toolrow"><button on:click="cursorStart">到开头</button><button on:click="cursorEnd">到末尾</button></div> <div class="toolrow"><button :style="themeStyles.card" on:click="cursorStart">到开头</button><button :style="themeStyles.card" on:click="cursorEnd">到末尾</button></div>
<div class="toolrow"><button on:click="newline">换行</button><button on:click="rawInput">拼音上屏</button></div> <div class="toolrow"><button :style="themeStyles.card" on:click="newline">换行</button><button :style="themeStyles.card" on:click="rawInput">拼音上屏</button></div>
<div class="toolrow"><button on:click="toggleLearning">{{learning ? '学习:开' : '学习:关'}}</button><button on:click="clearPreferences">清除学习</button></div> <div class="toolrow"><button :style="themeStyles.card" on:click="toggleLearning">{{learning ? '学习:开' : '学习:关'}}</button><button :style="themeStyles.card" on:click="clearPreferences">清除学习</button></div>
<div class="toolrow"><button class="danger" on:click="clearText">{{clearArmed ? '确认清空' : '清空全文'}}</button><button on:click="backspace">删除一字</button></div> <div class="toolrow"><button class="danger" :style="themeStyles.danger" on:click="clearText">{{clearArmed ? '确认清空' : '清空全文'}}</button><button :style="themeStyles.card" on:click="backspace">删除一字</button></div>
<div class="bottom"><button id="ime-back" class="icon-button" on:click="closePanel"><image class="icon" src="/assets/ime-icons/keyboard-box-line.png" /></button><button id="ime-finish" class="done icon-button" on:click="finish"><image class="icon" src="/assets/ime-icons/check-line.png" /></button></div> <div class="bottom"><button id="ime-back" class="icon-button" :style="themeStyles.icon" on:click="closePanel"><image class="icon" src="/assets/ime-icons/keyboard-box-line.png" /></button><button id="ime-finish" class="done icon-button" :style="themeStyles.primary" on:click="finish"><image class="icon" src="/assets/ime-icons/check-line.png" /></button></div>
</div> </div>
</div> </div>
</div> </div>
@@ -39,31 +39,33 @@
p{margin:0;color:#20232B;font-size:.62rem}button{padding:0;margin:3px;border-radius:12px;color:#20232B;background-color:#FFFFFF;font-size:.65rem;flex-shrink:0}button:active{background-color:#D7E5FF} p{margin:0;color:#20232B;font-size:.62rem}button{padding:0;margin:3px;border-radius:12px;color:#20232B;background-color:#FFFFFF;font-size:.65rem;flex-shrink:0}button:active{background-color:#D7E5FF}
.icon-button{display:flex;align-items:center;justify-content:center}.icon{width:24px;height:24px;object-fit:contain}.small-icon{width:20px;height:20px} .icon-button{display:flex;align-items:center;justify-content:center}.icon{width:24px;height:24px;object-fit:contain}.small-icon{width:20px;height:20px}
.top,.composition,.candidates,.keyrow,.modes,.bottom,.pager,.toolrow{display:flex;flex-direction:row;align-items:center;justify-content:center;flex-shrink:0} .top,.composition,.candidates,.keyrow,.modes,.bottom,.pager,.toolrow{display:flex;flex-direction:row;align-items:center;justify-content:center;flex-shrink:0}
.top{height:27px}.cancel{width:44px;height:27px;background-color:transparent;color:#2867D9;font-size:.53rem}.title{flex:1;text-align:center;font-size:.55rem;color:#737984}.count{width:44px;font-size:.4rem;text-align:right;color:#9297A1} .top{height:27px}.cancel{width:44px;height:27px;background-color:transparent;color:#2867D9;font-size:.53rem}.title{flex:1;text-align:center;font-size:.5rem;color:#737984}.count{width:44px;font-size:.4rem;text-align:right;color:#9297A1}
.preview{height:43px;margin:7px 7px 3px;padding:0 14px;background-color:#FFFFFF;text-align:left;font-size:.82rem;color:#20232B;border-radius:13px} .preview{height:43px;margin:7px 7px 3px;padding:0 14px;background-color:#FFFFFF;text-align:left;font-size:.82rem;color:#20232B;border-radius:13px}
.composition{height:24px;padding:0 12px}.spelling{flex:1;color:#2867D9;font-size:.55rem}.hint{color:#8B909A;font-size:.38rem;text-align:right} .composition{height:24px;padding:0 12px}.spelling{flex:1;color:#2867D9;font-size:.55rem}.hint{color:#8B909A;font-size:.38rem;text-align:right}
.body,.keypad,.full-list{display:flex;flex-direction:column;align-items:stretch;min-height:0}.body{flex:1;justify-content:center}.keypad{flex-shrink:0} .body,.keypad,.full-list{display:flex;flex-direction:column;align-items:stretch;min-height:0}.body{flex:1;justify-content:flex-start}.keypad{flex-shrink:0}
.candidates{height:42px;margin:0 4px 4px;background-color:#F8F9FB;border-radius:12px}.candidate{flex:1;min-width:45px;height:36px;background-color:transparent;color:#20232B;font-size:.78rem}.candidate-placeholder{flex:1;text-align:center;color:#A4A9B2;font-size:.45rem}.more{width:46px;height:36px;background-color:transparent;font-size:.5rem;color:#2867D9} .candidates{height:42px;margin:0 4px 4px;background-color:#F8F9FB;border-radius:12px}.candidate{flex:1;min-width:45px;height:36px;background-color:transparent;color:#20232B;font-size:.78rem}.candidate-placeholder{flex:1;text-align:center;color:#A4A9B2;font-size:.45rem}.more{width:46px;height:36px;background-color:transparent;font-size:.5rem;color:#2867D9}
.keyrow{align-items:stretch;align-self:center;width:100%}.key{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;height:52px;min-width:0;background-color:#FFFFFF;border-radius:12px}.key-label{font-size:.88rem;color:#22252E}.key-sub{font-size:.35rem;color:#9DA2AD;margin-top:1px} .keyrow{align-items:stretch;align-self:center;width:100%}.key{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;height:52px;min-width:0;background-color:#FFFFFF;border-radius:12px}.key-label{font-size:.88rem;color:#22252E}.key-sub{font-size:.35rem;color:#9DA2AD;margin-top:1px}
.modes{height:36px;margin-top:3px}.modes button{flex:1;height:31px;background-color:transparent;font-size:.53rem;color:#636A77} .modes{height:36px;margin-top:3px}.modes button{flex:1;height:31px;background-color:transparent;font-size:.53rem;color:#636A77}
.bottom{height:41px;margin-top:2px}.bottom button{flex:1;height:37px;font-size:.6rem;background-color:#FFFFFF}.bottom .done{background-color:#2867D9;color:#FFFFFF}.bottom .delete{background-color:#D9DDE4;color:#515866} .bottom{height:41px;margin-top:2px}.bottom button{flex:1;height:37px;font-size:.6rem;background-color:#FFFFFF}.bottom .done{background-color:#2867D9;color:#FFFFFF}.bottom .delete{background-color:#D9DDE4;color:#515866}
.page-info{text-align:center;color:#8B919D;font-size:.45rem;margin:5px 0;flex-shrink:0}.full-list{flex:1;justify-content:center}.candidate-grid-row{display:flex;flex-direction:row;align-self:flex-start;align-items:stretch;flex-shrink:0}.full-candidate{display:flex;align-items:center;justify-content:center;flex:1;min-width:0;margin:2px;padding:2px 4px;background-color:#FFFFFF;border-radius:10px}.word{width:100%;text-align:center;font-size:25px;color:#22252E}.empty{margin:15px 8px;color:#9299A5;text-align:center} .page-info{text-align:center;color:#8B919D;font-size:.45rem;margin:5px 0;flex-shrink:0}.full-list{flex:1;justify-content:flex-start}.candidate-grid-row{display:flex;flex-direction:row;align-self:flex-start;align-items:stretch;flex-shrink:0}.full-candidate{display:flex;align-items:center;justify-content:center;flex:1;min-width:0;margin:2px;padding:2px 4px;background-color:#FFFFFF;border-radius:10px}.word{width:100%;text-align:center;font-size:25px;color:#22252E}.empty{margin:15px 8px;color:#9299A5;text-align:center}
.pager{height:38px}.pager button{flex:1;height:34px;background-color:transparent;color:#2867D9;font-size:.55rem}.toolrow button{flex:1;height:40px;font-size:.57rem}.tools{justify-content:center}.tools .danger{color:#C85656}.tools .bottom{margin-top:8px} .pager{height:38px}.pager button{flex:1;height:34px;background-color:transparent;color:#2867D9;font-size:.55rem}.toolrow button{flex:1;height:40px;font-size:.57rem}.tools{justify-content:center}.tools .danger{color:#C85656}.tools .bottom{margin-top:8px}
@media (shape:circle){.ime{padding:30px 8px}.top{align-self:center;width:186px;height:24px}.cancel{height:24px}.preview{align-self:center;width:280px;height:32px;margin-top:5px}.composition{align-self:center;width:300px;height:19px}.candidates{align-self:center;width:352px;height:38px}.candidate{height:34px}.more{height:34px}.keypad{align-self:center;width:376px}.key{height:49px}.modes{align-self:center;width:286px;height:33px}.modes button{height:29px}.bottom{align-self:center;width:200px;height:38px}.bottom button{height:34px}.full-list{align-self:center;width:340px}.pager{align-self:center;width:276px}.toolrow{align-self:center;width:300px}.toolrow button{height:35px}.tools .page-info{align-self:center;width:280px}.tools .bottom{margin-top:4px}} @media (shape:circle){.ime{padding:30px 8px}.top{align-self:center;width:186px;height:24px}.cancel{height:24px}.preview{align-self:center;width:280px;height:32px;margin-top:5px}.composition{align-self:center;width:300px;height:23px}.candidates{align-self:center;width:352px;height:38px}.candidate{height:34px}.more{height:34px}.keypad{align-self:center;width:368px}.key{height:49px}.modes{align-self:center;width:286px;height:33px}.modes button{height:29px}.bottom{align-self:center;width:200px;height:38px}.bottom button{height:34px}.full-list{align-self:center;width:340px}.pager{align-self:center;width:276px}.toolrow{align-self:center;width:300px}.toolrow button{height:34px}.tools .page-info{align-self:center;width:280px}.tools .bottom{margin-top:4px}}
</style> </style>
<script> <script>
import file from '@system.file' import file from '@system.file'
import storage from '@system.storage' import storage from '@system.storage'
import router from '@system.router' import router from '@system.router'
import {normalizeTheme, themeStyles as stylesForTheme} from '../common/ime-theme.js'
import {createDictionary,chars,candidatePages,edit,erase,preview,learn,sanitizePreferences,KEY14_GROUPS,display14} from '../common/ime-engine.js' import {createDictionary,chars,candidatePages,edit,erase,preview,learn,sanitizePreferences,KEY14_GROUPS,display14} from '../common/ime-engine.js'
const LETTERS=['qwertyuiop','asdfghjkl','zxcvbnm'] const LETTERS=['qwertyuiop','asdfghjkl','zxcvbnm']
const SYMBOLS=['!"#$%&',"'()*+,",'-./:;<','=>?@[\\',']^_`{|','}~,。?!'] const SYMBOLS=['!"#$%&',"'()*+,",'-./:;<','=>?@[\\',']^_`{|','}~,。?!']
function keys(rows){return rows.map(row=>Array.from(row).map(value=>({label:value,value:value,sub:''})))} function keys(rows){return rows.map(row=>Array.from(row).map(value=>({label:value,value:value,sub:''})))}
export default { export default {
data:{initial:'',title:'蟹蟹输入',inputType:'text',maxLength:2048,allowNewline:true,secret:false,text:'',cursor:0,composition:'',compositionDisplay:'',display:'│',count:0,limit:2048,mode:'t9',modeLabel:'九宫拼音',upper:false,symbolPage:0,panel:'keys',keyRows:[],layoutRows:[],keyStyle:'',labelStyle:'',bar:[],visibleCandidates:[],candidateRows:[],total:0,candidatePage:0,pageCount:1,busy:false,hint:'离线全量词库',learning:false,clearArmed:false}, data:{titleLabel:'蟹蟹输入',inputTheme:'bluewhite',themeStyles:stylesForTheme('bluewhite'),initial:'',title:'蟹蟹输入',inputType:'text',maxLength:2048,allowNewline:true,secret:false,text:'',cursor:0,composition:'',compositionDisplay:'',display:'│',count:0,limit:2048,mode:'t9',modeLabel:'九宫拼音',upper:false,symbolPage:0,panel:'keys',keyRows:[],layoutRows:[],keyStyle:'',labelStyle:'',bar:[],visibleCandidates:[],candidateRows:[],total:0,candidatePage:0,pageCount:1,busy:false,hint:'离线全量词库',learning:false,clearArmed:false},
dictionary:null,preferences:{},allCandidates:[],pages:[],active:true,life:null,requestId:0,lookupTimer:null,repeatTimer:null,repeatDelay:null,result:null,original:'', dictionary:null,preferences:{},allCandidates:[],pages:[],active:true,life:null,requestId:0,lookupTimer:null,repeatTimer:null,repeatDelay:null,result:null,original:'',
onInit(){ onInit(){
this.titleLabel=chars(this.title).slice(0,4).join('')+(chars(this.title).length>4?'…':'');this.inputTheme=normalizeTheme(this.inputTheme);this.themeStyles=stylesForTheme(this.inputTheme)
this.life={active:true,id:0};this.secret=!!this.secret||this.inputType==='password' this.life={active:true,id:0};this.secret=!!this.secret||this.inputType==='password'
this.limit=Math.floor(Math.max(1,Math.min(4096,Number(this.maxLength)||2048))) this.limit=Math.floor(Math.max(1,Math.min(4096,Number(this.maxLength)||2048)))
this.text=chars(this.initial).slice(0,this.limit).join('');this.original=this.text;this.cursor=chars(this.text).length this.text=chars(this.initial).slice(0,this.limit).join('');this.original=this.text;this.cursor=chars(this.text).length
@@ -84,9 +86,9 @@
else if(this.mode==='sym')this.keyRows=keys(SYMBOLS.slice(this.symbolPage*3,this.symbolPage*3+3)) else if(this.mode==='sym')this.keyRows=keys(SYMBOLS.slice(this.symbolPage*3,this.symbolPage*3+3))
else if(this.mode==='14'){const all=KEY14_GROUPS.map((group,index)=>({label:group.toUpperCase(),value:'0123456789abcd'[index],sub:''}));this.keyRows=[all.slice(0,5),all.slice(5,10),all.slice(10)]} else if(this.mode==='14'){const all=KEY14_GROUPS.map((group,index)=>({label:group.toUpperCase(),value:'0123456789abcd'[index],sub:''}));this.keyRows=[all.slice(0,5),all.slice(5,10),all.slice(10)]}
else this.keyRows=keys(LETTERS.map(row=>this.upper&&this.mode==='en'?row.toUpperCase():row)) else this.keyRows=keys(LETTERS.map(row=>this.upper&&this.mode==='en'?row.toUpperCase():row))
this.keyStyle='height:'+(this.keyRows.length<=3?'49':this.keyRows.length===4?'38':this.keyRows.length===5?'28':'22')+'px' this.keyStyle='height:'+(this.keyRows.length<=3?'49':this.keyRows.length===4?'38':this.keyRows.length===5?'28':'22')+'px;'+this.themeStyles.card
const qwerty=this.mode==='py'||this.mode==='en' const qwerty=this.mode==='py'||this.mode==='en'
this.labelStyle=qwerty?'font-size:22px':this.mode==='14'?'font-size:24px':'' this.labelStyle=(qwerty?'font-size:22px;':this.mode==='14'?'font-size:24px;':'')+this.themeStyles.ink
this.layoutRows=this.keyRows.map((row,index)=>({keys:row,style:'width:'+(qwerty?['100','94','84'][index]:index===this.keyRows.length-1?'91':'100')+'%'})) this.layoutRows=this.keyRows.map((row,index)=>({keys:row,style:'width:'+(qwerty?['100','94','84'][index]:index===this.keyRows.length-1?'91':'100')+'%'}))
this.modeLabel={t9:'九宫拼音',py:'26键全拼 · v 代表 ü','14':'14键拼音',en:this.upper?'英文大写':'英文小写',num:'数字',sym:'符号 · '+(this.symbolPage+1)+'/2'}[this.mode] this.modeLabel={t9:'九宫拼音',py:'26键全拼 · v 代表 ü','14':'14键拼音',en:this.upper?'英文大写':'英文小写',num:'数字',sym:'符号 · '+(this.symbolPage+1)+'/2'}[this.mode]
this.compositionDisplay=this.mode==='14'?display14(this.composition):this.composition this.compositionDisplay=this.mode==='14'?display14(this.composition):this.composition
@@ -118,7 +120,7 @@
}catch(error){if(life.active&&id===life.id)this.hint='词库暂不可用,可切换英文输入'} }catch(error){if(life.active&&id===life.id)this.hint='词库暂不可用,可切换英文输入'}
finally{if(life.active&&id===life.id)this.busy=false} finally{if(life.active&&id===life.id)this.busy=false}
}, },
pageCandidates(){const rows=this.pages[this.candidatePage]||[];this.visibleCandidates=[];this.candidateRows=rows.map(row=>({style:'height:'+(row.units*43)+'px;width:'+(row.slots*25)+'%',items:row.items.map(entry=>{this.visibleCandidates.push(entry.item);return {item:entry.item,style:'flex:'+entry.span+';height:'+(row.units*43-4)+'px',labelStyle:'font-size:'+(entry.span===1?25:entry.span===2?23:20)+'px'}})}))}, pageCandidates(){const rows=this.pages[this.candidatePage]||[];this.visibleCandidates=[];this.candidateRows=rows.map(row=>({style:'height:'+(row.units*43)+'px;width:'+(row.slots*25)+'%',items:row.items.map(entry=>{this.visibleCandidates.push(entry.item);return {item:entry.item,style:'flex:'+entry.span+';height:'+(row.units*43-4)+'px;'+this.themeStyles.card,labelStyle:'font-size:'+(entry.span===1?25:entry.span===2?23:20)+'px;'+this.themeStyles.ink}})}))},
choose(item){ choose(item){
if(this.busy||!this.composition||!this.allCandidates.some(x=>x.word===item.word&&x.pinyin===item.pinyin&&x.consume===item.consume))return if(this.busy||!this.composition||!this.allCandidates.some(x=>x.word===item.word&&x.pinyin===item.pinyin&&x.consume===item.consume))return
if(chars(this.text).length+chars(item.word).length>this.limit){this.hint='剩余空间不足,未截断候选词';return} if(chars(this.text).length+chars(item.word).length>this.limit){this.hint='剩余空间不足,未截断候选词';return}
+16 -4
查看文件
@@ -2,9 +2,21 @@
"package": "com.sydxky.rtos.inputmethod", "package": "com.sydxky.rtos.inputmethod",
"name": "蟹蟹输入", "name": "蟹蟹输入",
"icon": "/assets/icon.png", "icon": "/assets/icon.png",
"versionName": "1.2.0", "versionName": "1.2.2",
"versionCode": 10200, "versionCode": 10202,
"features": [], "features": [],
"router": {"entry": "main", "pages": {"main": {"component": "index"}, "keyboard": {"component": "index"}}}, "router": {
"config": {"designWidth": 410} "entry": "main",
"pages": {
"main": {
"component": "index"
},
"keyboard": {
"component": "index"
}
}
},
"config": {
"designWidth": 410
}
} }
@@ -2,6 +2,7 @@ import fs from 'node:fs'
import vm from 'node:vm' import vm from 'node:vm'
import assert from 'node:assert/strict' import assert from 'node:assert/strict'
import * as engine from '../src/common/ime-engine.js' import * as engine from '../src/common/ime-engine.js'
import {normalizeTheme,themeStyles as stylesForTheme} from '../src/common/ime-theme.js'
const ux=fs.readFileSync(new URL('../src/keyboard/index.ux',import.meta.url),'utf8') const ux=fs.readFileSync(new URL('../src/keyboard/index.ux',import.meta.url),'utf8')
const source=ux.match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^\s*import .+$/gm,'').replace('export default','module.exports=') const source=ux.match(/<script>([\s\S]*?)<\/script>/)[1].replace(/^\s*import .+$/gm,'').replace('export default','module.exports=')
let count=0 let count=0
@@ -9,7 +10,7 @@ const closed=[],store=new Map(),timers=new Map();let nextTimer=1,storageFails=fa
function check(ok,label){assert.ok(ok,label);count++} function check(ok,label){assert.ok(ok,label);count++}
function page(params={}){ function page(params={}){
const module={exports:{}} const module={exports:{}}
vm.runInNewContext(source,{module,console,...engine,router:{close(p,r){closed.push(r)}},storage:{get:k=>store.get(k),set:(k,v)=>{if(storageFails)throw Error('storage full');store.set(k,v)},delete:k=>store.delete(k)},file:{readText:async({uri})=>fs.readFileSync(new URL('../src'+uri,import.meta.url),'utf8')},setTimeout:fn=>{const id=nextTimer++;timers.set(id,fn);return id},clearTimeout:id=>timers.delete(id),setInterval:fn=>{const id=nextTimer++;timers.set(id,fn);return id},clearInterval:id=>timers.delete(id)}) vm.runInNewContext(source,{module,console,...engine,normalizeTheme,stylesForTheme,router:{close(p,r){closed.push(r)}},storage:{get:k=>store.get(k),set:(k,v)=>{if(storageFails)throw Error('storage full');store.set(k,v)},delete:k=>store.delete(k)},file:{readText:async({uri})=>fs.readFileSync(new URL('../src'+uri,import.meta.url),'utf8')},setTimeout:fn=>{const id=nextTimer++;timers.set(id,fn);return id},clearTimeout:id=>timers.delete(id),setInterval:fn=>{const id=nextTimer++;timers.set(id,fn);return id},clearInterval:id=>timers.delete(id)})
const p={...module.exports,...JSON.parse(JSON.stringify(module.exports.data)),...params};delete p.data;p.onInit();return p const p={...module.exports,...JSON.parse(JSON.stringify(module.exports.data)),...params};delete p.data;p.onInit();return p
} }
let p=page();check(p.mode==='t9'&&!p.learning,'T9 large keys, learning opt-in') let p=page();check(p.mode==='t9'&&!p.learning,'T9 large keys, learning opt-in')
+11 -2
查看文件
@@ -17,12 +17,13 @@ def inspect(path,profile):
visible_pages(frame['widgets']) visible_pages(frame['widgets'])
page=pages[-1] page=pages[-1]
circle=profile.startswith('round');width=466 if circle else 390;height=466 if circle else 450 circle=profile.startswith('round');width=466 if circle else 390;height=466 if circle else 450
failures=[];buttons=[];icons=[] failures=[];buttons=[];icons=[];regions={}
def visit(node,ancestors=(),px=0,py=0,visible=True): def visit(node,ancestors=(),px=0,py=0,visible=True):
g=node['geometry'];x=px+g['x'];y=py+g['y'];w=g['w'];h=g['h'] g=node['geometry'];x=px+g['x'];y=py+g['y'];w=g['w'];h=g['h']
visible=visible and node.get('visible',True) visible=visible and node.get('visible',True)
if not visible:return if not visible:return
box=[x,y,w,h];kind=node['class'];identifier=node.get('id','') box=[x,y,w,h];kind=node['class'];identifier=node.get('id','')
if identifier in ['ime-preview','ime-composition','ime-keypad','ime-candidate-strip']:regions[identifier]=box
if kind in ['Button','ImageBox','Label']: if kind in ['Button','ImageBox','Label']:
for ancestor in ancestors: for ancestor in ancestors:
ax,ay,aw,ah=ancestor['box'] ax,ay,aw,ah=ancestor['box']
@@ -36,4 +37,12 @@ def inspect(path,profile):
(buttons if kind=='Button'else icons).append(record) (buttons if kind=='Button'else icons).append(record)
for child in node.get('children',[]):visit(child,ancestors+({'class':kind,'id':identifier,'box':box},),x,y,visible) for child in node.get('children',[]):visit(child,ancestors+({'class':kind,'id':identifier,'box':box},),x,y,visible)
visit(page) visit(page)
return {'page':page.get('id'),'buttons':len(buttons),'icons':len(icons),'max_button_radius':round(max([b['radius']or 0 for b in buttons],default=0),2),'failures':failures,'passed':not failures} gaps={}
if 'ime-composition' in regions and 'ime-keypad' in regions:
compose=regions['ime-composition'];keys=regions['ime-keypad']
gap=keys[1]-compose[1]-compose[3];gaps['composition_to_keys']=gap
# Account for the actual visible strip; direct entry may leave at most
# one rounding pixel, never an unused candidate-sized band.
maximum=(48 if circle else 53)if 'ime-candidate-strip' in regions else 1
if gap < -1 or gap > maximum:failures.append({'reason':'extra gap before keyboard','gap':gap,'maximum':maximum})
return {'page':page.get('id'),'buttons':len(buttons),'icons':len(icons),'gaps':gaps,'max_button_radius':round(max([b['radius']or 0 for b in buttons],default=0),2),'failures':failures,'passed':not failures}
+38 -15
查看文件
@@ -1,20 +1,43 @@
# 1.2.0 实际界面 # 1.2.2 实际界面
Android 图来自 OWW261 真机,RTOS 图来自 Glyphix 原生模拟器。预览拼图仅移除 RTOS 模拟器外壳,以下保留完整原始截图。未使用设计稿替代实际界面。 Android来自OWW261真机;RTOS来自Glyphix原生模拟器。拼图只裁掉圆屏模拟器外壳,以下保留原始帧。
## Android 应用内组件 ![1.2.2实际界面](screenshots/android-english.png)
![演示首页](screenshots/android-home.png) ![1.2.2实际界面](screenshots/android-number.png)
![16 个单字一页](screenshots/android-candidates-16.png)
![完整 QWERTY](screenshots/android-qwerty.png)
![14 键](screenshots/android-fourteen.png)
![词组自适应](screenshots/android-phrases.png)
![选词回填](screenshots/android-result.png)
![独立应用接入](screenshots/android-host.png)
## Glyphix RTOS ![1.2.2实际界面](screenshots/android-symbols.png)
![圆屏候选](screenshots/rtos-round-candidates.png) ![1.2.2实际界面](screenshots/rtos-rect-en.png)
![圆屏 14 键](screenshots/rtos-round-14-key.png)
![圆屏词组](screenshots/rtos-round-phrase-candidates.png) ![1.2.2实际界面](screenshots/rtos-rect-num.png)
![方屏候选](screenshots/rtos-rect-candidates.png)
![1.2.2实际界面](screenshots/rtos-round-en.png)
![1.2.2实际界面](screenshots/rtos-round-num.png)
## 1.2.0 历史截图
保留旧版候选与接入示例,以下不作为1.2.2验收证据。
![1.2.0历史界面](screenshots/android-candidates-16.png)
![1.2.0历史界面](screenshots/android-fourteen.png)
![1.2.0历史界面](screenshots/android-home.png)
![1.2.0历史界面](screenshots/android-host.png)
![1.2.0历史界面](screenshots/android-phrases.png)
![1.2.0历史界面](screenshots/android-qwerty.png)
![1.2.0历史界面](screenshots/android-result.png)
![1.2.0历史界面](screenshots/rtos-rect-candidates.png)
![1.2.0历史界面](screenshots/rtos-round-14-key.png)
![1.2.0历史界面](screenshots/rtos-round-candidates.png)
![1.2.0历史界面](screenshots/rtos-round-phrase-candidates.png)
二进制
查看文件
二进制文件未显示。

之前

宽度:  |  高度:  |  大小: 185 KiB

之后

宽度:  |  高度:  |  大小: 173 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 26 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 23 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 25 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 28 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 26 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 146 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 144 KiB