public void run() {
   try {
     if (myPreviousThread != null) myPreviousThread.join();
     Thread.sleep(delay);
     log("> run KeyDownThread");
     while (!hasFocus()) {
       Thread.sleep(1000);
     }
     int vkCode = getVKCode(charCode, keyCode);
     if (charCode >= 32) {
       // if it is printable, then it lives in our hashmap
       KeyEvent event = (KeyEvent) charMap.get(new Integer(charCode));
       // see if we need to press shift to generate this
       // character
       if (event.isShiftDown()) {
         robot.keyPress(KeyEvent.VK_SHIFT);
         shift = true;
       }
       if (event.isAltGraphDown()) {
         robot.keyPress(KeyEvent.VK_ALT_GRAPH);
         altgraph = true;
       }
     } else {
       if (vkCode == KeyEvent.VK_ALT) {
         alt = true;
       } else if (vkCode == KeyEvent.VK_CONTROL) {
         ctrl = true;
       } else if (vkCode == KeyEvent.VK_SHIFT) {
         shift = true;
       } else if (vkCode == KeyEvent.VK_ALT_GRAPH) {
         altgraph = true;
       }
     }
     if (!isUnsafe(vkCode)) {
       robot.keyPress(vkCode);
     }
   } catch (Exception e) {
     log("Bad parameters passed to downKey");
     e.printStackTrace();
   }
   log("< run KeyDownThread");
 }
 private boolean isControl(KeyEvent e) {
   return Character.isISOControl(e.getKeyChar())
       || (e.isAltDown() || e.isAltGraphDown() || e.isControlDown() || e.isMetaDown());
 }