2 package com.badlogic.gdx.backends.jglfw;
4 import static com.badlogic.jglfw.Glfw.*;
6 import com.badlogic.gdx.Input;
7 import com.badlogic.gdx.InputProcessor;
8 import com.badlogic.gdx.InputProcessorQueue;
9 import com.badlogic.jglfw.GlfwCallbackAdapter;
11 import java.awt.Color;
12 import java.awt.FlowLayout;
13 import java.awt.event.WindowEvent;
14 import java.awt.event.WindowFocusListener;
16 import javax.swing.JDialog;
17 import javax.swing.JLabel;
18 import javax.swing.JOptionPane;
19 import javax.swing.JPanel;
20 import javax.swing.JTextField;
21 import javax.swing.OverlayLayout;
22 import javax.swing.SwingUtilities;
23 import javax.swing.border.EmptyBorder;
24 import javax.swing.event.DocumentEvent;
25 import javax.swing.event.DocumentListener;
27 /** An implementation of the {@link Input} interface hooking GLFW panel for input.
29 * @author Nathan Sweet */
30 public class JglfwInput implements Input {
31 final JglfwApplication app;
32 final InputProcessorQueue processorQueue;
33 InputProcessor processor;
37 long currentEventTime;
39 public JglfwInput (final JglfwApplication app, boolean queueEvents) {
42 InputProcessor inputProcessor = new InputProcessor() {
43 private int mouseX, mouseY;
45 public boolean keyDown (int keycode) {
47 app.graphics.requestRendering();
48 return processor != null ? processor.keyDown(keycode) : false;
51 public boolean keyUp (int keycode) {
53 app.graphics.requestRendering();
54 return processor != null ? processor.keyUp(keycode) : false;
57 public boolean keyTyped (char character) {
58 app.graphics.requestRendering();
59 return processor != null ? processor.keyTyped(character) : false;
62 public boolean touchDown (int screenX, int screenY, int pointer, int button) {
64 app.graphics.requestRendering();
65 return processor != null ? processor.touchDown(screenX, screenY, pointer, button) : false;
68 public boolean touchUp (int screenX, int screenY, int pointer, int button) {
69 app.graphics.requestRendering();
70 return processor != null ? processor.touchUp(screenX, screenY, pointer, button) : false;
73 public boolean touchDragged (int screenX, int screenY, int pointer) {
74 deltaX = screenX - mouseX;
75 deltaY = screenY - mouseY;
78 app.graphics.requestRendering();
79 return processor != null ? processor.touchDragged(mouseX, mouseY, 0) : false;
82 public boolean mouseMoved (int screenX, int screenY) {
83 deltaX = screenX - mouseX;
84 deltaY = screenY - mouseX;
87 app.graphics.requestRendering();
88 return processor != null ? processor.mouseMoved(mouseX, mouseY) : false;
91 public boolean scrolled (int amount) {
92 app.graphics.requestRendering();
93 return processor != null ? processor.scrolled(amount) : false;
98 inputProcessor = processorQueue = new InputProcessorQueue(inputProcessor);
100 processorQueue = null;
102 app.getCallbacks().add(new GlfwInputProcessor(inputProcessor));
105 public void update () {
107 if (processorQueue != null)
108 processorQueue.drain(); // Main loop is handled elsewhere and events are queued.
110 currentEventTime = System.nanoTime();
111 glfwPollEvents(); // Use GLFW main loop to process events.
115 public float getAccelerometerX () {
119 public float getAccelerometerY () {
123 public float getAccelerometerZ () {
128 return glfwGetCursorPosX(app.graphics.window);
131 public int getX (int pointer) {
132 return pointer > 0 ? 0 : getX();
136 return glfwGetCursorPosY(app.graphics.window);
139 public int getY (int pointer) {
140 return pointer > 0 ? 0 : getY();
143 public int getDeltaX () {
147 public int getDeltaX (int pointer) {
148 return pointer > 0 ? 0 : deltaX;
151 public int getDeltaY () {
155 public int getDeltaY (int pointer) {
156 return pointer > 0 ? 0 : deltaY;
159 public boolean isTouched () {
160 return glfwGetMouseButton(app.graphics.window, 0) || glfwGetMouseButton(app.graphics.window, 1)
161 || glfwGetMouseButton(app.graphics.window, 2);
164 public boolean isTouched (int pointer) {
165 return pointer > 0 ? false : isTouched();
168 public boolean justTouched () {
172 public boolean isButtonPressed (int button) {
173 return glfwGetMouseButton(app.graphics.window, button);
176 public boolean isKeyPressed (int key) {
177 if (key == Input.Keys.ANY_KEY) return pressedKeys > 0;
178 if (key == Input.Keys.SYM) {
179 return glfwGetKey(app.graphics.window, getJglfwKeyCode(GLFW_KEY_LEFT_SUPER))
180 || glfwGetKey(app.graphics.window, getJglfwKeyCode(GLFW_KEY_RIGHT_SUPER));
182 return glfwGetKey(app.graphics.window, getJglfwKeyCode(key));
185 public void setOnscreenKeyboardVisible (boolean visible) {
188 public void vibrate (int milliseconds) {
191 public void vibrate (long[] pattern, int repeat) {
194 public void cancelVibrate () {
197 public float getAzimuth () {
201 public float getPitch () {
205 public float getRoll () {
209 public void getRotationMatrix (float[] matrix) {
212 public long getCurrentEventTime () {
213 return processorQueue != null ? processorQueue.getCurrentEventTime() : currentEventTime;
216 public void setCatchBackKey (boolean catchBack) {
219 public void setCatchMenuKey (boolean catchMenu) {
222 public void setInputProcessor (InputProcessor processor) {
223 this.processor = processor;
226 public InputProcessor getInputProcessor () {
230 public boolean isPeripheralAvailable (Peripheral peripheral) {
231 return peripheral == Peripheral.HardwareKeyboard;
234 public int getRotation () {
238 public Orientation getNativeOrientation () {
239 return Orientation.Landscape;
242 public void setCursorCatched (boolean captured) {
243 glfwSetInputMode(app.graphics.window, GLFW_CURSOR_MODE, captured ? GLFW_CURSOR_CAPTURED : GLFW_CURSOR_NORMAL);
246 public boolean isCursorCatched () {
247 return glfwGetInputMode(app.graphics.window, GLFW_CURSOR_MODE) == GLFW_CURSOR_CAPTURED;
250 public void setCursorPosition (int x, int y) {
251 glfwSetCursorPos(app.graphics.window, x, y);
254 public void getTextInput (final TextInputListener listener, final String title, final String text) {
255 SwingUtilities.invokeLater(new Runnable() {
257 final String output = JOptionPane.showInputDialog(null, title, text);
258 app.postRunnable(new Runnable() {
261 listener.input(output);
270 public void getPlaceholderTextInput (final TextInputListener listener, final String title, final String placeholder) {
271 SwingUtilities.invokeLater(new Runnable() {
273 JPanel panel = new JPanel(new FlowLayout());
275 JPanel textPanel = new JPanel() {
276 public boolean isOptimizedDrawingEnabled () {
280 textPanel.setLayout(new OverlayLayout(textPanel));
281 panel.add(textPanel);
283 final JTextField textField = new JTextField(20);
284 textField.setAlignmentX(0.0f);
285 textPanel.add(textField);
287 final JLabel placeholderLabel = new JLabel(placeholder);
288 placeholderLabel.setForeground(Color.GRAY);
289 placeholderLabel.setAlignmentX(0.0f);
290 textPanel.add(placeholderLabel, 0);
292 textField.getDocument().addDocumentListener(new DocumentListener() {
293 public void removeUpdate (DocumentEvent event) {
297 public void insertUpdate (DocumentEvent event) {
301 public void changedUpdate (DocumentEvent event) {
305 private void updated () {
306 placeholderLabel.setVisible(textField.getText().length() == 0);
310 JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, null,
312 pane.setComponentOrientation(JOptionPane.getRootFrame().getComponentOrientation());
313 pane.selectInitialValue();
315 placeholderLabel.setBorder(new EmptyBorder(textField.getBorder().getBorderInsets(textField)));
317 JDialog dialog = pane.createDialog(null, title);
318 dialog.addWindowFocusListener(new WindowFocusListener() {
319 public void windowLostFocus (WindowEvent arg0) {
322 public void windowGainedFocus (WindowEvent arg0) {
323 textField.requestFocusInWindow();
326 dialog.setVisible(true);
329 Object selectedValue = pane.getValue();
330 if (selectedValue != null && (selectedValue instanceof Integer) && (Integer)selectedValue == JOptionPane.OK_OPTION)
331 listener.input(textField.getText());
338 static char characterForKeyCode (int key) {
339 // Map certain key codes to character codes.
345 case Keys.FORWARD_DEL:
351 static public int getGdxKeyCode (int lwjglKeyCode) {
352 switch (lwjglKeyCode) {
353 case GLFW_KEY_LEFT_BRACKET:
354 return Input.Keys.LEFT_BRACKET;
355 case GLFW_KEY_RIGHT_BRACKET:
356 return Input.Keys.RIGHT_BRACKET;
357 case GLFW_KEY_GRAVE_ACCENT:
358 return Input.Keys.GRAVE;
359 case GLFW_KEY_KP_MULTIPLY:
360 return Input.Keys.STAR;
361 case GLFW_KEY_NUM_LOCK:
362 return Input.Keys.NUM;
363 case GLFW_KEY_KP_DECIMAL:
364 return Input.Keys.PERIOD;
365 case GLFW_KEY_KP_DIVIDE:
366 return Input.Keys.SLASH;
368 return Input.Keys.MENU;
369 case GLFW_KEY_RIGHT_SUPER:
370 return Input.Keys.SYM;
371 case GLFW_KEY_LEFT_SUPER:
372 return Input.Keys.SYM;
373 case GLFW_KEY_KP_EQUAL:
374 return Input.Keys.EQUALS;
376 return Input.Keys.EQUALS;
377 case GLFW_KEY_KP_ENTER:
378 return Input.Keys.ENTER;
380 return Input.Keys.NUM_0;
382 return Input.Keys.NUM_1;
384 return Input.Keys.NUM_2;
386 return Input.Keys.NUM_3;
388 return Input.Keys.NUM_4;
390 return Input.Keys.NUM_5;
392 return Input.Keys.NUM_6;
394 return Input.Keys.NUM_7;
396 return Input.Keys.NUM_8;
398 return Input.Keys.NUM_9;
452 return Input.Keys.ALT_LEFT;
454 return Input.Keys.ALT_RIGHT;
455 case GLFW_KEY_BACKSLASH:
456 return Input.Keys.BACKSLASH;
458 return Input.Keys.COMMA;
459 case GLFW_KEY_DELETE:
460 return Input.Keys.FORWARD_DEL;
462 return Input.Keys.DPAD_LEFT;
464 return Input.Keys.DPAD_RIGHT;
466 return Input.Keys.DPAD_UP;
468 return Input.Keys.DPAD_DOWN;
470 return Input.Keys.ENTER;
472 return Input.Keys.HOME;
474 return Input.Keys.MINUS;
475 case GLFW_KEY_PERIOD:
476 return Input.Keys.PERIOD;
477 case GLFW_KEY_KP_ADD:
478 return Input.Keys.PLUS;
479 case GLFW_KEY_SEMICOLON:
480 return Input.Keys.SEMICOLON;
481 case GLFW_KEY_LSHIFT:
482 return Input.Keys.SHIFT_LEFT;
483 case GLFW_KEY_RSHIFT:
484 return Input.Keys.SHIFT_RIGHT;
486 return Input.Keys.SLASH;
488 return Input.Keys.SPACE;
490 return Input.Keys.TAB;
491 case GLFW_KEY_LEFT_CONTROL:
492 return Input.Keys.CONTROL_LEFT;
493 case GLFW_KEY_RIGHT_CONTROL:
494 return Input.Keys.CONTROL_RIGHT;
495 case GLFW_KEY_ESCAPE:
496 return Input.Keys.ESCAPE;
498 return Input.Keys.END;
499 case GLFW_KEY_INSERT:
500 return Input.Keys.INSERT;
501 case GLFW_KEY_BACKSPACE:
502 return Input.Keys.DEL;
503 case GLFW_KEY_KP_SUBTRACT:
504 return Input.Keys.MINUS;
505 case GLFW_KEY_APOSTROPHE:
506 return Input.Keys.APOSTROPHE;
508 return Input.Keys.F1;
510 return Input.Keys.F2;
512 return Input.Keys.F3;
514 return Input.Keys.F4;
516 return Input.Keys.F5;
518 return Input.Keys.F6;
520 return Input.Keys.F7;
522 return Input.Keys.F8;
524 return Input.Keys.F9;
526 return Input.Keys.F10;
528 return Input.Keys.F11;
530 return Input.Keys.F12;
532 return Input.Keys.NUM_0;
534 return Input.Keys.NUM_1;
536 return Input.Keys.NUM_2;
538 return Input.Keys.NUM_3;
540 return Input.Keys.NUM_4;
542 return Input.Keys.NUM_5;
544 return Input.Keys.NUM_6;
546 return Input.Keys.NUM_7;
548 return Input.Keys.NUM_8;
550 return Input.Keys.NUM_9;
552 return Input.Keys.UNKNOWN;
556 static public int getJglfwKeyCode (int gdxKeyCode) {
557 switch (gdxKeyCode) {
558 case Input.Keys.LEFT_BRACKET:
559 return GLFW_KEY_LEFT_BRACKET;
560 case Input.Keys.RIGHT_BRACKET:
561 return GLFW_KEY_RIGHT_BRACKET;
562 case Input.Keys.GRAVE:
563 return GLFW_KEY_GRAVE_ACCENT;
564 case Input.Keys.STAR:
565 return GLFW_KEY_KP_MULTIPLY;
567 return GLFW_KEY_NUM_LOCK;
568 case Input.Keys.EQUALS:
569 return GLFW_KEY_MENU;
570 case Input.Keys.MENU:
571 return GLFW_KEY_MENU;
573 return GLFW_KEY_LEFT_SUPER;
574 case Input.Keys.NUM_0:
576 case Input.Keys.NUM_1:
578 case Input.Keys.NUM_2:
580 case Input.Keys.NUM_3:
582 case Input.Keys.NUM_4:
584 case Input.Keys.NUM_5:
586 case Input.Keys.NUM_6:
588 case Input.Keys.NUM_7:
590 case Input.Keys.NUM_8:
592 case Input.Keys.NUM_9:
646 case Input.Keys.ALT_LEFT:
647 return GLFW_KEY_LALT;
648 case Input.Keys.ALT_RIGHT:
649 return GLFW_KEY_RALT;
650 case Input.Keys.BACKSLASH:
651 return GLFW_KEY_BACKSLASH;
652 case Input.Keys.COMMA:
653 return GLFW_KEY_COMMA;
654 case Input.Keys.FORWARD_DEL:
655 return GLFW_KEY_DELETE;
656 case Input.Keys.DPAD_LEFT:
657 return GLFW_KEY_LEFT;
658 case Input.Keys.DPAD_RIGHT:
659 return GLFW_KEY_RIGHT;
660 case Input.Keys.DPAD_UP:
662 case Input.Keys.DPAD_DOWN:
663 return GLFW_KEY_DOWN;
664 case Input.Keys.ENTER:
665 return GLFW_KEY_ENTER;
666 case Input.Keys.HOME:
667 return GLFW_KEY_HOME;
668 case Input.Keys.MINUS:
669 return GLFW_KEY_MINUS;
670 case Input.Keys.PERIOD:
671 return GLFW_KEY_PERIOD;
672 case Input.Keys.PLUS:
673 return GLFW_KEY_KP_ADD;
674 case Input.Keys.SEMICOLON:
675 return GLFW_KEY_SEMICOLON;
676 case Input.Keys.SHIFT_LEFT:
677 return GLFW_KEY_LSHIFT;
678 case Input.Keys.SHIFT_RIGHT:
679 return GLFW_KEY_RSHIFT;
680 case Input.Keys.SLASH:
681 return GLFW_KEY_SLASH;
682 case Input.Keys.SPACE:
683 return GLFW_KEY_SPACE;
687 return GLFW_KEY_BACKSPACE;
688 case Input.Keys.CONTROL_LEFT:
689 return GLFW_KEY_LEFT_CONTROL;
690 case Input.Keys.CONTROL_RIGHT:
691 return GLFW_KEY_RIGHT_CONTROL;
692 case Input.Keys.ESCAPE:
693 return GLFW_KEY_ESCAPE;
723 /** Receives GLFW input and calls InputProcessor methods.
724 * @author Nathan Sweet */
725 static class GlfwInputProcessor extends GlfwCallbackAdapter {
726 private int mouseX, mouseY, mousePressed;
727 private char lastCharacter;
728 private InputProcessor processor;
730 public GlfwInputProcessor (InputProcessor processor) {
731 if (processor == null) throw new IllegalArgumentException("processor cannot be null.");
732 this.processor = processor;
735 public void key (long window, int key, int action) {
739 key = getGdxKeyCode(key);
740 processor.keyDown(key);
743 char character = characterForKeyCode(key);
744 if (character != 0) character(window, character);
748 processor.keyUp(getGdxKeyCode(key));
752 if (lastCharacter != 0) processor.keyTyped(lastCharacter);
757 public void character (long window, char character) {
758 lastCharacter = character;
759 processor.keyTyped(character);
762 public void scroll (long window, double scrollX, double scrollY) {
763 processor.scrolled((int)-Math.signum(scrollY));
766 public void mouseButton (long window, int button, boolean pressed) {
769 processor.touchDown(mouseX, mouseY, 0, button);
771 mousePressed = Math.max(0, mousePressed - 1);
772 processor.touchUp(mouseX, mouseY, 0, button);
776 public void cursorPos (long window, int x, int y) {
779 if (mousePressed > 0)
780 processor.touchDragged(x, y, 0);
782 processor.mouseMoved(x, y);