FileDocCategorySizeDatePackage
BasicInputMode.javaAPI DocphoneME MR2 API (J2ME)24615Wed May 02 18:00:20 BST 2007com.sun.midp.chameleon.input

BasicInputMode

public abstract class BasicInputMode extends Object implements InputMode, Runnable
An InputMode instance which processes the numeric 0-9 keys as their literal numeric values.

Fields Summary
protected int
constraints
Text input constraints for this input mode. The semantics of the constraints value are defined in the TextField API.
protected int
modifiers
Text input modifiers for this input mode. The semantics of the modifiers value are defined in the TextField API.
protected static final int
KEY_COMMIT_TIMEOUT
A timeout, in ms, after which a pending key will be committed to the text component. By default this is set to 250ms.
protected int
lastKey
A holder for the keyCode which was last processed
protected InputModeMediator
mediator
The InputModeMediator for the current input session
protected boolean
commitChar
A boolean flag used by the timer in this input mode to determine if a character should be committed to the text component or not
protected int
clickCount
The number of times the user pressed the last key code. This value acts as an index into the array of possible characters of any one key. For example, a lastKey == to Canvas.KEY_NUM2 and a clickCount of 3 would yield a 'c'.
protected int
pendingChar
The single, pending character based on the key presses thus far
protected boolean
hasMoreMatches
Flag indicating if more matches exist
protected boolean
sessionIsLive
A boolean flag used by the timer in this input mode to know when to completely shut down the timer thread. That is, when the input session is no longer active, the timer thread in this input mode will quit entirely, freeing up system resources.
static char[]
keyMap
the possible key maps for this input mode
Constructors Summary
Methods Summary
public voidbeginInput(InputModeMediator mediator, java.lang.String inputSubset, int constraints)
This method will be called before any input keys are passed to this InputMode to allow the InputMode to perform any needed initialization. A reference to the InputModeMediator which is currently managing the relationship between this InputMode and the input session is passed in. This reference can be used by this InputMode to commit text input as well as end the input session with this InputMode. The reference is only valid until this InputMode's endInput() method is called.

param
constraints text input constraints. The semantics of the constraints value are defined in the TextField API.
param
mediator the InputModeMediator which is negotiating the relationship between this InputMode and the input session
param
inputSubset current input subset


                                                                                                                                     
       
                               
        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[basic.beginInput] >>");
        }
        validateState(false);
        this.mediator = mediator;
        this.constraints = constraints & TextField.CONSTRAINT_MASK;
        this.modifiers = constraints & ~TextField.CONSTRAINT_MASK;
        startTimer();
        setInputSubset(inputSubset);
        setKeyMap(constraints, false);
        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[basic.beginInput] <<");
        }
    
protected booleancommitPendingChar()
This method is used to immediately commit the pending character because a new character is now pending.

return
true if char has been committed otherwise false

        boolean committed = false;
        int c = getPendingCharInternal();
        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[commitPendingChar] getPendingChar=" + c);
        }
        if (c != KEYCODE_NONE) {
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "[commitPendingChar] commiting " + String.valueOf((char) c));
            }
            committed = true;
            mediator.commit(String.valueOf((char) c));
        }

        lastKey = -1;
        clickCount = 0;
        pendingChar = KEYCODE_NONE;
        return committed;
    
protected voidcompleteInputMode(boolean commit)
This method is used to immediately commit the given string and then call the TextInputMediator's inputModeCompleted() method

param
commit true if the char is accepted, false if the char is rejected

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[Basic.completeInputMode] commit = " + commit);
        }
        if (commit) {
            commitPendingChar();
        }

        clickCount = 0;
        lastKey = -1;

        stopTimer();
        startTimer();
    
public voidendInput()
Mark the end of this InputMode's processing. The only possible call to this InputMode after a call to endInput() is a call to beginInput() to begin a new input session.

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[basic.endInput]");
        }
        validateState(true);
        this.mediator = null;
        clickCount = 0;
        lastKey = -1;

        stopTimer();
    
protected abstract char[]getCharOptions(int lastKey)
Gets the possible matches for the key code

