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