2 * Jexer - Java Text User Interface
4 * License: LGPLv3 or later
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
10 * Copyright (C) 2015 Kevin Lamonte
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
33 import java
.awt
.event
.ComponentEvent
;
34 import java
.awt
.event
.ComponentListener
;
35 import java
.awt
.event
.KeyEvent
;
36 import java
.awt
.event
.KeyListener
;
37 import java
.awt
.event
.MouseEvent
;
38 import java
.awt
.event
.MouseListener
;
39 import java
.awt
.event
.MouseMotionListener
;
40 import java
.awt
.event
.MouseWheelEvent
;
41 import java
.awt
.event
.MouseWheelListener
;
42 import java
.awt
.event
.WindowEvent
;
43 import java
.awt
.event
.WindowListener
;
44 import java
.util
.List
;
45 import java
.util
.LinkedList
;
47 import jexer
.TKeypress
;
48 import jexer
.event
.TCommandEvent
;
49 import jexer
.event
.TInputEvent
;
50 import jexer
.event
.TKeypressEvent
;
51 import jexer
.event
.TMouseEvent
;
52 import jexer
.event
.TResizeEvent
;
53 import jexer
.session
.SessionInfo
;
54 import jexer
.session
.AWTSessionInfo
;
55 import static jexer
.TCommand
.*;
56 import static jexer
.TKeypress
.*;
59 * This class reads keystrokes and mouse events from an AWT Frame.
61 public final class AWTTerminal
implements ComponentListener
, KeyListener
,
62 MouseListener
, MouseMotionListener
,
63 MouseWheelListener
, WindowListener
{
68 private AWTScreen screen
;
71 * The session information.
73 private AWTSessionInfo sessionInfo
;
76 * Getter for sessionInfo.
78 * @return the SessionInfo
80 public SessionInfo
getSessionInfo() {
85 * The event queue, filled up by a thread reading on input.
87 private List
<TInputEvent
> eventQueue
;
92 private Thread readerThread
;
95 * true if mouse1 was down. Used to report mouse1 on the release event.
97 private boolean mouse1
= false;
100 * true if mouse2 was down. Used to report mouse2 on the release event.
102 private boolean mouse2
= false;
105 * true if mouse3 was down. Used to report mouse3 on the release event.
107 private boolean mouse3
= false;
110 * Check if there are events in the queue.
112 * @return if true, getEvents() has something to return to the backend
114 public boolean hasEvents() {
115 synchronized (eventQueue
) {
116 return (eventQueue
.size() > 0);
121 * Constructor sets up state for getEvent().
123 * @param screen the top-level AWT frame
125 public AWTTerminal(final AWTScreen screen
) {
126 this.screen
= screen
;
130 sessionInfo
= screen
.getSessionInfo();
131 eventQueue
= new LinkedList
<TInputEvent
>();
133 screen
.frame
.addKeyListener(this);
134 screen
.frame
.addWindowListener(this);
135 screen
.frame
.addComponentListener(this);
136 screen
.frame
.addMouseListener(this);
137 screen
.frame
.addMouseMotionListener(this);
138 screen
.frame
.addMouseWheelListener(this);
142 * Restore terminal to normal state.
144 public void shutdown() {
145 // System.err.println("=== shutdown() ==="); System.err.flush();
146 screen
.frame
.dispose();
150 * Return any events in the IO queue.
152 * @param queue list to append new events to
154 public void getEvents(final List
<TInputEvent
> queue
) {
155 synchronized (eventQueue
) {
156 if (eventQueue
.size() > 0) {
157 synchronized (queue
) {
158 queue
.addAll(eventQueue
);
166 * Return any events in the IO queue due to timeout.
168 * @param queue list to append new events to
170 public void getIdleEvents(final List
<TInputEvent
> queue
) {
172 // Insert any polling action here...
174 // Return any events that showed up
175 synchronized (eventQueue
) {
176 if (eventQueue
.size() > 0) {
177 synchronized (queue
) {
178 queue
.addAll(eventQueue
);
186 * Pass AWT keystrokes into the event queue.
188 * @param key keystroke received
191 public void keyReleased(final KeyEvent key
) {
192 // Ignore release events
196 * Pass AWT keystrokes into the event queue.
198 * @param key keystroke received
201 public void keyTyped(final KeyEvent key
) {
202 // Ignore typed events
206 * Pass AWT keystrokes into the event queue.
208 * @param key keystroke received
211 public void keyPressed(final KeyEvent key
) {
213 boolean shift
= false;
214 boolean ctrl
= false;
216 boolean isKey
= false;
218 if (key
.isActionKey()) {
221 ch
= key
.getKeyChar();
223 alt
= key
.isAltDown();
224 ctrl
= key
.isControlDown();
225 shift
= key
.isShiftDown();
228 System.err.printf("AWT Key: %s\n", key);
229 System.err.printf(" isKey: %s\n", isKey);
230 System.err.printf(" alt: %s\n", alt);
231 System.err.printf(" ctrl: %s\n", ctrl);
232 System.err.printf(" shift: %s\n", shift);
233 System.err.printf(" ch: %s\n", ch);
236 // Special case: not return the bare modifier presses
237 switch (key
.getKeyCode()) {
238 case KeyEvent
.VK_ALT
:
240 case KeyEvent
.VK_ALT_GRAPH
:
242 case KeyEvent
.VK_CONTROL
:
244 case KeyEvent
.VK_SHIFT
:
246 case KeyEvent
.VK_META
:
252 TKeypress keypress
= null;
254 switch (key
.getKeyCode()) {
256 keypress
= new TKeypress(true, TKeypress
.F1
, ' ',
260 keypress
= new TKeypress(true, TKeypress
.F2
, ' ',
264 keypress
= new TKeypress(true, TKeypress
.F3
, ' ',
268 keypress
= new TKeypress(true, TKeypress
.F4
, ' ',
272 keypress
= new TKeypress(true, TKeypress
.F5
, ' ',
276 keypress
= new TKeypress(true, TKeypress
.F6
, ' ',
280 keypress
= new TKeypress(true, TKeypress
.F7
, ' ',
284 keypress
= new TKeypress(true, TKeypress
.F8
, ' ',
288 keypress
= new TKeypress(true, TKeypress
.F9
, ' ',
291 case KeyEvent
.VK_F10
:
292 keypress
= new TKeypress(true, TKeypress
.F10
, ' ',
295 case KeyEvent
.VK_F11
:
296 keypress
= new TKeypress(true, TKeypress
.F11
, ' ',
299 case KeyEvent
.VK_F12
:
300 keypress
= new TKeypress(true, TKeypress
.F12
, ' ',
303 case KeyEvent
.VK_HOME
:
304 keypress
= new TKeypress(true, TKeypress
.HOME
, ' ',
307 case KeyEvent
.VK_END
:
308 keypress
= new TKeypress(true, TKeypress
.END
, ' ',
311 case KeyEvent
.VK_PAGE_UP
:
312 keypress
= new TKeypress(true, TKeypress
.PGUP
, ' ',
315 case KeyEvent
.VK_PAGE_DOWN
:
316 keypress
= new TKeypress(true, TKeypress
.PGDN
, ' ',
319 case KeyEvent
.VK_INSERT
:
320 keypress
= new TKeypress(true, TKeypress
.INS
, ' ',
323 case KeyEvent
.VK_DELETE
:
324 keypress
= new TKeypress(true, TKeypress
.DEL
, ' ',
327 case KeyEvent
.VK_RIGHT
:
328 keypress
= new TKeypress(true, TKeypress
.RIGHT
, ' ',
331 case KeyEvent
.VK_LEFT
:
332 keypress
= new TKeypress(true, TKeypress
.LEFT
, ' ',
336 keypress
= new TKeypress(true, TKeypress
.UP
, ' ',
339 case KeyEvent
.VK_DOWN
:
340 keypress
= new TKeypress(true, TKeypress
.DOWN
, ' ',
343 case KeyEvent
.VK_TAB
:
344 // Special case: distinguish TAB vs BTAB
346 keypress
= kbShiftTab
;
351 case KeyEvent
.VK_ENTER
:
352 keypress
= new TKeypress(true, TKeypress
.ENTER
, ' ',
355 case KeyEvent
.VK_ESCAPE
:
356 keypress
= new TKeypress(true, TKeypress
.ESC
, ' ',
359 case KeyEvent
.VK_BACK_SPACE
:
360 // Special case: return it as kbBackspace (Ctrl-H)
361 keypress
= new TKeypress(false, 0, 'H', false, true, false);
364 // Unsupported, ignore
369 if (keypress
== null) {
372 keypress
= kbBackspace
;
387 if (!alt
&& ctrl
&& !shift
) {
388 ch
= key
.getKeyText(key
.getKeyCode()).charAt(0);
390 // Not a special key, put it together
391 keypress
= new TKeypress(false, 0, ch
, alt
, ctrl
, shift
);
395 // Save it and we are done.
396 synchronized (eventQueue
) {
397 eventQueue
.add(new TKeypressEvent(keypress
));
399 // Wake up the backend
400 synchronized (this) {
406 * Pass window events into the event queue.
408 * @param event window event received
411 public void windowActivated(final WindowEvent event
) {
416 * Pass window events into the event queue.
418 * @param event window event received
421 public void windowClosed(final WindowEvent event
) {
426 * Pass window events into the event queue.
428 * @param event window event received
431 public void windowClosing(final WindowEvent event
) {
432 // Drop a cmAbort and walk away
433 synchronized (eventQueue
) {
434 eventQueue
.add(new TCommandEvent(cmAbort
));
436 // Wake up the backend
437 synchronized (this) {
443 * Pass window events into the event queue.
445 * @param event window event received
448 public void windowDeactivated(final WindowEvent event
) {
453 * Pass window events into the event queue.
455 * @param event window event received
458 public void windowDeiconified(final WindowEvent event
) {
463 * Pass window events into the event queue.
465 * @param event window event received
468 public void windowIconified(final WindowEvent event
) {
473 * Pass window events into the event queue.
475 * @param event window event received
478 public void windowOpened(final WindowEvent event
) {
483 * Pass component events into the event queue.
485 * @param event component event received
488 public void componentHidden(final ComponentEvent event
) {
493 * Pass component events into the event queue.
495 * @param event component event received
498 public void componentShown(final ComponentEvent event
) {
503 * Pass component events into the event queue.
505 * @param event component event received
508 public void componentMoved(final ComponentEvent event
) {
513 * Pass component events into the event queue.
515 * @param event component event received
518 public void componentResized(final ComponentEvent event
) {
519 // Drop a new TResizeEvent into the queue
520 sessionInfo
.queryWindowSize();
521 synchronized (eventQueue
) {
522 TResizeEvent windowResize
= new TResizeEvent(TResizeEvent
.Type
.SCREEN
,
523 sessionInfo
.getWindowWidth(), sessionInfo
.getWindowHeight());
524 eventQueue
.add(windowResize
);
526 // Wake up the backend
527 synchronized (this) {
533 * Pass mouse events into the event queue.
535 * @param mouse mouse event received
538 public void mouseDragged(final MouseEvent mouse
) {
539 int modifiers
= mouse
.getModifiersEx();
540 boolean eventMouse1
= false;
541 boolean eventMouse2
= false;
542 boolean eventMouse3
= false;
543 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
546 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
549 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
552 mouse1
= eventMouse1
;
553 mouse2
= eventMouse2
;
554 mouse3
= eventMouse3
;
555 int x
= screen
.textColumn(mouse
.getX());
556 int y
= screen
.textRow(mouse
.getY());
558 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_MOTION
,
559 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, false, false);
561 synchronized (eventQueue
) {
562 eventQueue
.add(mouseEvent
);
564 // Wake up the backend
565 synchronized (this) {
571 * Pass mouse events into the event queue.
573 * @param mouse mouse event received
576 public void mouseMoved(final MouseEvent mouse
) {
577 int x
= screen
.textColumn(mouse
.getX());
578 int y
= screen
.textRow(mouse
.getY());
579 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_MOTION
,
580 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, false, false);
582 synchronized (eventQueue
) {
583 eventQueue
.add(mouseEvent
);
585 // Wake up the backend
586 synchronized (this) {
592 * Pass mouse events into the event queue.
594 * @param mouse mouse event received
597 public void mouseClicked(final MouseEvent mouse
) {
602 * Pass mouse events into the event queue.
604 * @param mouse mouse event received
607 public void mouseEntered(final MouseEvent mouse
) {
612 * Pass mouse events into the event queue.
614 * @param mouse mouse event received
617 public void mouseExited(final MouseEvent mouse
) {
622 * Pass mouse events into the event queue.
624 * @param mouse mouse event received
627 public void mousePressed(final MouseEvent mouse
) {
628 int modifiers
= mouse
.getModifiersEx();
629 boolean eventMouse1
= false;
630 boolean eventMouse2
= false;
631 boolean eventMouse3
= false;
632 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
635 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
638 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
641 mouse1
= eventMouse1
;
642 mouse2
= eventMouse2
;
643 mouse3
= eventMouse3
;
644 int x
= screen
.textColumn(mouse
.getX());
645 int y
= screen
.textRow(mouse
.getY());
647 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_DOWN
,
648 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, false, false);
650 synchronized (eventQueue
) {
651 eventQueue
.add(mouseEvent
);
653 // Wake up the backend
654 synchronized (this) {
660 * Pass mouse events into the event queue.
662 * @param mouse mouse event received
665 public void mouseReleased(final MouseEvent mouse
) {
666 int modifiers
= mouse
.getModifiersEx();
667 boolean eventMouse1
= false;
668 boolean eventMouse2
= false;
669 boolean eventMouse3
= false;
670 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
673 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
676 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
691 int x
= screen
.textColumn(mouse
.getX());
692 int y
= screen
.textRow(mouse
.getY());
694 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_UP
,
695 x
, y
, x
, y
, eventMouse1
, eventMouse2
, eventMouse3
, false, false);
697 synchronized (eventQueue
) {
698 eventQueue
.add(mouseEvent
);
700 // Wake up the backend
701 synchronized (this) {
707 * Pass mouse events into the event queue.
709 * @param mouse mouse event received
712 public void mouseWheelMoved(final MouseWheelEvent mouse
) {
713 int modifiers
= mouse
.getModifiersEx();
714 boolean eventMouse1
= false;
715 boolean eventMouse2
= false;
716 boolean eventMouse3
= false;
717 boolean mouseWheelUp
= false;
718 boolean mouseWheelDown
= false;
719 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
722 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
725 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
728 mouse1
= eventMouse1
;
729 mouse2
= eventMouse2
;
730 mouse3
= eventMouse3
;
731 int x
= screen
.textColumn(mouse
.getX());
732 int y
= screen
.textRow(mouse
.getY());
733 if (mouse
.getWheelRotation() > 0) {
734 mouseWheelDown
= true;
736 if (mouse
.getWheelRotation() < 0) {
740 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_DOWN
,
741 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, mouseWheelUp
, mouseWheelDown
);
743 synchronized (eventQueue
) {
744 eventQueue
.add(mouseEvent
);
746 // Wake up the backend
747 synchronized (this) {