public void insertScreenshot(
     boolean replace, String fileName, String desc, String attachments, String template) {
   String s = "Screenshot " + fileName;
   if (desc != null && !desc.trim().equals("")) {
     s +=
         " "
             + ScreenshotCommand.PARAM_DESC
             + "=\""
             + Utils.escapeUnescapedDoubleQuotes(desc)
             + "\"";
   }
   if (attachments != null && !attachments.trim().equals("")) {
     s +=
         " "
             + ScreenshotCommand.PARAM_ATTACH
             + "=\""
             + Utils.escapeUnescapedDoubleQuotes(attachments)
             + "\"";
   }
   if (template != null && !template.trim().equals("")) {
     s +=
         " "
             + ScreenshotCommand.PARAM_TEMPLATE
             + "=\""
             + Utils.escapeUnescapedDoubleQuotes(template)
             + "\"";
   }
   insertLine(s, replace, isEnabled(), false);
 }
  /**
   * Constructor.
   *
   * @param eventSource source of the mouse and key events which will be translated into scripting
   *     language commands. Such a typical source is e.g. the VNC viewer panel.
   */
  public RecordingModule(
      MainFrame frame, Component eventSource, ScriptManager scriptManager, UserConfiguration cfg) {
    this.cfg = cfg;
    this.scriptManager = scriptManager;
    readOnly = cfg.getBoolean("rfb.readOnly").booleanValue();

    fb = (DesktopViewer) eventSource;
    fb.removeMouseListener(fb);
    eventSource.addMouseListener(this);
    fb.addMouseListener(fb);
    eventSource.addMouseMotionListener(this);
    eventSource.addMouseWheelListener(this);
    eventSource.addKeyListener(this);

    client = scriptManager.getClient();
    if (client != null) {
      client.addServerListener(this);
    }

    //        scriptManager.addMouseInputListener(this);
    //        scriptManager.addKeyListener(this);

    // Number of archived events
    //        events.setSize(EVENT_VECTOR_SIZE);

    // Populate the reversed keycode->keyname Map
    Map t = Utils.getKeyCodeTable();
    Iterator e = t.keySet().iterator();
    Object o;
    while (e.hasNext()) {
      o = e.next();
      keyCodes.put(t.get(o), o);
    }
    cfg.addConfigurationListener(this);
    scriptManager.addScriptListener(this);
    configurationChanged(null);
  }
  public void keyTyped(KeyEvent e) {
    if (debug) {
      System.out.println(
          "--- RecordingModule: key typed = "
              + e
              + "\n  > Key char->int = "
              + (int) e.getKeyChar());
      System.out.println(" -- isActionKey() = " + e.isActionKey());
      System.out.println(" -- isISOControl() = " + Character.isISOControl(e.getKeyChar()));
      System.out.println(" -- isWhitespace() = " + Character.isWhitespace(e.getKeyChar()));
    }

    if (isKeyReserved(e)) {
      return;
    }

    if (enabled && !readOnly && lastKeyPressEvent != null) {

      if (enableKeyboard) {
        boolean replace = false;
        String text = "";
        if (isControl(e)) {
          if (lastKeyPressEvent.getKeyCode() == KeyEvent.VK_ENTER) {

            // Change the Type cmd prior to Typeline if the delay from the last type key is less
            // than 1 sec
            if (useTypeline && e.getModifiers() == 0 && lastElement != null) {
              String s = DocumentUtils.getElementText(lastElement);
              if (s.startsWith("Type ")
                  && (System.currentTimeMillis() - lastInsertTime) < typelineDelay) {
                replace = true;
                text = s.replaceFirst("Type", "Typeline");
              }
            }
          }

          if ("".equals(text)) {
            int count = 1;
            KeyEvent e2;

            long lastEventTime = e.getWhen();

            // We go through the vector of events and check whether there are events corresponding
            // to a typed text.
            for (int i = 0; i < events.size() && events.get(i) instanceof KeyEvent; i++) {
              e2 = (KeyEvent) events.get(i);
              if (e.getID() == e2.getID()
                  && e.getKeyChar() == e2.getKeyChar()
                  && e.getKeyCode() == e2.getKeyCode()
                  && e.getModifiers() == e2.getModifiers()
                  && (lastEventTime - e2.getWhen() < keyMutiDelay)) {
                count++;
                replace = true;
                lastEventTime = e2.getWhen();
              } else {
                break;
              }
            }

            text = "Press ";
            //                    String modifiers = KeyEvent.getKeyModifiersText(e.getModifiers());
            String modifiers = parser.modifiersToString(e.getModifiers());
            if (!"".equals(modifiers)) {
              text += modifiers + "+";
            }
            String charText = KeyEvent.getKeyText(lastKeyPressEvent.getKeyCode());
            if (charText == null) {
              charText = "<unknown>";
            }
            text += charText;
            if (count > 1) {
              text += " " + PressCommand.PARAM_COUNT + "=" + count;
            }

            if (debug) {
              System.out.println("--- RecordingModule: Inserting '" + text + "'");
            }
          }

        } else {
          text = "" + e.getKeyChar();
          KeyEvent e2;

          // We go through the vector of events and check whether there are events corresponding to
          // a typed text.
          for (int i = 0; i < events.size() && events.get(i) instanceof KeyEvent; i++) {
            e2 = (KeyEvent) events.get(i);
            if (!isControl(e2) && !e2.isActionKey()) {
              text = e2.getKeyChar() + text;
              replace = true;
            } else {
              break;
            }
          }

          text = "Type \"" + Utils.escapeUnescapedDoubleQuotes(text) + "\"";
        }

        // Insert the command to the current editor
        insertLine(text, replace, true, false);
      }
      insertEvent(e);
    }
  }