param
lastKey the key code
return
returns the set of options. Return null if matches are not found.

public abstract java.lang.StringgetCommandName()
Returns the command name which will represent this InputMode in the input menu

return
the locale-appropriate name to represent this InputMode to the user

public javax.microedition.lcdui.DisplayablegetDisplayable()
By default the regular input method has no specific displayable representation so it returns null.

return
null by default

        return null;
    
public abstract boolean[][]getIsConstraintsMap()
Returns the map specifying this input mode is proper one for the particular pair of input subset and constraint. The form of the map is |ANY|EMAILADDR|NUMERIC|PHONENUMBER|URL|DECIMAL| --------------------------------------------------------------------- IS_FULLWIDTH_DIGITS |t|f| t|f | t|f | t|f |t|f| t|f | IS_FULLWIDTH_LATIN |t|f| t|f | t|f | t|f |t|f| t|f | IS_HALFWIDTH_KATAKANA |t|f| t|f | t|f | t|f |t|f| t|f | IS_HANJA |t|f| t|f | t|f | t|f |t|f| t|f | IS_KANJI |t|f| t|f | t|f | t|f |t|f| t|f | IS_LATIN |t|f| t|f | t|f | t|f |t|f| t|f | IS_LATIN_DIGITS |t|f| t|f | t|f | t|f |t|f| t|f | IS_SIMPLIFIED_HANZI |t|f| t|f | t|f | t|f |t|f| t|f | IS_TRADITIONAL_HANZI |t|f| t|f | t|f | t|f |t|f| t|f | MIDP_UPPERCASE_LATIN |t|f| t|f | t|f | t|f |t|f| t|f | MIDP_LOWERCASE_LATIN |t|f| t|f | t|f | t|f |t|f| t|f | NULL |t|f| t|f | t|f | t|f |t|f| t|f |

return
input subset x constraint map

protected char[][]getMapByLine(java.lang.String line)
Converts the string to key map. The rows are separated each from other by '$'. The characters inside of one row follow each to other without any separator.

param
line string combines all keys
return
map of the keys in char[][] format

        char[] chars = line.toCharArray();
        int rows = 1;
        for (int i = line.length() - 1; i >= 0; i--) {
            if (chars[i] == '$") rows++;
        }
        
        char[][] map = new char[rows][];
        for (int start = 0, j = 0; start < line.length(); j++) {           
            int end = line.indexOf('$", start);
            
            // if '$' is not found that means the end of string is reached
            if (end == -1) end = line.length();
            map[j] = line.substring(start, end).toCharArray();
            start = end + 1;
        }
        return map;
    
public java.lang.String[]getMatchList()
Gets the possible string matches

return
returns the set of options.

        //   String[] value = null;
        //   int ch = getPendingCharInternal();
        
        //   if (ch != KEYCODE_NONE) {
        //      value = new String[1];
        //      value[0] = String.valueOf((char)ch);
        //   } else {
        //      value = new String[0];
        //   }
        //   return value;
        //         
        return new String[0];
    
public abstract java.lang.StringgetName()
Returns the display name which will represent this InputMode to the user, such as in a selection list or the softbutton bar.

return
the locale-appropriate name to represent this InputMode to the user

protected intgetNextChar()
Get next possble char

return
next key code

        pendingChar = KEYCODE_NONE;
        return getPendingCharInternal();
    
public java.lang.StringgetNextMatch()
Return the next possible match for the key input processed thus far by this InputMode. A call to this method should be preceeded by a check of hasMoreMatches(). If the InputMode has more available matches for the given input, this method will return them one by one.

return
a String representing the next available match to the key input thus far, or 'null' if no pending input is available

        String value = null;

        int ch = getNextChar();
        if (ch != KEYCODE_NONE) {
            value = String.valueOf((char)ch);
        }
        hasMoreMatches = false;

        return value;
    
public chargetPendingChar()
return the pending char used to bypass the asynchronous commit mechanism e.g. to immediately commit a char before moving the cursor

return
return the pending char

        int code = getPendingCharInternal();
        char c = code == KEYCODE_NONE ? 0 : (char) code;
        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[getPendingChar] returning " + c);
        }
        return c;
    
public intgetPendingCharInternal()
return the pending char for internal use

return
return the pending char

        if (pendingChar == KEYCODE_NONE) {
            char[] chars = null;
            char c;
            // log("[basic.getPendingCharInternal] lastKey=" + lastKey);
            if (lastKey == -1 || clickCount <= 0) {
                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                    Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                        "[getPendingCharInternal] returning KEYCODE_NONE");
                }
            } else {
                chars = getCharOptions(lastKey);
                if (chars == null) {
                    if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                        Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                            "[getPendingCharInternal] returning KEYCODE_NONE");
                    }
                } else {
                    if (clickCount > chars.length) {
                        clickCount = 1;
                    }

                    if (chars.length > 0) {
                        pendingChar = chars[clickCount - 1];
                    }

                    hasMoreMatches = true;
                    if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                        Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                            "[getPendingCharInternal] returning " + pendingChar);
                    }
                }
            }
        }
        return pendingChar;
    
