1   /*
2    * LocaleHandler.java
3    *
4    * Copyright (c) 2000-2001, The University of Sheffield.
5    *
6    * This file is part of GATE (see http://gate.ac.uk/), and is free
7    * software, licenced under the GNU Library General Public License,
8    * Version 2, June1991.
9    *
10   * A copy of this licence is included in the distribution in the file
11   * licence.html, and is also available at http://gate.ac.uk/gate/licence.html.
12   *
13   * Valentin Tablan, October 2000
14   *
15   * $Id: LocaleHandler.java,v 1.3 2001/04/17 18:09:11 oana Exp $
16   */
17  package guk.im;
18  
19  import java.io.*;
20  import java.util.*;
21  import java.awt.event.*;
22  
23  import guk.*;
24  
25  /**
26   * A Handler for a locale.
27   * A locale handler is actually a finite state machine (FSM) that maps
28   * input events (presseed keys) to other input events(typed characters).
29   *
30   */
31  public class LocaleHandler {
32    /**
33     * Creates a locale handler for a given locale using the definitions from
34     * the file provided.
35     *
36     * @exception IOException
37     * @param locale
38     * @param fileName
39     */
40    public LocaleHandler(Locale locale, String fileName) throws IOException {
41    //System.out.println("Loading " + fileName);
42      this.locale = locale;
43      InputStream is = GateIM.class.getResourceAsStream(GateIM.getIMBase()
44                         + fileName);
45      if (is==null) throw new IllegalArgumentException
46       ("Failed to retrieve resource '"+fileName+"'. Please reset classpath.");
47      BufferedReader br = new BufferedReader(new InputStreamReader(is));
48      String line = br.readLine();
49      initialState = new State();
50  
51      String remains;
52      String keyStr;
53      String keycapStr;
54      String keymapName;
55      String number;
56      String output;
57      keycap = new HashMap();
58      int start, end;
59      while(line != null){
60    //System.out.println(line);
61        //skip comments and empty lines
62        line = line.trim();
63        if( line.startsWith("#") || line.startsWith("//" ) ||
64            line.length() == 0 ){
65          line = br.readLine();
66          continue;
67        }
68        try {
69          remains = line;
70          keycapStr = null;
71          keymapName = null;
72          if(remains.startsWith("bind")){
73            //bind declaration
74            //skip the bind
75            remains = remains.substring(4).trim();
76            //get the key string
77            keyStr = "";
78            start = remains.indexOf('\"');
79            for(end = start + 1 ; remains.charAt(end)!='\"'; end++){
80              if(remains.charAt(end) == '\\') end++;
81              keyStr += remains.charAt(end);
82            }
83            remains = remains.substring(end + 1).trim();
84            if(remains.startsWith("digit")) {
85              //digit declaration
86              //skip the "digit"
87              remains = remains.substring(5).trim();
88              //read the hex number(s)
89              output = "";
90              while(remains.startsWith("0x")){
91                //read the hex number(s)
92                number = remains.substring(2,6);
93                output += (char)Integer.parseInt(number, 16);
94                //do not trim so we can get out after the first number is read
95                remains = remains.substring(6);
96              }
97              remains = remains.trim();
98  
99              //read the second number if it exists and ignore the first
100             if(remains.length() > 0){
101               output = "";
102               while(remains.startsWith("0x")){
103                 //read the hex number(s)
104                 number = remains.substring(2,6);
105                 output += (char)Integer.parseInt(number, 16);
106                 //do not trim so we can get out after the first number is read
107                 remains = remains.substring(6);
108               }
109             }
110             addAction(keyStr, output, output);
111             //we're through with this line
112           } else if(remains.startsWith("send")) {
113             //send declaration
114             //skip the send
115             remains = remains.substring(4).trim();
116             //parse the text to be sent
117             output = "";
118             while(remains.startsWith("0x")) {
119               //read the hex number(s)
120               number = remains.substring(2,6);
121               output += (char)Integer.parseInt(number, 16);
122               remains = remains.substring(6).trim();
123             }
124             //skip the keycap declaration
125             if(remains.startsWith("keycap")){
126               //skip "keycap"
127               remains = remains.substring(6).trim();
128               //skip all the numbers
129               keycapStr = "";
130               while(remains.startsWith("0x")){
131                 //read the hex number(s)
132                 number = remains.substring(2,6);
133                 keycapStr += (char)Integer.parseInt(number, 16);
134                 remains = remains.substring(6).trim();
135               }
136             }
137             //is there a keymap declaration?
138             if (remains.startsWith("keymap")){
139               //skip "keymap"
140               remains = remains.substring(6).trim();
141   //XXXXXXXXXXXXXXXXXX//TO DO handle keymap declaration
142             } else if(remains.length() == 0) {
143               //we're done with this line
144               addAction(keyStr, output, keycapStr);
145             } else System.err.println("[Gate Unicode input method loader]" +
146                                      " Ignoring line: " + line);
147           } else if(remains.startsWith("resetorsend")){
148             //send declaration
149             //skip the resetorsend
150             remains = remains.substring(11).trim();
151   //XXXXXXXXXXXXXXXXXX//TO DO handle resetorsend declaration
152           } else System.err.println("[Gate Unicode input method loader]" +
153                                  " Ignoring line: " + line);
154         } else if(remains.startsWith("keymap")){
155           //keymap declaration
156         } else if(remains.startsWith("inputmethod")){
157           //ignore
158         } else if(remains.startsWith("option")){
159           //ignore
160         } else System.err.println("[Gate Unicode input method loader]" +
161                                  " Ignoring line: " + line);
162       } catch(StringIndexOutOfBoundsException siobe) {
163         System.err.println("[Gate Unicode input method loader]" +
164                            " Ignoring line: " + line);
165       }
166       line = br.readLine();
167     }//while(line != null)
168   }//public LocaleHandler(String fileName)
169 
170   /**    *
171    * @param keyDesc
172    * @param textToAdd
173    * @param keycapStr
174    */
175   protected State addAction(String keyDesc,
176                             String textToAdd,
177                             String keycapStr) {
178     //create the list of keys
179     List keyList = new ArrayList(1);
180     int modifiers = 0;
181     char keyChar;
182     int offset = 0;
183     while(keyDesc.length() > 0) {
184   //System.out.println("A");
185       modifiers = 0;
186       offset = 0;
187       if(keyDesc.startsWith("C-")) {
188         //CTRL + ?
189         modifiers |= InputEvent.CTRL_MASK;
190         offset = 2;
191       } else if(keyDesc.startsWith("M-")) {
192         //ALT + ?
193         modifiers |= InputEvent.ALT_MASK;
194         offset = 2;
195       }
196       keyChar = keyDesc.charAt(offset);
197       keyDesc = keyDesc.substring(offset + 1).trim();
198       keyList.add(new Key(keyChar, modifiers));
199     }//while(keyDesc.length() > 0)
200 
201     //add the keycap
202     if(keycapStr != null && keyList.size() == 1) {
203       keycap.put(keyList.get(0), keycapStr);
204 //System.out.println("Added keycap: " + keycapStr);
205     }
206 
207     //create the states and actions from the list of keys
208     State nextState, currentState = initialState;
209     Action currentAction = null;
210     Iterator keyIter = keyList.iterator();
211     Key currentKey;
212     while(keyIter.hasNext()) {
213       currentKey = (Key)keyIter.next();
214       currentAction = currentState.getNext(currentKey);
215       if(currentAction == null){
216         nextState = new State();
217         currentAction = new Action(nextState);
218         currentState.addAction(currentKey, currentAction);
219         currentAction.setComposedText("" + currentKey.keyChar);
220       } else nextState = currentAction.getNext();
221       currentState = nextState;
222     }//while(keyIter.hasNext())
223     currentAction.setComposedText(textToAdd);
224     currentState.setFinal(true);
225     return currentState;
226   }// State addAction
227 
228   /**
229    * The initial state of the FSM.
230    *
231    */
232   public State getInitialState(){
233     return initialState;
234   }
235 
236   /**
237    * Gets the map with the keycaps (the strings to be painted on virtual keys).
238    *
239    */
240   public Map  getKeyCap(){
241     return keycap;
242   }
243 
244   //the initial state of the fsm
245   /**
246    * The initial state of the fsm.
247    *
248    */
249   State initialState;
250   /** maps from string (the English description of the key) to
251    * string (the string to be displayed on the key)
252    *
253    */
254   Map keycap;
255 
256   /**
257    * The locale this handler handles.
258    *
259    */
260   Locale locale;
261 }//class LocaleHandler
262