/* * Copyright (C) 2015-present, osfans * waxaca@163.com https://github.com/osfans * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.osfans.trime; import android.view.KeyEvent; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** {@link Key 按鍵}的各種事件(單擊、長按、滑動等) */ public class Event { private String TAG = "Event"; private Keyboard mKeyboard; private int code = 0; private int mask = 0; private String text; private String label; private String preview; private List states; private String command; private String option; private String select; private String toggle; private String commit; private String shiftLock; private boolean functional; private boolean repeatable; private boolean sticky; public Event(Keyboard keyboard, String s) { mKeyboard = keyboard; if (s.matches("\\{[^\\{\\}]+\\}")) { //{send|key} label = s.substring(1, s.length() -1); int[] sends = parseSend(label); //send code = sends[0]; mask = sends[1]; if (code >= 0) return; s = label; //key label = null; } if (Key.presetKeys.containsKey(s)) { Map m = Key.presetKeys.get(s); command = Config.getString(m, "command"); option = Config.getString(m, "option"); select = Config.getString(m, "select"); toggle = Config.getString(m, "toggle"); label = Config.getString(m, "label"); preview = Config.getString(m, "preview"); shiftLock = Config.getString(m, "shift_lock"); commit = Config.getString(m, "commit"); String send = Config.getString(m, "send"); if (Function.isEmpty(send) && !Function.isEmpty(command)) send = "function"; //command默認發function int[] sends = parseSend(send); code = sends[0]; mask = sends[1]; parseLabel(); text = Config.getString(m, "text"); if (code < 0 && Function.isEmpty(text)) text = s; if (m.containsKey("states")) states = (List) m.get("states"); sticky = Config.getBoolean(m, "sticky", false); repeatable = Config.getBoolean(m, "repeatable", false); functional = Config.getBoolean(m, "functional", true); } else if ((code = getClickCode(s)) >= 0) { parseLabel(); } else { code = 0; text = s; label = s.replaceAll("\\{[^\\{\\}]+?\\}", ""); } } public Event(String s) { this(null, s); } public int getCode() { return code; } public int getMask() { return mask; } public String getCommand() { return command; } public String getOption() { return option; } public String getSelect() { return select; } public boolean isFunctional() { return functional; } public boolean isRepeatable() { return repeatable; } public boolean isSticky() { return sticky; } public String getShiftLock() { return shiftLock; } public static int[] parseSend(String s) { int[] sends = new int[2]; if (Function.isEmpty(s)) return sends; String codes; if (!s.contains("+")) codes = s; else { String[] ss = s.split("\\+"); int n = ss.length; for (int i = 0; i < n - 1; i++) if (masks.containsKey(ss[i])) sends[1] |= masks.get(ss[i]); codes = ss[n - 1]; } sends[0] = Key.androidKeys.indexOf(codes); return sends; } private String adjustCase(String s) { if (Function.isEmpty(s)) return ""; if (s.length() == 1 && mKeyboard != null && mKeyboard.isShifted()) s = s.toUpperCase(Locale.getDefault()); else if (s.length() == 1 && mKeyboard != null && !Rime.isAsciiMode() && mKeyboard.isLabelUppercase()) s = s.toUpperCase(Locale.getDefault()); return s; } public String getLabel() { if (!Function.isEmpty(toggle)) return states.get(Rime.getOption(toggle) ? 1 : 0); return adjustCase(label); } public String getText() { String s = ""; if (!Function.isEmpty(text)) s = text; else if (mKeyboard != null && mKeyboard.isShifted() && mask == 0 && code >= KeyEvent.KEYCODE_A && code <= KeyEvent.KEYCODE_Z) s = label; return adjustCase(s); } public String getPreviewText() { if (!Function.isEmpty(preview)) return preview; return getLabel(); } public String getToggle() { if (!Function.isEmpty(toggle)) return toggle; return "ascii_mode"; } public String getCommit() { return commit; } private void parseLabel() { if (!Function.isEmpty(label)) return; int c = code; if (c == KeyEvent.KEYCODE_SPACE) { label = Rime.getSchemaName(); } else { if (c > 0) label = getDisplayLabel(c); } } public static String getDisplayLabel(int keyCode) { String s = ""; if (keyCode < Key.getSymbolStart()) { //字母數字 if (Key.getKcm().isPrintingKey(keyCode)) { char c = Key.getKcm().getDisplayLabel(keyCode); if (Character.isUpperCase(c)) c = Character.toLowerCase(c); s = String.valueOf(c); } else { s = Key.androidKeys.get(keyCode); } } else if (keyCode < Key.androidKeys.size()) { //可見符號 keyCode -= Key.getSymbolStart(); s = Key.getSymbols().substring(keyCode, keyCode + 1); } return s; } public static int getClickCode(String s) { int keyCode = -1; if (Function.isEmpty(s)) { //空鍵 keyCode = 0; } else if (Key.androidKeys.contains(s)) { //字母數字 keyCode = Key.androidKeys.indexOf(s); } else if (Key.getSymbols().contains(s)) { //可見符號 keyCode = Key.getSymbolStart() + Key.getSymbols().indexOf(s); } else if (symbolAliases.containsKey(s)) { keyCode = symbolAliases.get(s); } return keyCode; } private static int getRimeCode(int code) { int i = 0; if (code >= 0 && code < Key.androidKeys.size()) { String s = Key.androidKeys.get(code); i = Rime.get_keycode_by_name(s); } return i; } public static boolean hasModifier(int mask, int modifier) { return (mask & modifier) > 0; } public static int[] getRimeEvent(int code, int mask) { int i = getRimeCode(code); int m = 0; if (hasModifier(mask, KeyEvent.META_SHIFT_ON)) m |= Rime.META_SHIFT_ON; if (hasModifier(mask, KeyEvent.META_CTRL_ON)) m |= Rime.META_CTRL_ON; if (hasModifier(mask, KeyEvent.META_ALT_ON)) m |= Rime.META_ALT_ON; if (mask == Rime.META_RELEASE_ON) m |= Rime.META_RELEASE_ON; return new int[] {i, m}; } private static Map masks = new HashMap() { { put("Shift", KeyEvent.META_SHIFT_ON); put("Control", KeyEvent.META_CTRL_ON); put("Alt", KeyEvent.META_ALT_ON); } }; private static Map symbolAliases = new HashMap() { { put("#", KeyEvent.KEYCODE_POUND); put("'", KeyEvent.KEYCODE_APOSTROPHE); put("(", KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN); put(")", KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN); put("*", KeyEvent.KEYCODE_STAR); put("+", KeyEvent.KEYCODE_PLUS); put(",", KeyEvent.KEYCODE_COMMA); put("-", KeyEvent.KEYCODE_MINUS); put(".", KeyEvent.KEYCODE_PERIOD); put("/", KeyEvent.KEYCODE_SLASH); put(";", KeyEvent.KEYCODE_SEMICOLON); put("=", KeyEvent.KEYCODE_EQUALS); put("@", KeyEvent.KEYCODE_AT); put("\\", KeyEvent.KEYCODE_BACKSLASH); put("[", KeyEvent.KEYCODE_LEFT_BRACKET); put("`", KeyEvent.KEYCODE_GRAVE); put("]", KeyEvent.KEYCODE_RIGHT_BRACKET); } }; }