1   /*
2    * KeyboardMap.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: KeyboardMap.java,v 1.3 2001/05/09 11:08:28 valyt Exp $
16   */
17  package guk.im;
18  
19  import java.awt.*;
20  import java.awt.event.*;
21  import java.util.*;
22  import javax.swing.*;
23  import javax.swing.border.*;
24  import javax.swing.plaf.LabelUI;
25  
26  import guk.*;
27  
28  /**
29   * A virtual keyboard map. It uses its own thread do udate the display.
30   *
31   */
32  public class KeyboardMap implements Runnable{
33  
34    /**
35     * Builds the keyboard map. Uses a window provided by the context of the input
36     * method.
37     *
38     * @param im the input method
39     * @param handler the active Locale handler
40     * @param state the state of the handler.
41     */
42    public KeyboardMap(GateIM im, LocaleHandler handler, State state){
43      this.im = im;
44      this.handler = handler;
45      this.state = state;
46      jobs = Collections.synchronizedList(new ArrayList());
47      myThread = new Thread(Thread.currentThread().getThreadGroup(),
48                            this);
49      myThread.start();
50    }
51  
52    /**
53     * The run method for the thread responsible for updating the display.
54     */
55    public void run(){
56      //do all the initialisations
57      this.window = im.getContext().createInputMethodWindow(null, true);
58      if(window instanceof Frame) ((Frame)window).setTitle(
59                        handler.locale.getDisplayName() +
60                        " keyboard map");
61      window.setVisible(false);
62      window.addWindowListener(new WindowAdapter(){
63  
64      });
65      window.setLayout(new GridLayout(1,1));
66      GridBagLayout layout = new GridBagLayout();
67      contentPane = new JPanel(layout);
68      contentPane.setDoubleBuffered(true);
69      window.add(contentPane, BorderLayout.CENTER);
70  
71      labelForKey = new HashMap();
72      GUIforString = new HashMap();
73  
74      double [] wheights = new double[45];
75      for(int i = 0; i < wheights.length; i++) wheights[i] = 0.001;
76      layout.columnWeights = wheights;
77      wheights = new double[5];
78      for(int i = 0; i < wheights.length; i++) wheights[i] = 0.001;
79      layout.rowWeights = wheights;
80  
81      //read keycaps
82      Map keyCap = handler.getKeyCap();
83      Iterator keyIter = keyCap.keySet().iterator();
84      Key currentKey;
85      JLabel currentLabel;
86      //LabelUI uLabelUI = new BasicUnicodeLabelUI(GateIM.getFontSet());
87      while(keyIter.hasNext()){
88        currentKey = (Key)keyIter.next();
89        currentLabel = new JLabel();
90        //currentLabel.setUI(uLabelUI);
91        currentLabel.setFont(GateIM.getKeyboardFont());
92        currentLabel.setForeground(Color.black);
93        currentLabel.setText((String)keyCap.get(currentKey));
94        labelForKey.put(currentKey, currentLabel);
95      }
96      //build the guis
97      GUIforString = new HashMap();
98      KeyGUI currentGui;
99      int currentModifiers = 0;
100     if(ctrl) currentModifiers |= InputEvent.CTRL_MASK;
101     if(alt) currentModifiers |= InputEvent.ALT_MASK;
102     char ch;
103     String sKey;
104     for(ch = 'a'; ch <= 'z'; ch++){
105       sKey = "" + ch;
106       if(shift) currentKey = new Key(Character.toUpperCase(ch), currentModifiers);
107       else currentKey = new Key(ch, currentModifiers);
108       currentGui = new KeyGUI(sKey, ch, Character.toUpperCase(ch),
109                              (JLabel)labelForKey.get(currentKey));
110       GUIforString.put(sKey, currentGui);
111     }
112     if(shift) ch = '!'; else ch = '1';
113     sKey = "1";
114     currentKey = new Key(ch, currentModifiers);
115     currentGui = new KeyGUI(sKey, '1', '!',(JLabel)labelForKey.get(currentKey));
116     GUIforString.put(sKey, currentGui);
117     if(shift) ch = '\"'; else ch = '2';
118     sKey = "2";
119     currentKey = new Key(ch, currentModifiers);
120     currentGui = new KeyGUI(sKey, '2', '\"',(JLabel)labelForKey.get(currentKey));
121     GUIforString.put(sKey, currentGui);
122     if(shift) ch = '£'; else ch = '3';
123     sKey = "3";
124     currentKey = new Key(ch, currentModifiers);
125     currentGui = new KeyGUI(sKey, '3', '£',(JLabel)labelForKey.get(currentKey));
126     GUIforString.put(sKey, currentGui);
127     if(shift) ch = '$'; else ch = '4';
128     sKey = "4";
129     currentKey = new Key(ch, currentModifiers);
130     currentGui = new KeyGUI(sKey, '4', '$',(JLabel)labelForKey.get(currentKey));
131     GUIforString.put(sKey, currentGui);
132     if(shift) ch = '%'; else ch = '5';
133     sKey = "5";
134     currentKey = new Key(ch, currentModifiers);
135     currentGui = new KeyGUI(sKey, '5', '%',(JLabel)labelForKey.get(currentKey));
136     GUIforString.put(sKey, currentGui);
137     if(shift) ch = '^'; else ch = '6';
138     sKey = "6";
139     currentKey = new Key(ch, currentModifiers);
140     currentGui = new KeyGUI(sKey, '6', '^',(JLabel)labelForKey.get(currentKey));
141     GUIforString.put(sKey, currentGui);
142     if(shift) ch = '&'; else ch = '7';
143     sKey = "7";
144     currentKey = new Key(ch, currentModifiers);
145     currentGui = new KeyGUI(sKey, '7', '&',(JLabel)labelForKey.get(currentKey));
146     GUIforString.put(sKey, currentGui);
147     if(shift) ch = '*'; else ch = '8';
148     sKey = "8";
149     currentKey = new Key(ch, currentModifiers);
150     currentGui = new KeyGUI(sKey, '8', '*',(JLabel)labelForKey.get(currentKey));
151     GUIforString.put(sKey, currentGui);
152     if(shift) ch = '('; else ch = '9';
153     sKey = "9";
154     currentKey = new Key(ch, currentModifiers);
155     currentGui = new KeyGUI(sKey, '9', '(',(JLabel)labelForKey.get(currentKey));
156     GUIforString.put(sKey, currentGui);
157     if(shift) ch = ')'; else ch = '0';
158     sKey = "0";
159     currentKey = new Key(ch, currentModifiers);
160     currentGui = new KeyGUI(sKey, '0', ')',(JLabel)labelForKey.get(currentKey));
161     GUIforString.put(sKey, currentGui);
162     if(shift) ch = '¬'; else ch = '`';
163     sKey = "`";
164     currentKey = new Key(ch, currentModifiers);
165     currentGui = new KeyGUI(sKey, '`', '¬',(JLabel)labelForKey.get(currentKey));
166     GUIforString.put(sKey, currentGui);
167     if(shift) ch = '_'; else ch = '-';
168     sKey = "-";
169     currentKey = new Key(ch, currentModifiers);
170     currentGui = new KeyGUI(sKey, '-', '_',(JLabel)labelForKey.get(currentKey));
171     GUIforString.put(sKey, currentGui);
172     if(shift) ch = '+'; else ch = '=';
173     sKey = "=";
174     currentKey = new Key(ch, currentModifiers);
175     currentGui = new KeyGUI(sKey, '=', '+',(JLabel)labelForKey.get(currentKey));
176     GUIforString.put(sKey, currentGui);
177     if(shift) ch = '{'; else ch = '[';
178     sKey = "[";
179     currentKey = new Key(ch, currentModifiers);
180     currentGui = new KeyGUI(sKey, '[', '{',(JLabel)labelForKey.get(currentKey));
181     GUIforString.put(sKey, currentGui);
182     if(shift) ch = '}'; else ch = ']';
183     sKey = "]";
184     currentKey = new Key(ch, currentModifiers);
185     currentGui = new KeyGUI(sKey, ']', '}',(JLabel)labelForKey.get(currentKey));
186     GUIforString.put(sKey, currentGui);
187     if(shift) ch = ':'; else ch = ';';
188     sKey = ";";
189     currentKey = new Key(ch, currentModifiers);
190     currentGui = new KeyGUI(sKey, ';', ':',(JLabel)labelForKey.get(currentKey));
191     GUIforString.put(sKey, currentGui);
192     if(shift) ch = '@'; else ch = '\'';
193     sKey = "'";
194     currentKey = new Key(ch, currentModifiers);
195     currentGui = new KeyGUI(sKey, '\'', '@',(JLabel)labelForKey.get(currentKey));
196     GUIforString.put(sKey, currentGui);
197     if(shift) ch = '~'; else ch = '#';
198     sKey = "#";
199     currentKey = new Key(ch, currentModifiers);
200     currentGui = new KeyGUI(sKey, '#', '~',(JLabel)labelForKey.get(currentKey));
201     GUIforString.put(sKey, currentGui);
202     if(shift) ch = '|'; else ch = '\\';
203     sKey = "\\";
204     currentKey = new Key(ch, currentModifiers);
205     currentGui = new KeyGUI(sKey, '\\', '|',(JLabel)labelForKey.get(currentKey));
206     GUIforString.put(sKey, currentGui);
207     if(shift) ch = '<'; else ch = ',';
208     sKey = ",";
209     currentKey = new Key(ch, currentModifiers);
210     currentGui = new KeyGUI(sKey, ',', '<',(JLabel)labelForKey.get(currentKey));
211     GUIforString.put(sKey, currentGui);
212     if(shift) ch = '>'; else ch = '.';
213     sKey = ".";
214     currentKey = new Key(ch, currentModifiers);
215     currentGui = new KeyGUI(sKey, '.', '>',(JLabel)labelForKey.get(currentKey));
216     GUIforString.put(sKey, currentGui);
217     if(shift) ch = '?'; else ch = '/';
218     sKey = "/";
219     currentKey = new Key(ch, currentModifiers);
220     currentGui = new KeyGUI(sKey, '/', '?',(JLabel)labelForKey.get(currentKey));
221     GUIforString.put(sKey, currentGui);
222 
223     GUIforString.put("BACK_SPACE", new KeyGUI("BACK_SPACE", (char)0,(char)0,new JLabel("BackSpace")));
224     GUIforString.put("TAB", new KeyGUI("TAB", (char)0,(char)0,new JLabel("Tab")));
225     GUIforString.put("CAPS_LOCK", new KeyGUI("CAPS_LOCK", (char)0,(char)0,new JLabel("Caps Lock")));
226     GUIforString.put("ENTER", new KeyGUI("ENTER", (char)0, (char)0,new JLabel("Enter")));
227     GUIforString.put("LSHIFT", new KeyGUI("LSHIFT", (char)0,(char)0,new JLabel("Shift")));
228     GUIforString.put("RSHIFT", new KeyGUI("RSHIFT", (char)0,(char)0,new JLabel("Shift")));
229     GUIforString.put("LCTRL", new KeyGUI("LCTRL", (char)0,(char)0,new JLabel("Ctrl")));
230     GUIforString.put("RCTRL", new KeyGUI("RCTRL", (char)0,(char)0,new JLabel("Ctrl")));
231     GUIforString.put("LALT", new KeyGUI("LALT", (char)0,(char)0,new JLabel("Alt")));
232     GUIforString.put("RALT", new KeyGUI("RALT", (char)0,(char)0,new JLabel("Alt")));
233     GUIforString.put("SPACE", new KeyGUI("SPACE", ' ', ' ',new JLabel(" ")));
234 
235     //add the components to the window
236     GridBagConstraints constraints = new GridBagConstraints();
237     constraints.fill = constraints.BOTH;
238     constraints.gridwidth = 3;
239     contentPane.add((Component)GUIforString.get("`"), constraints);
240     contentPane.add((Component)GUIforString.get("1"), constraints);
241     contentPane.add((Component)GUIforString.get("2"), constraints);
242     contentPane.add((Component)GUIforString.get("3"), constraints);
243     contentPane.add((Component)GUIforString.get("4"), constraints);
244     contentPane.add((Component)GUIforString.get("5"), constraints);
245     contentPane.add((Component)GUIforString.get("6"), constraints);
246     contentPane.add((Component)GUIforString.get("7"), constraints);
247     contentPane.add((Component)GUIforString.get("8"), constraints);
248     contentPane.add((Component)GUIforString.get("9"), constraints);
249     contentPane.add((Component)GUIforString.get("0"), constraints);
250     contentPane.add((Component)GUIforString.get("-"), constraints);
251     contentPane.add((Component)GUIforString.get("="), constraints);
252     constraints.gridwidth = 6;
253     contentPane.add((Component)GUIforString.get("BACK_SPACE"), constraints);
254     //second line
255     constraints.gridy = 1;
256     constraints.gridwidth = 5;
257     contentPane.add((Component)GUIforString.get("TAB"), constraints);
258     constraints.gridwidth = 3;
259     contentPane.add((Component)GUIforString.get(""+'q'), constraints);
260     contentPane.add((Component)GUIforString.get(""+'w'), constraints);
261     contentPane.add((Component)GUIforString.get(""+'e'), constraints);
262     contentPane.add((Component)GUIforString.get(""+'r'), constraints);
263     contentPane.add((Component)GUIforString.get(""+'t'), constraints);
264     contentPane.add((Component)GUIforString.get(""+'y'), constraints);
265     contentPane.add((Component)GUIforString.get(""+'u'), constraints);
266     contentPane.add((Component)GUIforString.get(""+'i'), constraints);
267     contentPane.add((Component)GUIforString.get(""+'o'), constraints);
268     contentPane.add((Component)GUIforString.get(""+'p'), constraints);
269     contentPane.add((Component)GUIforString.get(""+'['), constraints);
270     contentPane.add((Component)GUIforString.get(""+']'), constraints);
271     constraints.gridwidth = 4;
272     contentPane.add((Component)GUIforString.get(""+'\\'), constraints);
273     //line 3
274     constraints.gridy = 2;
275     constraints.gridwidth = 6;
276     contentPane.add((Component)GUIforString.get("CAPS_LOCK"), constraints);
277     constraints.gridwidth = 3;
278     contentPane.add((Component)GUIforString.get("a"), constraints);
279     contentPane.add((Component)GUIforString.get(""+'s'), constraints);
280     contentPane.add((Component)GUIforString.get(""+'d'), constraints);
281     contentPane.add((Component)GUIforString.get(""+'f'), constraints);
282     contentPane.add((Component)GUIforString.get(""+'g'), constraints);
283     contentPane.add((Component)GUIforString.get(""+'h'), constraints);
284     contentPane.add((Component)GUIforString.get(""+'j'), constraints);
285     contentPane.add((Component)GUIforString.get(""+'k'), constraints);
286     contentPane.add((Component)GUIforString.get(""+'l'), constraints);
287     contentPane.add((Component)GUIforString.get(""+';'), constraints);
288     contentPane.add((Component)GUIforString.get("'"), constraints);
289     constraints.gridwidth = 6;
290     contentPane.add((Component)GUIforString.get("ENTER"), constraints);
291     //line 4
292     constraints.gridy = 3;
293     constraints.gridwidth = 5;
294     contentPane.add((Component)GUIforString.get("LSHIFT"), constraints);
295     constraints.gridwidth = 3;
296     contentPane.add((Component)GUIforString.get(""+'z'), constraints);
297     contentPane.add((Component)GUIforString.get(""+'x'), constraints);
298     contentPane.add((Component)GUIforString.get(""+'c'), constraints);
299     contentPane.add((Component)GUIforString.get(""+'v'), constraints);
300     contentPane.add((Component)GUIforString.get(""+'b'), constraints);
301     contentPane.add((Component)GUIforString.get(""+'n'), constraints);
302     contentPane.add((Component)GUIforString.get(""+'m'), constraints);
303     contentPane.add((Component)GUIforString.get(""+','), constraints);
304     contentPane.add((Component)GUIforString.get(""+'.'), constraints);
305     contentPane.add((Component)GUIforString.get(""+'/'), constraints);
306     contentPane.add((Component)GUIforString.get(""+'#'), constraints);
307     constraints.gridwidth = 8;
308     contentPane.add((Component)GUIforString.get("RSHIFT"), constraints);
309     //line 5
310     constraints.gridy = 4;
311     constraints.gridwidth = 5;
312     contentPane.add((Component)GUIforString.get("LCTRL"), constraints);
313     contentPane.add((Component)GUIforString.get("LALT"), constraints);
314     constraints.gridwidth = 25;
315     contentPane.add((Component)GUIforString.get("SPACE"), constraints);
316     constraints.gridwidth = 5;
317     contentPane.add((Component)GUIforString.get("RALT"), constraints);
318     contentPane.add((Component)GUIforString.get("RCTRL"), constraints);
319     window.pack();
320 
321     if(im.mapVisible) window.setVisible(true);
322 
323     //initialisations done
324     //wait for jobs to do
325     infinite:while(true){
326       synchronized(jobs){
327         try{
328           if(!jobs.isEmpty()){
329             //do the jobs in the job list
330             while(!jobs.isEmpty()){
331               Object job = jobs.remove(0);
332               //do job
333               if(job instanceof String){
334                 //job is a command
335                 String sJob = (String)job;
336                 //should we die? :(
337                 if(sJob.equalsIgnoreCase("DIE")) break infinite;
338                 else if(sJob.equalsIgnoreCase("HIDE") && window.isShowing()){
339                   window.setVisible(false);
340                 }else if(sJob.equalsIgnoreCase("SHOW") && (!window.isShowing())){
341                   window.setVisible(true);
342                 }else if(sJob.equalsIgnoreCase("UPDATE")) update();
343               }else if(job instanceof KeyEvent){
344                 //job is an key event
345                 int code;
346                 KeyEvent kEvent = (KeyEvent)job;
347                 KeyGUI someGui;
348                 if(kEvent.getID() == KeyEvent.KEY_PRESSED){
349                   code = kEvent.getKeyCode();
350                   switch(code){
351                     case KeyEvent.VK_SHIFT: {
352                       if(!shift) {
353                         shift = true;
354                         ((KeyGUI)GUIforString.get("LSHIFT")).pressKey();
355                         ((KeyGUI)GUIforString.get("RSHIFT")).pressKey();
356                         updateLabels();
357                       }
358                       break;
359                     }
360                     case KeyEvent.VK_CONTROL:{
361                       if(!ctrl){
362                         ctrl = true;
363                         ((KeyGUI)GUIforString.get("LCTRL")).pressKey();
364                         ((KeyGUI)GUIforString.get("RCTRL")).pressKey();
365                       updateLabels();
366                       }
367                       break;
368                     }
369                     case KeyEvent.VK_ALT:{
370                       if(!alt){
371                         alt = true;
372                         ((KeyGUI)GUIforString.get("LALT")).pressKey();
373                         ((KeyGUI)GUIforString.get("RALT")).pressKey();
374                         updateLabels();
375                       }
376                       break;
377                     }
378                     case KeyEvent.VK_CAPS_LOCK:{
379                       someGui = (KeyGUI)GUIforString.get("CAPS_LOCK");
380                       someGui.pressKey();
381                       break;
382                     }
383                     case KeyEvent.VK_BACK_SPACE:{
384                       someGui = (KeyGUI)GUIforString.get("BACK_SPACE");
385                       someGui.pressKey();
386                       break;
387                     }
388                     case KeyEvent.VK_ENTER:{
389                       someGui = (KeyGUI)GUIforString.get("ENTER");
390                       someGui.pressKey();
391                       break;
392                     }
393                     case KeyEvent.VK_TAB:{
394                       someGui = (KeyGUI)GUIforString.get("TAB");
395                       someGui.pressKey();
396                       break;
397                     }
398                     case KeyEvent.VK_SPACE:{
399                       someGui = (KeyGUI)GUIforString.get("SPACE");
400                       someGui.pressKey();
401                       break;
402                     }
403                     default:{
404                       String key = "";
405                       char keyCh = kEvent.getKeyChar();
406                       if('a' <= keyCh && keyCh <= 'z'){
407                         key += keyCh;
408                       }else if('A' <= keyCh && keyCh <= 'Z'){
409                         key += Character.toLowerCase(keyCh);
410                       }else{
411                         switch(keyCh){
412                           case '`':{
413                             key += keyCh;
414                             break;
415                           }
416                           case '1':{
417                             key += keyCh;
418                             break;
419                           }
420                           case '2':{
421                             key += keyCh;
422                             break;
423                           }
424                           case '3':{
425                             key += keyCh;
426                             break;
427                           }
428                           case '4':{
429                             key += keyCh;
430                             break;
431                           }
432                           case '5':{
433                             key += keyCh;
434                             break;
435                           }
436                           case '6':{
437                             key += keyCh;
438                             break;
439                           }
440                           case '7':{
441                             key += keyCh;
442                             break;
443                           }
444                           case '8':{
445                             key += keyCh;
446                             break;
447                           }
448                           case '9':{
449                             key += keyCh;
450                             break;
451                           }
452                           case '0':{
453                             key += keyCh;
454                             break;
455                           }
456                           case '-':{
457                             key += keyCh;
458                             break;
459                           }
460                           case '=':{
461                             key += keyCh;
462                             break;
463                           }
464                           case '[':{
465                             key += keyCh;
466                             break;
467                           }
468                           case ']':{
469                             key += keyCh;
470                             break;
471                           }
472                           case ';':{
473                             key += keyCh;
474                             break;
475                           }
476                           case '\'':{
477                             key += keyCh;
478                             break;
479                           }
480                           case '#':{
481                             key += keyCh;
482                             break;
483                           }
484                           case '\\':{
485                             key += keyCh;
486                             break;
487                           }
488                           case ',':{
489                             key += keyCh;
490                             break;
491                           }
492                           case '.':{
493                             key += keyCh;
494                             break;
495                           }
496                           case '/':{
497                             key += keyCh;
498                             break;
499                           }
500 
501 
502                           case '¬':{
503                             key += '`';
504                             break;
505                           }
506                           case '!':{
507                             key += '1';
508                             break;
509                           }
510                           case '\"':{
511                             key += '2';
512                             break;
513                           }
514                           case '£':{
515                             key += '3';
516                             break;
517                           }
518                           case '$':{
519                             key += '4';
520                             break;
521                           }
522                           case '%':{
523                             key += '5';
524                             break;
525                           }
526                           case '^':{
527                             key += '6';
528                             break;
529                           }
530                           case '&':{
531                             key += '7';
532                             break;
533                           }
534                           case '*':{
535                             key += '8';
536                             break;
537                           }
538                           case '(':{
539                             key += '9';
540                             break;
541                           }
542                           case ')':{
543                             key += '0';
544                             break;
545                           }
546                           case '_':{
547                             key += '-';
548                             break;
549                           }
550                           case '+':{
551                             key += '=';
552                             break;
553                           }
554                           case '{':{
555                             key += '[';
556                             break;
557                           }
558                           case '}':{
559                             key += ']';
560                             break;
561                           }
562                           case ':':{
563                             key += ';';
564                             break;
565                           }
566                           case '@':{
567                             key += '\'';
568                             break;
569                           }
570                           case '~':{
571                             key += '#';
572                             break;
573                           }
574                           case '|':{
575                             key += '\\';
576                             break;
577                           }
578                           case '<':{
579                             key += ',';
580                             break;
581                           }
582                           case '>':{
583                             key += '.';
584                             break;
585                           }
586                           case '?':{
587                             key += '/';
588                             break;
589                           }
590                         }//switch
591                       }
592                       someGui = (KeyGUI)GUIforString.get(key);
593                       if(someGui != null){
594                         someGui.pressKey();
595                       }
596                     }//default
597                   }//switch
598                 }else if(kEvent.getID() == KeyEvent.KEY_RELEASED){
599                   code = kEvent.getKeyCode();
600                   switch(code){
601                     case KeyEvent.VK_SHIFT: {
602                       if(shift) {
603                         shift = false;
604                         ((KeyGUI)GUIforString.get("LSHIFT")).releaseKey();
605                         ((KeyGUI)GUIforString.get("RSHIFT")).releaseKey();
606                         updateLabels();
607                       }
608                       break;
609                     }
610                     case KeyEvent.VK_CONTROL:{
611                       if(ctrl){
612                         ctrl = false;
613                         ((KeyGUI)GUIforString.get("LCTRL")).releaseKey();
614                         ((KeyGUI)GUIforString.get("RCTRL")).releaseKey();
615                         updateLabels();
616                       }
617                       break;
618                     }
619                     case KeyEvent.VK_ALT:{
620                       if(alt){
621                         alt = false;
622                         ((KeyGUI)GUIforString.get("LALT")).releaseKey();
623                         ((KeyGUI)GUIforString.get("RALT")).releaseKey();
624                         updateLabels();
625                       }
626                       break;
627                     }
628                     case KeyEvent.VK_CAPS_LOCK:{
629                       someGui = (KeyGUI)GUIforString.get("CAPS_LOCK");
630                       someGui.releaseKey();
631                       break;
632                     }
633                     case KeyEvent.VK_BACK_SPACE:{
634                       someGui = (KeyGUI)GUIforString.get("BACK_SPACE");
635                       someGui.releaseKey();
636                       break;
637                     }
638                     case KeyEvent.VK_ENTER:{
639                       someGui = (KeyGUI)GUIforString.get("ENTER");
640                       someGui.releaseKey();
641                       break;
642                     }
643                     case KeyEvent.VK_TAB:{
644                       someGui = (KeyGUI)GUIforString.get("TAB");
645                       someGui.releaseKey();
646                       break;
647                     }
648                     case KeyEvent.VK_SPACE:{
649                       someGui = (KeyGUI)GUIforString.get("SPACE");
650                       someGui.releaseKey();
651                       break;
652                     }
653                     default:{
654                       String key = "";
655                       char keyCh = kEvent.getKeyChar();
656                       if('a' <= keyCh && keyCh <= 'z'){
657                         key += keyCh;
658                       }else if('A' <= keyCh && keyCh <= 'Z'){
659                         key += Character.toLowerCase(keyCh);
660                       }else{
661                         switch(keyCh){
662                           case '`':{
663                             key += keyCh;
664                             break;
665                           }
666                           case '1':{
667                             key += keyCh;
668                             break;
669                           }
670                           case '2':{
671                             key += keyCh;
672                             break;
673                           }
674                           case '3':{
675                             key += keyCh;
676                             break;
677                           }
678                           case '4':{
679                             key += keyCh;
680                             break;
681                           }
682                           case '5':{
683                             key += keyCh;
684                             break;
685                           }
686                           case '6':{
687                             key += keyCh;
688                             break;
689                           }
690                           case '7':{
691                             key += keyCh;
692                             break;
693                           }
694                           case '8':{
695                             key += keyCh;
696                             break;
697                           }
698                           case '9':{
699                             key += keyCh;
700                             break;
701                           }
702                           case '0':{
703                             key += keyCh;
704                             break;
705                           }
706                           case '-':{
707                             key += keyCh;
708                             break;
709                           }
710                           case '=':{
711                             key += keyCh;
712                             break;
713                           }
714                           case '[':{
715                             key += keyCh;
716                             break;
717                           }
718                           case ']':{
719                             key += keyCh;
720                             break;
721                           }
722                           case ';':{
723                             key += keyCh;
724                             break;
725                           }
726                           case '\'':{
727                             key += keyCh;
728                             break;
729                           }
730                           case '#':{
731                             key += keyCh;
732                             break;
733                           }
734                           case '\\':{
735                             key += keyCh;
736                             break;
737                           }
738                           case ',':{
739                             key += keyCh;
740                             break;
741                           }
742                           case '.':{
743                             key += keyCh;
744                             break;
745                           }
746                           case '/':{
747                             key += keyCh;
748                             break;
749                           }
750 
751 
752                           case '¬':{
753                             key += '`';
754                             break;
755                           }
756                           case '!':{
757                             key += '1';
758                             break;
759                           }
760                           case '\"':{
761                             key += '2';
762                             break;
763                           }
764                           case '£':{
765                             key += '3';
766                             break;
767                           }
768                           case '$':{
769                             key += '4';
770                             break;
771                           }
772                           case '%':{
773                             key += '5';
774                             break;
775                           }
776                           case '^':{
777                             key += '6';
778                             break;
779                           }
780                           case '&':{
781                             key += '7';
782                             break;
783                           }
784                           case '*':{
785                             key += '8';
786                             break;
787                           }
788                           case '(':{
789                             key += '9';
790                             break;
791                           }
792                           case ')':{
793                             key += '0';
794                             break;
795                           }
796                           case '_':{
797                             key += '-';
798                             break;
799                           }
800                           case '+':{
801                             key += '=';
802                             break;
803                           }
804                           case '{':{
805                             key += '[';
806                             break;
807                           }
808                           case '}':{
809                             key += ']';
810                             break;
811                           }
812                           case ':':{
813                             key += ';';
814                             break;
815                           }
816                           case '@':{
817                             key += '\'';
818                             break;
819                           }
820                           case '~':{
821                             key += '#';
822                             break;
823                           }
824                           case '|':{
825                             key += '\\';
826                             break;
827                           }
828                           case '<':{
829                             key += ',';
830                             break;
831                           }
832                           case '>':{
833                             key += '.';
834                             break;
835                           }
836                           case '?':{
837                             key += '/';
838                             break;
839                           }
840                         }//switch
841                       }
842                       someGui = (KeyGUI)GUIforString.get(key);
843                       if(someGui != null){
844                         someGui.releaseKey();
845                       }
846                     }//default
847                   }//switch
848                 }
849                 //update the state so the rebuildGui will update the highlights
850 //                state = im.currentState;
851 //                update();
852               }
853             }
854           }
855         }catch(Exception e){}
856         jobs.notifyAll();
857       }//synchronized(jobs);
858       //no more jobs, take a nap :)
859       try{
860         myThread.sleep(150);
861       }catch(InterruptedException ie){
862         ie.printStackTrace();
863       }
864     }//infinite: while(true)
865 
866   }
867 
868   /**
869    * Adds a job to the job list of the thread.
870    * A job is either a {@link java.lang.String} or an {@link java.awt.event.InputEvent}
871    * The string can be one of
872    * <ul>
873    * <li>SHOW: shows the keyboard map window
874    * <li>UPDATE updates the keyboard map window
875    * <li>HIDE: hides the keyboard map window
876    * <li>DIE: releases all the memory and terminates the thread
877    * </ul>
878    *
879    * The input events refer to pressed keys and are treated accordingly.
880    *
881    * @param job
882    */
883   public void addJob(Object job){
884     synchronized(jobs){
885       jobs.add(job);
886       jobs.notifyAll();
887     }
888   }
889 
890   /**
891    * Updates the keyboard map for a new Locale or a new state of the current locale handler.
892    * Currently the state changes are ignored.
893    * This method delegates its job to the thread which will do the actual
894    * update.
895    * @param newHandler
896    * @param newState
897    */
898   public void update(LocaleHandler newHandler, State newState){
899     //did anything changed?
900     if(newHandler == handler && newState == state) return;
901     this.newHandler = newHandler;
902     this.newState = newState;
903     addJob("UPDATE");
904   }
905 
906   /**
907    * Does th actual update.
908    */
909   protected void update(){
910     //did the locale changed?
911     if(newHandler != handler){
912       handler = newHandler;
913       state = newState;
914       if(window instanceof Frame) ((Frame)window).setTitle(
915                               handler.locale.getDisplayLanguage() + " (" +
916                               handler.locale.getVariant() + ") keyboard map");
917       //read keycaps
918       labelForKey.clear();
919       Map keyCap = handler.getKeyCap();
920       Iterator keyIter = keyCap.keySet().iterator();
921       Key currentKey;
922       JLabel currentLabel;
923       //LabelUI uLabelUI = new BasicUnicodeLabelUI(GateIM.getFontSet());
924       while(keyIter.hasNext()){
925         currentKey = (Key)keyIter.next();
926         currentLabel = new JLabel();
927         currentLabel.setFont(GateIM.getKeyboardFont());
928         //currentLabel.setUI(uLabelUI);
929         currentLabel.setText((String)keyCap.get(currentKey));
930         labelForKey.put(currentKey, currentLabel);
931       }
932       updateLabels();
933     }
934     //did the state changed?
935     if(newState != state){
936       //highlight the allowed keys
937       state = newState;
938       //un-highlight the highlighted keys
939       Iterator keysIter = highlightedKeys.iterator();
940       while(keysIter.hasNext()) ((KeyGUI)keysIter.next()).unHighlight();
941       highlightedKeys.clear();
942 
943       //if not initial state highlight the allowed keys
944       if(state != handler.getInitialState()){
945         keysIter = state.transitionFunction.keySet().iterator();
946         KeyGUI someGui;
947         while(keysIter.hasNext()){
948           someGui = guiForKey((Key)keysIter.next());
949           if(someGui != null){
950             someGui.highlight();
951             highlightedKeys.add(someGui);
952           }
953         }
954       }
955     }
956   }
957 
958   /**
959    * Updates the virtual keyboard to reflect the current state.
960    */
961   protected void updateLabels(){
962     //update the labels
963     Component[] components = contentPane.getComponents();
964     for(int i = 0; i <components.length; i++){
965       if(components[i] instanceof KeyGUI) ((KeyGUI)components[i]).updateLabel();
966     }
967     fixShape();
968   }
969 
970   /**    */
971   protected void fixShape(){
972     //get the current sizes
973     int [][] sizes = ((GridBagLayout)contentPane.getLayout()).getLayoutDimensions();
974     //override the minimum sizes
975     ((GridBagLayout)contentPane.getLayout()).columnWidths = sizes[0];
976     ((GridBagLayout)contentPane.getLayout()).rowHeights = sizes[1];
977     window.pack();
978     contentPane.repaint(100);
979   }
980   /**
981    * Gets the gui that corresponds to a Key object.
982    *
983    * @param key
984    */
985   protected KeyGUI guiForKey(Key key){
986     char ch = key.keyChar;
987     boolean shiftOn = false;
988     if(Character.isUpperCase(ch)){
989       ch = Character.toLowerCase(ch);
990       shiftOn = true;
991     }
992     boolean ctrlOn = (key.modifiers & KeyEvent.CTRL_MASK) > 0;
993     boolean altOn = (key.modifiers & KeyEvent.ALT_MASK) > 0;
994     if(shift == shiftOn &&
995        ctrl == ctrlOn &&
996        alt == altOn){
997       return (KeyGUI)GUIforString.get("" + ch);
998     }
999     return null;
1000  }
1001  /**
1002   * Is the Shift key pressed?
1003   *
1004   * @param shift
1005   */
1006  public void setShift(boolean shift){
1007    this.shift = shift;
1008  }
1009
1010  /**
1011   * Is the Alt key pressed?
1012   *
1013   * @param alt
1014   */
1015  public void setAlt(boolean alt){
1016    this.alt = alt;
1017  }
1018
1019  /**
1020   * Is the Ctrl key pressed?
1021   *
1022   * @param ctrl
1023   */
1024  public void setCtrl(boolean ctrl){
1025    this.ctrl = ctrl;
1026  }
1027
1028//variables
1029
1030  //the current LocaleHandler
1031  /**
1032   * the active locale handler
1033   */
1034  LocaleHandler handler;
1035  //thenew handler that will become current on the next update
1036  /**
1037   * The new active locale handler. This member is useful during the period when the active locale handler has changed but the keyboard map is not updated yet. The keyboard map will be updated as soon as the tasks that were added to the job list before the locale change are consumed.
1038   */
1039  LocaleHandler newHandler;
1040
1041  //the current state of the current locale handler
1042  /**
1043   * The current state of the current locale handler.
1044   */
1045  State state;
1046  //the new state that will become current on the next update
1047  /**
1048   * The current state of the new current locale handler.
1049   *
1050   * @see #newHandler
1051   */
1052  State newState;
1053  /**
1054   * The window used for displaying the keyboard map
1055   */
1056  Window window;
1057  /**
1058   * The content pane that holds all the KeyGUIs.
1059   *
1060   * @see guk.im.KeyboardMap.KeyGUI
1061   */
1062  JPanel contentPane;
1063
1064  /**
1065   * The keys curently highlighted
1066   */
1067  java.util.List highlightedKeys = new ArrayList();
1068
1069  /**    */
1070  boolean shift = false, ctrl = false, alt = false, capslock = false;
1071  /** maps from String(the English lowercase representation of the key) to
1072   * KeyGUI
1073   */
1074  Map GUIforString;
1075  //maps from Key to JLabel for the key that have keyCap defined
1076  /**
1077   * Maps from Key to JLabel for the keys that have keyCap defined
1078   * .
1079   */
1080  Map labelForKey;
1081
1082  /**
1083   * The input method.
1084   */
1085  GateIM im;
1086
1087  /**
1088   * The thread that does the updating.
1089   */
1090  Thread myThread;
1091
1092  /**
1093   * The job list.
1094   */
1095  java.util.List jobs;
1096//classes
1097  public class KeyGUI extends JPanel {
1098    /**      */
1099    Box leftBox;
1100    /**      */
1101    JLabel leftUpLabel = new JLabel();
1102    /**      */
1103    JLabel leftDownLabel = new JLabel();
1104    /**      */
1105    Component centerLabel;
1106    /**      */
1107    char low, up;
1108    /**      */
1109    Border normalBorder, highlightedBorder;
1110
1111    /**
1112     * Constructs a new KeyGUI.
1113     *
1114     * @param key the String key used in the map that holds the GUIs used for
1115     * keys
1116     * @param englishLow the English char on the key
1117     * @param englishUp the English char on the key when used with the Shift
1118     *     key.
1119     * @param center the center label (the Unicode character on the key)
1120     */
1121    public KeyGUI(String key, char englishLow, char englishUp,
1122                  JLabel center) {
1123      this.setBackground(Color.lightGray);
1124      low = englishLow;
1125      up = englishUp;
1126      leftBox = Box.createVerticalBox();
1127      Dimension dim;
1128      if(englishUp > (char)0){
1129        leftUpLabel.setFont(leftUpLabel.getFont().deriveFont((float)10));
1130        leftUpLabel.setText("" + englishUp);
1131        leftBox.add(leftUpLabel);
1132      }else{
1133        leftBox.add(placeHolder);
1134      }
1135      if(englishLow > (char)0){
1136        leftDownLabel.setFont(leftDownLabel.getFont().deriveFont((float)10));
1137        leftDownLabel.setText("" + englishLow);
1138        leftBox.add(leftDownLabel);
1139      }else{
1140        leftBox.add(placeHolder);
1141      }
1142      leftBox.add(Box.createVerticalGlue());
1143      if(center == null) centerLabel = placeHolder;
1144      else centerLabel = center;
1145      this.setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
1146      this.add(leftBox);
1147      this.add(Box.createHorizontalGlue());
1148      this.add(centerLabel);
1149      normalBorder = new CompoundBorder(new BevelBorder(BevelBorder.RAISED),
1150                                        new EmptyBorder(2,3,2,3));
1151      highlightedBorder = new CompoundBorder(new BevelBorder(BevelBorder.RAISED),
1152                                        new MatteBorder(2,3,2,3, Color.green));
1153
1154      this.setBorder(normalBorder);
1155      addMouseListener(new MouseAdapter(){
1156        /**          *
1157         * @param e
1158         */
1159        public void mouseClicked(MouseEvent e){
1160          int modifiers = 0;
1161          if(ctrl) modifiers |= KeyEvent.CTRL_MASK;
1162          if(alt) modifiers |= KeyEvent.ALT_MASK;
1163          char ch;
1164          if(shift) ch = up;
1165          else ch = low;
1166          if(ch != 0){
1167            im.dispatchEvent(new KeyEvent(window, KeyEvent.KEY_TYPED,
1168                                          System.currentTimeMillis(),
1169                                          modifiers, KeyEvent.VK_UNDEFINED, ch));
1170          }
1171        }
1172        /**          */
1173        public void mousePressed(MouseEvent e){
1174          char ch;
1175          if(shift) ch = up;
1176          else ch = low;
1177          if(ch != 0){
1178            pressKey();
1179            //repaint(100);
1180          }
1181        }
1182        /**          */
1183        public void mouseReleased(MouseEvent e){
1184          char ch;
1185          if(shift) ch = up;
1186          else ch = low;
1187          if(ch != 0){
1188            releaseKey();
1189            //repaint(100);
1190          }
1191        }
1192      });
1193    }
1194
1195    /**      */
1196    public void updateLabel(){
1197      if(low == (char)0 || up == (char)0)return;
1198      remove(centerLabel);
1199      Key key;
1200      int modifiers = 0;
1201      if(ctrl) modifiers |= InputEvent.CTRL_MASK;
1202      if(alt) modifiers |= InputEvent.ALT_MASK;
1203      if(shift) key = new Key(up, modifiers);
1204      else key = new Key(low, modifiers);
1205      centerLabel = (JLabel)labelForKey.get(key);
1206      if(centerLabel == null) centerLabel = placeHolder;
1207      this.add(centerLabel);
1208//      this.invalidate();
1209    }
1210
1211    /**
1212     * Displays this key as pressed
1213     */
1214    public void pressKey(){
1215      this.setBackground(Color.darkGray);
1216    }
1217
1218    /**
1219     * Displays ths key as released.
1220     */
1221    public void releaseKey(){
1222      this.setBackground(Color.lightGray);
1223    }
1224
1225    /**
1226     * Renders this KeyGUI as highlighted
1227     */
1228    public void highlight(){
1229      setBorder(highlightedBorder);
1230    }
1231
1232    /**
1233     * Renders this KeyGUI normaly (not highlighted)
1234     */
1235    public void unHighlight(){
1236      setBorder(normalBorder);
1237    }
1238
1239  }//public class KeyGUI extends JPanel
1240
1241
1242
1243  /**
1244   * Empty component used for the key that are not bound to a Unicode character.
1245   */
1246  static Component placeHolder = Box.createRigidArea(new Dimension(12, 12));
1247}//class KeyboardMap
1248