public booleanhasDisplayable()
Returns true if input mode is using its own displayable, false ifinput mode does not require the speial displayable for its representation. By default - false

return
true if input mode is using its own displayable, otherwise false

        return false;
    
public booleanhasMoreMatches()
True, if after processing a key, there is more than one possible match to the input. If this method returns true, the getNextMatch() method can be called to return the value.

return
true if after processing a key, there is more than the one possible match to the given input

        return hasMoreMatches;
    
private booleanhasOneCase(int keyCode)
Check if only one char option exists for the key code

param
keyCode key code
return
true if only one char option exists otherwise false.

        boolean ret = false;
        if (keyCode != -1) {
            char[] options = getCharOptions(keyCode);
            if (options != null)
                ret = options.length <= 1;
        }
        return ret;
    
private booleanisValidKey(int keyCode, boolean longPress)
Check if the key has to be handled this input mode

param
keyCode key
param
longPress true if long key press happens otherwise false.
return
true if this key can be handled by this input mode, otherwise false

        if ((keyCode != Canvas.KEY_STAR && 
             keyCode != Canvas.KEY_POUND && 
             (mediator != null && !mediator.isClearKey(keyCode)) && 
             keyCode != Canvas.LEFT && 
             keyCode != Canvas.RIGHT && 
             keyCode != Canvas.UP && 
             keyCode != Canvas.DOWN && 
             (keyCode < Canvas.KEY_NUM0 || 
              keyCode > Canvas.KEY_NUM9)) || 
            (longPress && 
             lastKey != keyCode && 
             lastKey != -1)) {
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "INVALID KEY");
            }
            return false;
        }
        return true;
    
protected voidnextCapsMode()
Set the next capital mode for this input method

public intprocessKey(int keyCode, boolean longPress)
Process the given key code as input. This method will return true if the key was processed successfully, false otherwise.

param
keyCode the keycode of the key which was input
param
longPress return true if it's long key press otherwise false
return
the key code if the key has been committed for the input, or KEYCODE_NONE if the key has not been habdled by the input mode, or KEYCODE_INVISIBLE if the key has been handled by the input mode but this key has not been displayed

        int ret = KEYCODE_NONE;
        if (isValidKey(keyCode, longPress)) {
            
            // We immediately disable the commit of any pending character
            // input in case the timer expires
            commitChar = false;
            validateState(true);
            
            if (mediator != null && mediator.isClearKey(keyCode) || 
                keyCode == Canvas.LEFT || 
                keyCode == Canvas.RIGHT || 
                keyCode == Canvas.UP ||
                keyCode == Canvas.DOWN) {
                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                    Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                        "[processKey] got clear or arrow. lastKey=" + lastKey);
                }
                completeInputMode(true);
            } else {

                if (setKeyMap(constraints, longPress)) {
                    pendingChar = KEYCODE_NONE;
                    clickCount = 0;
                }
                
                // at first check if previous key has to be committed

            
                // If we have a pending keycode and this new keycode is
                // different, we will commit the previous key and continue
                if (lastKey != -1 && lastKey != keyCode) {
                    commitPendingChar();
                }
            
                clickCount++;

                // If the pending key code has just one match or long key
                // press happens commit the current key 

                if (longPress) {
                    if (lastKey != -1) {
                        lastKey = keyCode;                  
                        commitPendingChar();
                    } 
                } else if (hasOneCase(keyCode)) {
                    lastKey = keyCode;                  
                    commitPendingChar();
                } else {
                    lastKey = keyCode;                  
                }
                
                // Lastly, we'll interrupt the timer to reset it or start it if
                // timer is still not working.
                resetTimer();        

                if (getNextChar() == KEYCODE_NONE) {
                    lastKey = -1;
                }
                
                ret = getPendingCharInternal();
            }            
        } else {
            ret = InputMode.KEYCODE_INVISIBLE;
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "[processKey] returning KEYCODE_INVISIBLE");
            }
        }
        return ret;
    
