VirtualKeyboard.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:19k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit.impl.midp;
  26. import com.sun.lwuit.*;
  27. import com.sun.lwuit.animations.CommonTransitions;
  28. import com.sun.lwuit.events.ActionEvent;
  29. import com.sun.lwuit.events.ActionListener;
  30. import com.sun.lwuit.geom.Rectangle;
  31. import com.sun.lwuit.layouts.BorderLayout;
  32. import com.sun.lwuit.layouts.BoxLayout;
  33. import java.util.Hashtable;
  34. import java.util.Vector;
  35. /**
  36.  * This class is a Light Weight Virtual Keyboard
  37.  * 
  38.  * @author Chen Fishbein
  39.  */
  40. public class VirtualKeyboard extends Dialog {
  41.     /**
  42.      * This keymap represents qwerty keyboard
  43.      */
  44.     public static final String[][] DEFAULT_QWERTY = new String[][]{
  45.         {"q", "w", "e", "r", "t", "y", "u", "i", "o", "p"},
  46.         {"a", "s", "d", "f", "g", "h", "j", "k", "l"},
  47.         {"$Shift$", "z", "x", "c", "v", "b", "n", "m", "$Delete$"},
  48.         {"$Mode$", "$T9$", "$Space$", "$OK$"}
  49.     };
  50.     /**
  51.      * This keymap represents numbers keyboard
  52.      */
  53.     public static final String[][] DEFAULT_NUMBERS = new String[][]{
  54.         {"1", "2", "3",},
  55.         {"4", "5", "6",},
  56.         {"7", "8", "9",},
  57.         {"*", "0", "#",},
  58.         {"$Mode$", "$Space$", "$Delete$", "$OK$"}
  59.     };
  60.     /**
  61.      * This keymap represents numbers and symbols keyboard
  62.      */
  63.     public static final String[][] DEFAULT_NUMBERS_SYMBOLS = new String[][]{
  64.         {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"},
  65.         {"-", "/", ":", ";", "(", ")", "$", "&", "@"},
  66.         {".", ",", "?", "!", "'", """, "$Delete$"},
  67.         {"$Mode$", "$Space$", "$OK$"}
  68.     };
  69.     /**
  70.      * This keymap represents symbols keyboard
  71.      */
  72.     public static final String[][] DEFAULT_SYMBOLS = new String[][]{
  73.         {"[", "]", "{", "}", "#", "%", "^", "*", "+", "="},
  74.         {"_", "\", "|", "~", "<", ">", "u00A3", "u00A5"},
  75.         {":-0", ";-)", ":-)", ":-(", ":P", ":D", "$Delete$"},
  76.         {"$Mode$", "$Space$", "$OK$"}
  77.     };
  78.     /**
  79.      * The String that represent the qwerty mode.
  80.      */
  81.     public static final String QWERTY_MODE = "ABC";
  82.     /**
  83.      * The String that represent the numbers mode.
  84.      */
  85.     public static final String NUMBERS_MODE = "123";
  86.     /**
  87.      * The String that represent the numbers sybols mode.
  88.      */
  89.     public static final String NUMBERS_SYMBOLS_MODE = ".,123";
  90.     /**
  91.      * The String that represent the symbols mode.
  92.      */
  93.     public static final String SYMBOLS_MODE = ".,?";
  94.     private String currentMode = QWERTY_MODE;
  95.     private Vector modesKeys = new Vector();
  96.     private Hashtable modesMap = new Hashtable();
  97.     private TextField inputField;
  98.     private Container buttons = new Container(new BoxLayout(BoxLayout.Y_AXIS));
  99.     private TextPainter txtPainter = new TextPainter();
  100.     private boolean upperCase = false;
  101.     private Button currentButton;
  102.     private static final int INSERT_CHAR = 1;
  103.     private static final int DELETE_CHAR = 2;
  104.     private static final int CHANGE_MODE = 3;
  105.     private static final int SHIFT = 4;
  106.     private static final int OK = 5;
  107.     private static final int SPACE = 6;
  108.     private static final int T9 = 7;
  109.     private Hashtable specialButtons = new Hashtable();
  110.     private TextField field;
  111.     private boolean finishedT9Edit = false;
  112.     /**
  113.      * Creates a new instance of VirtualKeyboard 
  114.      * 
  115.      * @param field The TextField to edit.
  116.      */
  117.     public VirtualKeyboard() {
  118.         setLayout(new BorderLayout());
  119.         getContentPane().setUIID("VKB");
  120.         setAutoDispose(false);
  121.         setDisposeWhenPointerOutOfBounds(true);
  122.         setTransitionInAnimator(
  123.                 CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, true, 500));
  124.         setTransitionOutAnimator(
  125.                 CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, false, 500));
  126.         setGlassPane(txtPainter);
  127.     }
  128.     public void setTextField(TextField field) {
  129.         this.field = field;
  130.         removeAll();
  131.         field.setUseSoftkeys(false);
  132.         inputField = new TextField() {
  133.             public boolean hasFocus() {
  134.                 return true;
  135.             }
  136.             public String getUIID() {
  137.                 return "VKBTextInput";
  138.             }
  139.         };
  140.         inputField.setText(field.getText());
  141.         inputField.setConstraint(field.getConstraint());
  142.         inputField.setInputModeOrder(new String[]{"ABC"});
  143.         initModes();
  144.         initSpecialButtons();
  145.         addComponent(BorderLayout.NORTH, inputField);
  146.         buttons.getStyle().setPadding(0, 0, 0, 0);
  147.         addComponent(BorderLayout.CENTER, buttons);
  148.         initInputButtons(upperCase);
  149.         inputField.setUseSoftkeys(false);
  150.         applyRTL(false);
  151.     }
  152.     /**
  153.      * @inheritDoc
  154.      */
  155.     public void show() {
  156.         super.showPacked(BorderLayout.SOUTH, true);
  157.     }
  158.     /**
  159.      * @inheritDoc
  160.      */
  161.     protected void sizeChanged(int w, int h) {
  162.         if (!finishedT9Edit) {
  163.             setTransitionOutAnimator(CommonTransitions.createEmpty());
  164.             dispose();
  165.         } else {
  166.             finishedT9Edit = false;
  167.         }
  168.         super.sizeChanged(w, h);
  169.     }
  170.     /**
  171.      * init all virtual keyboard modes, such as QWERTY_MODE, NUMBERS_SYMBOLS_MODE...
  172.      * to add an addtitional mode a developer needs to override this method and
  173.      * add a mode by calling addInputMode method
  174.      */
  175.     protected void initModes() {
  176.         modesKeys.removeAllElements();
  177.         modesMap.clear();
  178.         if (inputField.getConstraint() == TextField.NUMERIC) {
  179.             setCurrentMode(NUMBERS_SYMBOLS_MODE);
  180.             addInputMode(NUMBERS_SYMBOLS_MODE, DEFAULT_NUMBERS_SYMBOLS);
  181.             addInputMode(NUMBERS_MODE, DEFAULT_NUMBERS);
  182.         } else {
  183.             setCurrentMode(QWERTY_MODE);
  184.             addInputMode(QWERTY_MODE, DEFAULT_QWERTY);
  185.             addInputMode(NUMBERS_SYMBOLS_MODE, DEFAULT_NUMBERS_SYMBOLS);
  186.             addInputMode(SYMBOLS_MODE, DEFAULT_SYMBOLS);
  187.             addInputMode(NUMBERS_MODE, DEFAULT_NUMBERS);
  188.         }
  189.     }
  190.     /**
  191.      * Sets the current virtual keyboard mode.
  192.      * 
  193.      * @param mode the String that represents the mode(QWERTY_MODE, 
  194.      * SYMBOLS_MODE, ...)
  195.      */
  196.     protected void setCurrentMode(String mode) {
  197.         this.currentMode = mode;
  198.     }
  199.     /**
  200.      * Gets the current mode.
  201.      * 
  202.      * @return the String that represents the current mode(QWERTY_MODE, 
  203.      * SYMBOLS_MODE, ...)
  204.      */
  205.     protected String getCurrentMode() {
  206.         return currentMode;
  207.     }
  208.     private void initInputButtons(boolean upperCase) {
  209.         buttons.removeAll();
  210.         int largestLine = 0;
  211.         String[][] currentKeyboardChars = (String[][]) modesMap.get(currentMode);
  212.         for (int i = 1; i < currentKeyboardChars.length; i++) {
  213.             if (currentKeyboardChars[i].length > currentKeyboardChars[largestLine].length) {
  214.                 largestLine = i;
  215.             }
  216.         }
  217.         int length = currentKeyboardChars[largestLine].length;
  218.         Button dummy = createButton(new Command("dummy"), 0);
  219.         int buttonMargins = dummy.getUnselectedStyle().getMargin(dummy.isRTL(), LEFT) +
  220.                 dummy.getUnselectedStyle().getMargin(dummy.isRTL(), RIGHT);
  221.         Container row = null;
  222.         int rowW = (Display.getInstance().getDisplayWidth() -
  223.                 getContentPane().getUnselectedStyle().getPadding(false, LEFT) -
  224.                 getContentPane().getUnselectedStyle().getPadding(false, RIGHT) -
  225.                 getContentPane().getUnselectedStyle().getMargin(false, LEFT) -
  226.                 getContentPane().getUnselectedStyle().getMargin(false, RIGHT));
  227.         int availableSpace = rowW - length * buttonMargins;
  228.         int buttonSpace = (availableSpace) / length;
  229.         for (int i = 0; i < currentKeyboardChars.length; i++) {
  230.             int rowWidth = rowW;
  231.             row = new Container(new BoxLayout(BoxLayout.X_AXIS));
  232.             row.getUnselectedStyle().setMargin(0, 0, 0, 0);
  233.             Vector specialsButtons = new Vector();
  234.             for (int j = 0; j < currentKeyboardChars[i].length; j++) {
  235.                 String txt = currentKeyboardChars[i][j];
  236.                 Button b = null;
  237.                 if (txt.startsWith("$") && txt.endsWith("$") && txt.length() > 1) {
  238.                     //add a special button
  239.                     Button cmd = (Button) specialButtons.get(txt.substring(1, txt.length() - 1));
  240.                     int prefW = 0;
  241.                     int space = ((Integer) cmd.getClientProperty("space")).intValue();
  242.                     if (space != -1) {
  243.                         prefW = availableSpace * space / 100;
  244.                     }
  245.                     b = createButton(cmd.getCommand(), prefW, "VKBSpecialButton");
  246.                     if (prefW != 0) {
  247.                         rowWidth -= (b.getPreferredW() + buttonMargins);
  248.                     } else {
  249.                         //if we can't determind the size at this stage, wait until
  250.                         //the loops ends and give the remains size to the special
  251.                         //button
  252.                         specialsButtons.addElement(b);
  253.                     }
  254.                 } else {
  255.                     if (upperCase) {
  256.                         txt = txt.toUpperCase();
  257.                     }
  258.                     b = createInputButton(txt, buttonSpace);
  259.                     rowWidth -= (b.getPreferredW() + buttonMargins);
  260.                 }
  261.                 if (currentButton != null) {
  262.                     if (currentButton.getCommand().getId() == b.getCommand().getId()) {
  263.                         currentButton = b;
  264.                     }
  265.                     if (currentButton.getText().equals(b.getText())) {
  266.                         currentButton = b;
  267.                     }
  268.                 }
  269.                 row.addComponent(b);
  270.             }
  271.             int emptySpace = Math.max(rowWidth, 0);
  272.             //if we have special buttons on the keyboard give them the size or 
  273.             //else give the remain size to the row margins
  274.             if (specialsButtons.size() > 0) {
  275.                 int prefW = emptySpace / specialsButtons.size();
  276.                 for (int j = 0; j < specialsButtons.size(); j++) {
  277.                     Button special = (Button) specialsButtons.elementAt(j);
  278.                     special.setPreferredW(prefW);
  279.                 }
  280.             } else {
  281.                 row.getUnselectedStyle().setPadding(Component.LEFT, 0);
  282.                 row.getUnselectedStyle().setPadding(Component.RIGHT, 0);
  283.                 row.getUnselectedStyle().setMargin(Component.LEFT, emptySpace / 2);
  284.                 row.getUnselectedStyle().setMargin(Component.RIGHT, emptySpace / 2);
  285.             }
  286.             buttons.addComponent(row);
  287.         }
  288.         applyRTL(false);
  289.     }
  290.     private Button createInputButton(String text, int prefSize) {
  291.         Button b = createButton(new Command(text, INSERT_CHAR), prefSize);
  292.         b.putClientProperty("glasspane", "true");
  293.         return b;
  294.     }
  295.     private Button createButton(Command cmd, int prefSize) {
  296.         return createButton(cmd, prefSize, "VKBButton");
  297.     }
  298.     private Button createButton(Command cmd, int prefSize, String uiid) {
  299.         final Button b = new Button(cmd);
  300.         b.setUIID(uiid);
  301.         b.setEndsWith3Points(false);
  302.         b.setAlignment(Component.CENTER);
  303.         prefSize = Math.max(prefSize, b.getPreferredW());
  304.         b.setPreferredW(prefSize);
  305.         b.addActionListener(new ActionListener() {
  306.             public void actionPerformed(ActionEvent evt) {
  307.                 currentButton = b;
  308.             }
  309.         });
  310.         return b;
  311.     }
  312.     /**
  313.      * Add an input mode to the virtual keyboard 
  314.      * 
  315.      * @param mode a string that represents the identifier of the mode
  316.      * @param inputChars 2 dimentional String array that contains buttons String
  317.      * and special buttons (a special button is identified with $...$ marks 
  318.      * e.g: "$Space$")
  319.      */
  320.     public void addInputMode(String mode, String[][] inputChars) {
  321.         modesKeys.addElement(mode);
  322.         modesMap.put(mode, inputChars);
  323.     }
  324.     /**
  325.      * This method adds a special button to the virtual keyboard
  326.      * 
  327.      * @param key the string identifier from within the relevant input mode
  328.      * @param cmd the Command to invoke when this button is invoked.
  329.      */
  330.     public void addSpecialButton(String key, Command cmd) {
  331.         addSpecialButton(key, cmd, -1);
  332.     }
  333.     /**
  334.      * This method adds a special button to the virtual keyboard
  335.      * 
  336.      * @param key the string identifier from within the relevant input mode
  337.      * @param cmd the Command to invoke when this button is invoked.
  338.      * @param space how much space in percentage from the overall row 
  339.      * the special button should occupy
  340.      */
  341.     public void addSpecialButton(String key, Command cmd, int space) {
  342.         Button b = new Button(cmd);
  343.         b.putClientProperty("space", new Integer(space));
  344.         specialButtons.put(key, b);
  345.     }
  346.     private String getNextMode(String current) {
  347.         int index = modesKeys.indexOf(current);
  348.         if (index == modesKeys.size() - 1) {
  349.             return (String) modesKeys.elementAt(0);
  350.         }
  351.         return (String) modesKeys.elementAt(index + 1);
  352.     }
  353.     /**
  354.      * @inheritDoc
  355.      */
  356.     public void pointerPressed(int x, int y) {
  357.         super.pointerPressed(x, y);
  358.         //txtPainter.clear();
  359.         Component cmp = getComponentAt(x, y);
  360.         if (cmp != null && cmp instanceof Button && cmp.getClientProperty("glasspane") != null) {
  361.             txtPainter.showButtonOnGlasspane((Button) cmp);
  362.         }
  363.     }
  364.     /**
  365.      * @inheritDoc
  366.      */
  367.     public void pointerDragged(int x, int y) {
  368.         super.pointerDragged(x, y);
  369.         //txtPainter.clear();
  370.         Component cmp = getComponentAt(x, y);
  371.         if (cmp != null && cmp instanceof Button && cmp.getClientProperty("glasspane") != null) {
  372.             txtPainter.showButtonOnGlasspane((Button) cmp);
  373.         }
  374.     }
  375.     /**
  376.      * @inheritDoc
  377.      */
  378.     public void pointerReleased(int x, int y) {
  379.         txtPainter.clear();
  380.         super.pointerReleased(x, y);
  381.     }
  382.     /**
  383.      * This method initialize all the virtual keyboard special buttons.
  384.      */
  385.     protected void initSpecialButtons() {
  386.         specialButtons.clear();
  387.         addSpecialButton("Shift", new Command("SH", SHIFT), 15);
  388.         addSpecialButton("Delete", new Command("Del", DELETE_CHAR), 15);
  389.         addSpecialButton("T9", new Command("T9", T9), 15);
  390.         addSpecialButton("Mode", new Command(getNextMode(currentMode), CHANGE_MODE));
  391.         addSpecialButton("Space", new Command("Space", SPACE), 50);
  392.         addSpecialButton("OK", new Command("Ok", OK));
  393.     }
  394.     class TextPainter implements Painter {
  395.         private Label label = new Label();
  396.         private boolean paint = true;
  397.         public TextPainter() {
  398.             label = new Label();
  399.             label.setUIID("VKBtooltip");
  400.         }
  401.         public void showButtonOnGlasspane(Button button) {
  402.             if(label.getText().equals(button.getText())){
  403.                 return;
  404.             }
  405.             paint = true;
  406.             repaint(label.getAbsoluteX()-2,
  407.                     label.getAbsoluteY()-2,
  408.                     label.getWidth()+4,
  409.                     label.getHeight()+4);
  410.             label.setText(button.getText());
  411.             label.setSize(label.getPreferredSize());
  412.             label.setX(button.getAbsoluteX() + (button.getWidth() - label.getWidth()) / 2);
  413.             label.setY(button.getAbsoluteY() - label.getPreferredH() * 4 / 3);
  414.             repaint(label.getAbsoluteX()-2,
  415.                     label.getAbsoluteY()-2,
  416.                     label.getPreferredW()+4,
  417.                     label.getPreferredH()+4);
  418.         }
  419.         public void paint(Graphics g, Rectangle rect) {
  420.             if (paint) {
  421.                 label.paintComponent(g);
  422.             }
  423.         }
  424.         private void clear() {
  425.             paint = false;
  426.             repaint();
  427.         }
  428.     }
  429.     /**
  430.      * @inheritDoc
  431.      */
  432.     protected void actionCommand(Command cmd) {
  433.         super.actionCommand(cmd);
  434.         switch (cmd.getId()) {
  435.             case OK:
  436.                 field.setText(inputField.getText());
  437.                 field.setCursorPosition(field.getText().length());
  438.                 dispose();
  439.                 break;
  440.             case INSERT_CHAR:
  441.                 Button btn = currentButton;
  442.                 String text = btn.getText();
  443.                 if (inputField.getText().length() == 0) {
  444.                     inputField.setText(text);
  445.                     inputField.setCursorPosition(text.length());
  446.                 } else {
  447.                     inputField.insertChars(text);
  448.                 }
  449.                 break;
  450.             case SPACE:
  451.                 if (inputField.getText().length() == 0) {
  452.                     inputField.setText(" ");
  453.                 } else {
  454.                     inputField.insertChars(" ");
  455.                 }
  456.                 break;
  457.             case DELETE_CHAR:
  458.                 inputField.deleteChar();
  459.                 break;
  460.             case CHANGE_MODE:
  461.                 currentMode = getNextMode(currentMode);
  462.                 Display.getInstance().callSerially(new Runnable() {
  463.                     public void run() {
  464.                         initInputButtons(upperCase);
  465.                         currentButton.setText(getNextMode(currentMode));
  466.                         setTransitionOutAnimator(CommonTransitions.createEmpty());
  467.                         setTransitionInAnimator(CommonTransitions.createEmpty());
  468.                         getTitleComponent().getStyle().setMargin(TOP, 0);
  469.                         dispose();
  470.                         show();
  471.                         setTransitionOutAnimator(
  472.                                 CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, false, 500));
  473.                     }
  474.                 });
  475.                 return;
  476.             case SHIFT:
  477.                 if (currentMode.equals(QWERTY_MODE)) {
  478.                     upperCase = !upperCase;
  479.                     Display.getInstance().callSerially(new Runnable() {
  480.                         public void run() {
  481.                             initInputButtons(upperCase);
  482.                             revalidate();
  483.                         }
  484.                     });
  485.                 }
  486.                 return;
  487.             case T9:
  488.                 Display.getInstance().editString(inputField, inputField.getMaxSize(), inputField.getConstraint(), inputField.getText());
  489.                 finishedT9Edit = true;
  490.         }
  491.     }
  492.     /**
  493.      * This method returns the Virtual Keyboard TextField.
  494.      * 
  495.      * @return the the Virtual Keyboard TextField.
  496.      */
  497.     protected TextField getInputField() {
  498.         return inputField;
  499.     }
  500. }