X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Fio%2FAWTTerminal.java;h=8b542402daf5b7321de855fbeffd8d31f09559c7;hb=091d8a06c7f9f91c2a15c9350b6502cf4c10f5a3;hp=c9ddc13f0772eb116dc50327356a424460d84e0b;hpb=1ac2ccb131cfab3a72dad856c67e2f4fd87aa143;p=nikiroo-utils.git diff --git a/src/jexer/io/AWTTerminal.java b/src/jexer/io/AWTTerminal.java index c9ddc13..8b54240 100644 --- a/src/jexer/io/AWTTerminal.java +++ b/src/jexer/io/AWTTerminal.java @@ -30,28 +30,47 @@ */ package jexer.io; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; import java.util.List; import java.util.LinkedList; import jexer.TKeypress; -import jexer.bits.Color; +import jexer.event.TCommandEvent; import jexer.event.TInputEvent; import jexer.event.TKeypressEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; import jexer.session.SessionInfo; -import jexer.session.TSessionInfo; +import jexer.session.AWTSessionInfo; +import static jexer.TCommand.*; import static jexer.TKeypress.*; /** * This class reads keystrokes and mouse events from an AWT Frame. */ -public final class AWTTerminal { +public final class AWTTerminal implements ComponentListener, KeyListener, + MouseListener, MouseMotionListener, + MouseWheelListener, WindowListener { + + /** + * The backend Screen. + */ + private AWTScreen screen; /** * The session information. */ - private SessionInfo sessionInfo; + private AWTSessionInfo sessionInfo; /** * Getter for sessionInfo. @@ -62,35 +81,40 @@ public final class AWTTerminal { return sessionInfo; } + /** + * The listening object that run() wakes up on new input. + */ + private Object listener; + /** * The event queue, filled up by a thread reading on input. */ private List eventQueue; /** - * If true, we want the reader thread to exit gracefully. + * The last reported mouse X position. */ - private boolean stopReaderThread; + private int oldMouseX = -1; /** - * The reader thread. + * The last reported mouse Y position. */ - private Thread readerThread; + private int oldMouseY = -1; /** * true if mouse1 was down. Used to report mouse1 on the release event. */ - private boolean mouse1; + private boolean mouse1 = false; /** * true if mouse2 was down. Used to report mouse2 on the release event. */ - private boolean mouse2; + private boolean mouse2 = false; /** * true if mouse3 was down. Used to report mouse3 on the release event. */ - private boolean mouse3; + private boolean mouse3 = false; /** * Check if there are events in the queue. @@ -106,15 +130,25 @@ public final class AWTTerminal { /** * Constructor sets up state for getEvent(). * - * @param screen the top-level AWT frame + * @param listener the object this backend needs to wake up when new + * input comes in + * @param screen the top-level AWT frame */ - public AWTTerminal(final AWTScreen screen) { + public AWTTerminal(final Object listener, final AWTScreen screen) { + this.listener = listener; + this.screen = screen; mouse1 = false; mouse2 = false; mouse3 = false; - stopReaderThread = false; - sessionInfo = new TSessionInfo(); + sessionInfo = screen.getSessionInfo(); eventQueue = new LinkedList(); + + screen.frame.addKeyListener(this); + screen.frame.addWindowListener(this); + screen.frame.addComponentListener(this); + screen.frame.addMouseListener(this); + screen.frame.addMouseMotionListener(this); + screen.frame.addMouseWheelListener(this); } /** @@ -122,6 +156,7 @@ public final class AWTTerminal { */ public void shutdown() { // System.err.println("=== shutdown() ==="); System.err.flush(); + screen.frame.dispose(); } /** @@ -141,23 +176,578 @@ public final class AWTTerminal { } /** - * Return any events in the IO queue due to timeout. + * Pass AWT keystrokes into the event queue. * - * @param queue list to append new events to + * @param key keystroke received */ - public void getIdleEvents(final List queue) { + @Override + public void keyReleased(final KeyEvent key) { + // Ignore release events + } - // Insert any polling action here... + /** + * Pass AWT keystrokes into the event queue. + * + * @param key keystroke received + */ + @Override + public void keyTyped(final KeyEvent key) { + // Ignore typed events + } - // Return any events that showed up - synchronized (eventQueue) { - if (eventQueue.size() > 0) { - synchronized (queue) { - queue.addAll(eventQueue); + /** + * Pass AWT keystrokes into the event queue. + * + * @param key keystroke received + */ + @Override + public void keyPressed(final KeyEvent key) { + boolean alt = false; + boolean shift = false; + boolean ctrl = false; + char ch = ' '; + boolean isKey = false; + if (key.isActionKey()) { + isKey = true; + } else { + ch = key.getKeyChar(); + } + alt = key.isAltDown(); + ctrl = key.isControlDown(); + shift = key.isShiftDown(); + + /* + System.err.printf("AWT Key: %s\n", key); + System.err.printf(" isKey: %s\n", isKey); + System.err.printf(" alt: %s\n", alt); + System.err.printf(" ctrl: %s\n", ctrl); + System.err.printf(" shift: %s\n", shift); + System.err.printf(" ch: %s\n", ch); + */ + + // Special case: not return the bare modifier presses + switch (key.getKeyCode()) { + case KeyEvent.VK_ALT: + return; + case KeyEvent.VK_ALT_GRAPH: + return; + case KeyEvent.VK_CONTROL: + return; + case KeyEvent.VK_SHIFT: + return; + case KeyEvent.VK_META: + return; + default: + break; + } + + TKeypress keypress = null; + if (isKey) { + switch (key.getKeyCode()) { + case KeyEvent.VK_F1: + keypress = new TKeypress(true, TKeypress.F1, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F2: + keypress = new TKeypress(true, TKeypress.F2, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F3: + keypress = new TKeypress(true, TKeypress.F3, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F4: + keypress = new TKeypress(true, TKeypress.F4, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F5: + keypress = new TKeypress(true, TKeypress.F5, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F6: + keypress = new TKeypress(true, TKeypress.F6, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F7: + keypress = new TKeypress(true, TKeypress.F7, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F8: + keypress = new TKeypress(true, TKeypress.F8, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F9: + keypress = new TKeypress(true, TKeypress.F9, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F10: + keypress = new TKeypress(true, TKeypress.F10, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F11: + keypress = new TKeypress(true, TKeypress.F11, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_F12: + keypress = new TKeypress(true, TKeypress.F12, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_HOME: + keypress = new TKeypress(true, TKeypress.HOME, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_END: + keypress = new TKeypress(true, TKeypress.END, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_PAGE_UP: + keypress = new TKeypress(true, TKeypress.PGUP, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_PAGE_DOWN: + keypress = new TKeypress(true, TKeypress.PGDN, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_INSERT: + keypress = new TKeypress(true, TKeypress.INS, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_DELETE: + keypress = new TKeypress(true, TKeypress.DEL, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_RIGHT: + keypress = new TKeypress(true, TKeypress.RIGHT, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_LEFT: + keypress = new TKeypress(true, TKeypress.LEFT, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_UP: + keypress = new TKeypress(true, TKeypress.UP, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_DOWN: + keypress = new TKeypress(true, TKeypress.DOWN, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_TAB: + // Special case: distinguish TAB vs BTAB + if (shift) { + keypress = kbShiftTab; + } else { + keypress = kbTab; } - eventQueue.clear(); + break; + case KeyEvent.VK_ENTER: + keypress = new TKeypress(true, TKeypress.ENTER, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_ESCAPE: + keypress = new TKeypress(true, TKeypress.ESC, ' ', + alt, ctrl, shift); + break; + case KeyEvent.VK_BACK_SPACE: + // Special case: return it as kbBackspace (Ctrl-H) + keypress = new TKeypress(false, 0, 'H', false, true, false); + break; + default: + // Unsupported, ignore + return; } } + + if (keypress == null) { + switch (ch) { + case 0x08: + keypress = kbBackspace; + break; + case 0x0A: + keypress = kbEnter; + break; + case 0x1B: + keypress = kbEsc; + break; + case 0x0D: + keypress = kbEnter; + break; + case 0x09: + if (shift) { + keypress = kbShiftTab; + } else { + keypress = kbTab; + } + break; + case 0x7F: + keypress = kbDel; + break; + default: + if (!alt && ctrl && !shift) { + ch = KeyEvent.getKeyText(key.getKeyCode()).charAt(0); + } + // Not a special key, put it together + keypress = new TKeypress(false, 0, ch, alt, ctrl, shift); + } + } + + // Save it and we are done. + synchronized (eventQueue) { + eventQueue.add(new TKeypressEvent(keypress)); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowActivated(final WindowEvent event) { + // Force a total repaint + synchronized (screen) { + screen.clearPhysical(); + } + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowClosed(final WindowEvent event) { + // Ignore + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowClosing(final WindowEvent event) { + // Drop a cmAbort and walk away + synchronized (eventQueue) { + eventQueue.add(new TCommandEvent(cmAbort)); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowDeactivated(final WindowEvent event) { + // Ignore + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowDeiconified(final WindowEvent event) { + // Ignore + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowIconified(final WindowEvent event) { + // Ignore + } + + /** + * Pass window events into the event queue. + * + * @param event window event received + */ + @Override + public void windowOpened(final WindowEvent event) { + // Ignore + } + + /** + * Pass component events into the event queue. + * + * @param event component event received + */ + @Override + public void componentHidden(final ComponentEvent event) { + // Ignore + } + + /** + * Pass component events into the event queue. + * + * @param event component event received + */ + @Override + public void componentShown(final ComponentEvent event) { + // Ignore + } + + /** + * Pass component events into the event queue. + * + * @param event component event received + */ + @Override + public void componentMoved(final ComponentEvent event) { + // Ignore + } + + /** + * Pass component events into the event queue. + * + * @param event component event received + */ + @Override + public void componentResized(final ComponentEvent event) { + // Drop a new TResizeEvent into the queue + sessionInfo.queryWindowSize(); + synchronized (eventQueue) { + TResizeEvent windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN, + sessionInfo.getWindowWidth(), sessionInfo.getWindowHeight()); + eventQueue.add(windowResize); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseDragged(final MouseEvent mouse) { + int modifiers = mouse.getModifiersEx(); + boolean eventMouse1 = false; + boolean eventMouse2 = false; + boolean eventMouse3 = false; + if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) { + eventMouse1 = true; + } + if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) { + eventMouse2 = true; + } + if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) { + eventMouse3 = true; + } + mouse1 = eventMouse1; + mouse2 = eventMouse2; + mouse3 = eventMouse3; + int x = screen.textColumn(mouse.getX()); + int y = screen.textRow(mouse.getY()); + + TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_MOTION, + x, y, x, y, mouse1, mouse2, mouse3, false, false); + + synchronized (eventQueue) { + eventQueue.add(mouseEvent); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseMoved(final MouseEvent mouse) { + int x = screen.textColumn(mouse.getX()); + int y = screen.textRow(mouse.getY()); + if ((x == oldMouseX) && (y == oldMouseY)) { + // Bail out, we've moved some pixels but not a whole text cell. + return; + } + oldMouseX = x; + oldMouseY = y; + + TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_MOTION, + x, y, x, y, mouse1, mouse2, mouse3, false, false); + + synchronized (eventQueue) { + eventQueue.add(mouseEvent); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseClicked(final MouseEvent mouse) { + // Ignore + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseEntered(final MouseEvent mouse) { + // Ignore + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseExited(final MouseEvent mouse) { + // Ignore + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mousePressed(final MouseEvent mouse) { + int modifiers = mouse.getModifiersEx(); + boolean eventMouse1 = false; + boolean eventMouse2 = false; + boolean eventMouse3 = false; + if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) { + eventMouse1 = true; + } + if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) { + eventMouse2 = true; + } + if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) { + eventMouse3 = true; + } + mouse1 = eventMouse1; + mouse2 = eventMouse2; + mouse3 = eventMouse3; + int x = screen.textColumn(mouse.getX()); + int y = screen.textRow(mouse.getY()); + + TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_DOWN, + x, y, x, y, mouse1, mouse2, mouse3, false, false); + + synchronized (eventQueue) { + eventQueue.add(mouseEvent); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseReleased(final MouseEvent mouse) { + int modifiers = mouse.getModifiersEx(); + boolean eventMouse1 = false; + boolean eventMouse2 = false; + boolean eventMouse3 = false; + if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) { + eventMouse1 = true; + } + if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) { + eventMouse2 = true; + } + if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) { + eventMouse3 = true; + } + if (mouse1) { + mouse1 = false; + eventMouse1 = true; + } + if (mouse2) { + mouse2 = false; + eventMouse2 = true; + } + if (mouse3) { + mouse3 = false; + eventMouse3 = true; + } + int x = screen.textColumn(mouse.getX()); + int y = screen.textRow(mouse.getY()); + + TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_UP, + x, y, x, y, eventMouse1, eventMouse2, eventMouse3, false, false); + + synchronized (eventQueue) { + eventQueue.add(mouseEvent); + } + synchronized (listener) { + listener.notifyAll(); + } + } + + /** + * Pass mouse events into the event queue. + * + * @param mouse mouse event received + */ + @Override + public void mouseWheelMoved(final MouseWheelEvent mouse) { + int modifiers = mouse.getModifiersEx(); + boolean eventMouse1 = false; + boolean eventMouse2 = false; + boolean eventMouse3 = false; + boolean mouseWheelUp = false; + boolean mouseWheelDown = false; + if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) { + eventMouse1 = true; + } + if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) { + eventMouse2 = true; + } + if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) { + eventMouse3 = true; + } + mouse1 = eventMouse1; + mouse2 = eventMouse2; + mouse3 = eventMouse3; + int x = screen.textColumn(mouse.getX()); + int y = screen.textRow(mouse.getY()); + if (mouse.getWheelRotation() > 0) { + mouseWheelDown = true; + } + if (mouse.getWheelRotation() < 0) { + mouseWheelUp = true; + } + + TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_DOWN, + x, y, x, y, mouse1, mouse2, mouse3, mouseWheelUp, mouseWheelDown); + + synchronized (eventQueue) { + eventQueue.add(mouseEvent); + } + synchronized (listener) { + listener.notifyAll(); + } } }