private voidresetTimer()
Reset timmer which will attempt to commit a pending character after a certain timeout

        sessionIsLive = true;
        // Lastly, we'll interrupt the timer to end it.
        synchronized (this) {
            try {
                notify();
            } catch (IllegalMonitorStateException ignore) { }
        }
    
public voidrun()
Implementation of a timer routine which will attempt to commit a pending character after a certain timeout (depending on the state of the commitChar boolean).

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[run] sessionIsLive=" + sessionIsLive + " commitChar=" + commitChar);
        }
        // We initially block until the first key press is processed
        if (!sessionIsLive) {
            try {
                synchronized (this) {
                    wait();
                }
            } catch (Throwable t) {
            } // ignore interruptions
        }

        while (sessionIsLive) {
            try {
                synchronized (this) {
                    // Just before we start the timeout we set the
                    // commit flag to true. If it doesn't get reset
                    // to false by the processKey method, we will
                    // commit the pending key when we wake up
                    commitChar = true;
                    wait(KEY_COMMIT_TIMEOUT);
                }
            } catch (Throwable t) {
            } // ignore any exceptions here

            if (sessionIsLive && commitChar) {
                completeInputMode(true);
            }
        }
    
protected voidsetInputSubset(java.lang.String inputSubset)
Notify about current input subset

param
inputSubset current input subset

    
protected abstract booleansetKeyMap(int constraints, boolean longPress)
Set the corresponding key map.

param
constraints text input constraints. The semantics of the constraints value are defined in the TextField API.
param
longPress return true if it's long key press otherwise false
return
true if the key map has been changed otherwise false

private voidstartTimer()
Start timmer which will attempt to commit a pending character after a certain timeout

        (new Thread(this)).start();
    
private voidstopTimer()
Stop timmer which will attempt to commit a pending character after a certain timeout

        sessionIsLive = false;
        // Lastly, we'll interrupt the timer to end it.
        synchronized (this) {
            try {
                notify();
            } catch (IllegalMonitorStateException ignore) { }
        }
    
public abstract booleansupportsConstraints(int constraints)
This method is called to determine if this InputMode supports the given text input constraints. The semantics of the constraints value are defined in the javax.microedition.lcdui.TextField API. If this InputMode returns false, this InputMode must not be used to process key input for the selected text component.

param
constraints text input constraints. The semantics of the constraints value are defined in the TextField API.
return
true if this InputMode supports the given text component constraints, as defined in the MIDP TextField API

protected voidvalidateState(boolean activeOperation)
This method will validate the state of this InputMode. If this is a check for an "active" operation, the TextInputMediator must be non-null or else this method will throw an IllegalStateException. If this is a check for an "inactive" operation, then the TextInputMediator should be null.

param
activeOperation true if any operation is active otherwise false.

        if (activeOperation && this.mediator == null) {
            throw new IllegalStateException(
            "Illegal operation on an input session already in progress");
        } else if (!activeOperation && this.mediator != null) {
            throw new IllegalStateException(
            "Illegal operation on an input session which is not in progress");
        }