fix eclipse warnings
[nikiroo-utils.git] / src / jexer / io / AWTTerminal.java
CommitLineData
1ac2ccb1
KL
1/**
2 * Jexer - Java Text User Interface
3 *
4 * License: LGPLv3 or later
5 *
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.
9 *
10 * Copyright (C) 2015 Kevin Lamonte
11 *
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.
16 *
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.
21 *
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
26 * 02110-1301 USA
27 *
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 * @version 1
30 */
31package jexer.io;
32
30bd4abd
KL
33import java.awt.event.ComponentEvent;
34import java.awt.event.ComponentListener;
84614868 35import java.awt.event.KeyEvent;
30bd4abd
KL
36import java.awt.event.KeyListener;
37import java.awt.event.MouseEvent;
84614868 38import java.awt.event.MouseListener;
30bd4abd
KL
39import java.awt.event.MouseMotionListener;
40import java.awt.event.MouseWheelEvent;
41import java.awt.event.MouseWheelListener;
42import java.awt.event.WindowEvent;
84614868 43import java.awt.event.WindowListener;
1ac2ccb1
KL
44import java.util.List;
45import java.util.LinkedList;
46
47import jexer.TKeypress;
30bd4abd 48import jexer.event.TCommandEvent;
1ac2ccb1
KL
49import jexer.event.TInputEvent;
50import jexer.event.TKeypressEvent;
51import jexer.event.TMouseEvent;
52import jexer.event.TResizeEvent;
53import jexer.session.SessionInfo;
30bd4abd
KL
54import jexer.session.AWTSessionInfo;
55import static jexer.TCommand.*;
1ac2ccb1
KL
56import static jexer.TKeypress.*;
57
58/**
59 * This class reads keystrokes and mouse events from an AWT Frame.
60 */
30bd4abd
KL
61public final class AWTTerminal implements ComponentListener, KeyListener,
62 MouseListener, MouseMotionListener,
63 MouseWheelListener, WindowListener {
84614868
KL
64
65 /**
66 * The backend Screen.
67 */
68 private AWTScreen screen;
1ac2ccb1
KL
69
70 /**
71 * The session information.
72 */
30bd4abd 73 private AWTSessionInfo sessionInfo;
1ac2ccb1
KL
74
75 /**
76 * Getter for sessionInfo.
77 *
78 * @return the SessionInfo
79 */
80 public SessionInfo getSessionInfo() {
81 return sessionInfo;
82 }
83
92554d64
KL
84 /**
85 * The listening object that run() wakes up on new input.
86 */
87 private Object listener;
88
1ac2ccb1
KL
89 /**
90 * The event queue, filled up by a thread reading on input.
91 */
92 private List<TInputEvent> eventQueue;
93
a90d3119
KL
94 /**
95 * The last reported mouse X position.
96 */
97 private int oldMouseX = -1;
98
99 /**
100 * The last reported mouse Y position.
101 */
102 private int oldMouseY = -1;
103
1ac2ccb1
KL
104 /**
105 * true if mouse1 was down. Used to report mouse1 on the release event.
106 */
30bd4abd 107 private boolean mouse1 = false;
1ac2ccb1
KL
108
109 /**
110 * true if mouse2 was down. Used to report mouse2 on the release event.
111 */
30bd4abd 112 private boolean mouse2 = false;
1ac2ccb1
KL
113
114 /**
115 * true if mouse3 was down. Used to report mouse3 on the release event.
116 */
30bd4abd 117 private boolean mouse3 = false;
1ac2ccb1
KL
118
119 /**
120 * Check if there are events in the queue.
121 *
122 * @return if true, getEvents() has something to return to the backend
123 */
124 public boolean hasEvents() {
125 synchronized (eventQueue) {
126 return (eventQueue.size() > 0);
127 }
128 }
129
130 /**
131 * Constructor sets up state for getEvent().
132 *
92554d64
KL
133 * @param listener the object this backend needs to wake up when new
134 * input comes in
84614868 135 * @param screen the top-level AWT frame
1ac2ccb1 136 */
92554d64
KL
137 public AWTTerminal(final Object listener, final AWTScreen screen) {
138 this.listener = listener;
84614868 139 this.screen = screen;
1ac2ccb1
KL
140 mouse1 = false;
141 mouse2 = false;
142 mouse3 = false;
30bd4abd 143 sessionInfo = screen.getSessionInfo();
1ac2ccb1 144 eventQueue = new LinkedList<TInputEvent>();
84614868
KL
145
146 screen.frame.addKeyListener(this);
30bd4abd
KL
147 screen.frame.addWindowListener(this);
148 screen.frame.addComponentListener(this);
149 screen.frame.addMouseListener(this);
150 screen.frame.addMouseMotionListener(this);
151 screen.frame.addMouseWheelListener(this);
1ac2ccb1
KL
152 }
153
154 /**
155 * Restore terminal to normal state.
156 */
157 public void shutdown() {
158 // System.err.println("=== shutdown() ==="); System.err.flush();
84614868 159 screen.frame.dispose();
1ac2ccb1
KL
160 }
161
162 /**
163 * Return any events in the IO queue.
164 *
165 * @param queue list to append new events to
166 */
167 public void getEvents(final List<TInputEvent> queue) {
168 synchronized (eventQueue) {
169 if (eventQueue.size() > 0) {
170 synchronized (queue) {
171 queue.addAll(eventQueue);
172 }
173 eventQueue.clear();
174 }
175 }
176 }
177
84614868
KL
178 /**
179 * Pass AWT keystrokes into the event queue.
180 *
181 * @param key keystroke received
182 */
183 @Override
184 public void keyReleased(final KeyEvent key) {
185 // Ignore release events
186 }
187
188 /**
189 * Pass AWT keystrokes into the event queue.
190 *
191 * @param key keystroke received
192 */
193 @Override
194 public void keyTyped(final KeyEvent key) {
195 // Ignore typed events
196 }
197
198 /**
199 * Pass AWT keystrokes into the event queue.
200 *
201 * @param key keystroke received
202 */
203 @Override
204 public void keyPressed(final KeyEvent key) {
205 boolean alt = false;
206 boolean shift = false;
207 boolean ctrl = false;
208 char ch = ' ';
209 boolean isKey = false;
84614868
KL
210 if (key.isActionKey()) {
211 isKey = true;
212 } else {
213 ch = key.getKeyChar();
214 }
215 alt = key.isAltDown();
216 ctrl = key.isControlDown();
217 shift = key.isShiftDown();
218
219 /*
220 System.err.printf("AWT Key: %s\n", key);
221 System.err.printf(" isKey: %s\n", isKey);
222 System.err.printf(" alt: %s\n", alt);
223 System.err.printf(" ctrl: %s\n", ctrl);
224 System.err.printf(" shift: %s\n", shift);
225 System.err.printf(" ch: %s\n", ch);
bd8d51fa 226 */
84614868
KL
227
228 // Special case: not return the bare modifier presses
229 switch (key.getKeyCode()) {
230 case KeyEvent.VK_ALT:
231 return;
232 case KeyEvent.VK_ALT_GRAPH:
233 return;
234 case KeyEvent.VK_CONTROL:
235 return;
236 case KeyEvent.VK_SHIFT:
237 return;
238 case KeyEvent.VK_META:
239 return;
240 default:
241 break;
242 }
243
244 TKeypress keypress = null;
245 if (isKey) {
246 switch (key.getKeyCode()) {
247 case KeyEvent.VK_F1:
248 keypress = new TKeypress(true, TKeypress.F1, ' ',
249 alt, ctrl, shift);
250 break;
251 case KeyEvent.VK_F2:
252 keypress = new TKeypress(true, TKeypress.F2, ' ',
253 alt, ctrl, shift);
254 break;
255 case KeyEvent.VK_F3:
256 keypress = new TKeypress(true, TKeypress.F3, ' ',
257 alt, ctrl, shift);
258 break;
259 case KeyEvent.VK_F4:
260 keypress = new TKeypress(true, TKeypress.F4, ' ',
261 alt, ctrl, shift);
262 break;
263 case KeyEvent.VK_F5:
264 keypress = new TKeypress(true, TKeypress.F5, ' ',
265 alt, ctrl, shift);
266 break;
267 case KeyEvent.VK_F6:
268 keypress = new TKeypress(true, TKeypress.F6, ' ',
269 alt, ctrl, shift);
270 break;
271 case KeyEvent.VK_F7:
272 keypress = new TKeypress(true, TKeypress.F7, ' ',
273 alt, ctrl, shift);
274 break;
275 case KeyEvent.VK_F8:
276 keypress = new TKeypress(true, TKeypress.F8, ' ',
277 alt, ctrl, shift);
278 break;
279 case KeyEvent.VK_F9:
280 keypress = new TKeypress(true, TKeypress.F9, ' ',
281 alt, ctrl, shift);
282 break;
283 case KeyEvent.VK_F10:
284 keypress = new TKeypress(true, TKeypress.F10, ' ',
285 alt, ctrl, shift);
286 break;
287 case KeyEvent.VK_F11:
288 keypress = new TKeypress(true, TKeypress.F11, ' ',
289 alt, ctrl, shift);
290 break;
291 case KeyEvent.VK_F12:
292 keypress = new TKeypress(true, TKeypress.F12, ' ',
293 alt, ctrl, shift);
294 break;
295 case KeyEvent.VK_HOME:
296 keypress = new TKeypress(true, TKeypress.HOME, ' ',
297 alt, ctrl, shift);
298 break;
299 case KeyEvent.VK_END:
300 keypress = new TKeypress(true, TKeypress.END, ' ',
301 alt, ctrl, shift);
302 break;
303 case KeyEvent.VK_PAGE_UP:
304 keypress = new TKeypress(true, TKeypress.PGUP, ' ',
305 alt, ctrl, shift);
306 break;
307 case KeyEvent.VK_PAGE_DOWN:
308 keypress = new TKeypress(true, TKeypress.PGDN, ' ',
309 alt, ctrl, shift);
310 break;
311 case KeyEvent.VK_INSERT:
312 keypress = new TKeypress(true, TKeypress.INS, ' ',
313 alt, ctrl, shift);
314 break;
315 case KeyEvent.VK_DELETE:
30bd4abd 316 keypress = new TKeypress(true, TKeypress.DEL, ' ',
84614868
KL
317 alt, ctrl, shift);
318 break;
319 case KeyEvent.VK_RIGHT:
320 keypress = new TKeypress(true, TKeypress.RIGHT, ' ',
321 alt, ctrl, shift);
322 break;
323 case KeyEvent.VK_LEFT:
324 keypress = new TKeypress(true, TKeypress.LEFT, ' ',
325 alt, ctrl, shift);
326 break;
327 case KeyEvent.VK_UP:
328 keypress = new TKeypress(true, TKeypress.UP, ' ',
329 alt, ctrl, shift);
330 break;
331 case KeyEvent.VK_DOWN:
332 keypress = new TKeypress(true, TKeypress.DOWN, ' ',
333 alt, ctrl, shift);
334 break;
335 case KeyEvent.VK_TAB:
336 // Special case: distinguish TAB vs BTAB
337 if (shift) {
338 keypress = kbShiftTab;
339 } else {
340 keypress = kbTab;
341 }
342 break;
343 case KeyEvent.VK_ENTER:
344 keypress = new TKeypress(true, TKeypress.ENTER, ' ',
345 alt, ctrl, shift);
346 break;
347 case KeyEvent.VK_ESCAPE:
348 keypress = new TKeypress(true, TKeypress.ESC, ' ',
349 alt, ctrl, shift);
350 break;
351 case KeyEvent.VK_BACK_SPACE:
352 // Special case: return it as kbBackspace (Ctrl-H)
353 keypress = new TKeypress(false, 0, 'H', false, true, false);
354 break;
355 default:
356 // Unsupported, ignore
357 return;
358 }
359 }
360
361 if (keypress == null) {
362 switch (ch) {
363 case 0x08:
364 keypress = kbBackspace;
365 break;
366 case 0x0A:
367 keypress = kbEnter;
368 break;
87a17f3c
KL
369 case 0x1B:
370 keypress = kbEsc;
371 break;
84614868
KL
372 case 0x0D:
373 keypress = kbEnter;
374 break;
bd8d51fa
KL
375 case 0x09:
376 keypress = kbTab;
377 break;
30bd4abd
KL
378 case 0x7F:
379 keypress = kbDel;
380 break;
84614868
KL
381 default:
382 if (!alt && ctrl && !shift) {
cf9af8df 383 ch = KeyEvent.getKeyText(key.getKeyCode()).charAt(0);
84614868
KL
384 }
385 // Not a special key, put it together
386 keypress = new TKeypress(false, 0, ch, alt, ctrl, shift);
387 }
388 }
389
390 // Save it and we are done.
391 synchronized (eventQueue) {
392 eventQueue.add(new TKeypressEvent(keypress));
393 }
92554d64
KL
394 synchronized (listener) {
395 listener.notifyAll();
30bd4abd
KL
396 }
397 }
398
399 /**
400 * Pass window events into the event queue.
401 *
402 * @param event window event received
403 */
404 @Override
405 public void windowActivated(final WindowEvent event) {
bd8d51fa
KL
406 // Force a total repaint
407 synchronized (screen) {
408 screen.clearPhysical();
409 }
30bd4abd
KL
410 }
411
412 /**
413 * Pass window events into the event queue.
414 *
415 * @param event window event received
416 */
417 @Override
418 public void windowClosed(final WindowEvent event) {
419 // Ignore
420 }
421
422 /**
423 * Pass window events into the event queue.
424 *
425 * @param event window event received
426 */
427 @Override
428 public void windowClosing(final WindowEvent event) {
429 // Drop a cmAbort and walk away
430 synchronized (eventQueue) {
431 eventQueue.add(new TCommandEvent(cmAbort));
432 }
92554d64
KL
433 synchronized (listener) {
434 listener.notifyAll();
30bd4abd
KL
435 }
436 }
437
438 /**
439 * Pass window events into the event queue.
440 *
441 * @param event window event received
442 */
443 @Override
444 public void windowDeactivated(final WindowEvent event) {
445 // Ignore
446 }
447
448 /**
449 * Pass window events into the event queue.
450 *
451 * @param event window event received
452 */
453 @Override
454 public void windowDeiconified(final WindowEvent event) {
455 // Ignore
456 }
457
458 /**
459 * Pass window events into the event queue.
460 *
461 * @param event window event received
462 */
463 @Override
464 public void windowIconified(final WindowEvent event) {
465 // Ignore
466 }
467
468 /**
469 * Pass window events into the event queue.
470 *
471 * @param event window event received
472 */
473 @Override
474 public void windowOpened(final WindowEvent event) {
475 // Ignore
476 }
477
478 /**
479 * Pass component events into the event queue.
480 *
481 * @param event component event received
482 */
483 @Override
484 public void componentHidden(final ComponentEvent event) {
485 // Ignore
486 }
487
488 /**
489 * Pass component events into the event queue.
490 *
491 * @param event component event received
492 */
493 @Override
494 public void componentShown(final ComponentEvent event) {
495 // Ignore
496 }
497
498 /**
499 * Pass component events into the event queue.
500 *
501 * @param event component event received
502 */
503 @Override
504 public void componentMoved(final ComponentEvent event) {
505 // Ignore
506 }
507
508 /**
509 * Pass component events into the event queue.
510 *
511 * @param event component event received
512 */
513 @Override
514 public void componentResized(final ComponentEvent event) {
515 // Drop a new TResizeEvent into the queue
516 sessionInfo.queryWindowSize();
517 synchronized (eventQueue) {
518 TResizeEvent windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
519 sessionInfo.getWindowWidth(), sessionInfo.getWindowHeight());
520 eventQueue.add(windowResize);
521 }
92554d64
KL
522 synchronized (listener) {
523 listener.notifyAll();
30bd4abd
KL
524 }
525 }
526
527 /**
528 * Pass mouse events into the event queue.
529 *
530 * @param mouse mouse event received
531 */
532 @Override
533 public void mouseDragged(final MouseEvent mouse) {
534 int modifiers = mouse.getModifiersEx();
535 boolean eventMouse1 = false;
536 boolean eventMouse2 = false;
537 boolean eventMouse3 = false;
538 if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) {
539 eventMouse1 = true;
540 }
541 if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) {
542 eventMouse2 = true;
543 }
544 if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) {
545 eventMouse3 = true;
546 }
547 mouse1 = eventMouse1;
548 mouse2 = eventMouse2;
549 mouse3 = eventMouse3;
87a17f3c
KL
550 int x = screen.textColumn(mouse.getX());
551 int y = screen.textRow(mouse.getY());
30bd4abd
KL
552
553 TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_MOTION,
554 x, y, x, y, mouse1, mouse2, mouse3, false, false);
555
556 synchronized (eventQueue) {
557 eventQueue.add(mouseEvent);
558 }
92554d64
KL
559 synchronized (listener) {
560 listener.notifyAll();
30bd4abd
KL
561 }
562 }
563
564 /**
565 * Pass mouse events into the event queue.
566 *
567 * @param mouse mouse event received
568 */
569 @Override
570 public void mouseMoved(final MouseEvent mouse) {
87a17f3c
KL
571 int x = screen.textColumn(mouse.getX());
572 int y = screen.textRow(mouse.getY());
a90d3119
KL
573 if ((x == oldMouseX) && (y == oldMouseY)) {
574 // Bail out, we've moved some pixels but not a whole text cell.
575 return;
576 }
577 oldMouseX = x;
578 oldMouseY = y;
579
30bd4abd
KL
580 TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_MOTION,
581 x, y, x, y, mouse1, mouse2, mouse3, false, false);
582
583 synchronized (eventQueue) {
584 eventQueue.add(mouseEvent);
585 }
92554d64
KL
586 synchronized (listener) {
587 listener.notifyAll();
30bd4abd 588 }
84614868 589 }
30bd4abd
KL
590
591 /**
592 * Pass mouse events into the event queue.
593 *
594 * @param mouse mouse event received
595 */
596 @Override
597 public void mouseClicked(final MouseEvent mouse) {
598 // Ignore
599 }
600
601 /**
602 * Pass mouse events into the event queue.
603 *
604 * @param mouse mouse event received
605 */
606 @Override
607 public void mouseEntered(final MouseEvent mouse) {
608 // Ignore
609 }
610
611 /**
612 * Pass mouse events into the event queue.
613 *
614 * @param mouse mouse event received
615 */
616 @Override
617 public void mouseExited(final MouseEvent mouse) {
618 // Ignore
619 }
620
621 /**
622 * Pass mouse events into the event queue.
623 *
624 * @param mouse mouse event received
625 */
626 @Override
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) {
633 eventMouse1 = true;
634 }
635 if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) {
636 eventMouse2 = true;
637 }
638 if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) {
639 eventMouse3 = true;
640 }
641 mouse1 = eventMouse1;
642 mouse2 = eventMouse2;
643 mouse3 = eventMouse3;
87a17f3c
KL
644 int x = screen.textColumn(mouse.getX());
645 int y = screen.textRow(mouse.getY());
30bd4abd
KL
646
647 TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_DOWN,
648 x, y, x, y, mouse1, mouse2, mouse3, false, false);
649
650 synchronized (eventQueue) {
651 eventQueue.add(mouseEvent);
652 }
92554d64
KL
653 synchronized (listener) {
654 listener.notifyAll();
30bd4abd
KL
655 }
656 }
657
658 /**
659 * Pass mouse events into the event queue.
660 *
661 * @param mouse mouse event received
662 */
663 @Override
664 public void mouseReleased(final MouseEvent mouse) {
665 int modifiers = mouse.getModifiersEx();
666 boolean eventMouse1 = false;
667 boolean eventMouse2 = false;
668 boolean eventMouse3 = false;
669 if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) {
670 eventMouse1 = true;
671 }
672 if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) {
673 eventMouse2 = true;
674 }
675 if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) {
676 eventMouse3 = true;
677 }
678 if (mouse1) {
679 mouse1 = false;
680 eventMouse1 = true;
681 }
682 if (mouse2) {
683 mouse2 = false;
684 eventMouse2 = true;
685 }
686 if (mouse3) {
687 mouse3 = false;
688 eventMouse3 = true;
689 }
87a17f3c
KL
690 int x = screen.textColumn(mouse.getX());
691 int y = screen.textRow(mouse.getY());
30bd4abd
KL
692
693 TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_UP,
694 x, y, x, y, eventMouse1, eventMouse2, eventMouse3, false, false);
695
696 synchronized (eventQueue) {
697 eventQueue.add(mouseEvent);
698 }
92554d64
KL
699 synchronized (listener) {
700 listener.notifyAll();
30bd4abd
KL
701 }
702 }
703
704 /**
705 * Pass mouse events into the event queue.
706 *
707 * @param mouse mouse event received
708 */
709 @Override
710 public void mouseWheelMoved(final MouseWheelEvent mouse) {
711 int modifiers = mouse.getModifiersEx();
712 boolean eventMouse1 = false;
713 boolean eventMouse2 = false;
714 boolean eventMouse3 = false;
715 boolean mouseWheelUp = false;
716 boolean mouseWheelDown = false;
717 if ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) != 0) {
718 eventMouse1 = true;
719 }
720 if ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0) {
721 eventMouse2 = true;
722 }
723 if ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0) {
724 eventMouse3 = true;
725 }
726 mouse1 = eventMouse1;
727 mouse2 = eventMouse2;
728 mouse3 = eventMouse3;
87a17f3c
KL
729 int x = screen.textColumn(mouse.getX());
730 int y = screen.textRow(mouse.getY());
30bd4abd
KL
731 if (mouse.getWheelRotation() > 0) {
732 mouseWheelDown = true;
733 }
734 if (mouse.getWheelRotation() < 0) {
735 mouseWheelUp = true;
736 }
737
738 TMouseEvent mouseEvent = new TMouseEvent(TMouseEvent.Type.MOUSE_DOWN,
739 x, y, x, y, mouse1, mouse2, mouse3, mouseWheelUp, mouseWheelDown);
740
741 synchronized (eventQueue) {
742 eventQueue.add(mouseEvent);
743 }
92554d64
KL
744 synchronized (listener) {
745 listener.notifyAll();
30bd4abd
KL
746 }
747 }
748
1ac2ccb1 749}