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 return glfwGetKey(app.graphics.window, getJglfwKeyCode(key));
181 public void setOnscreenKeyboardVisible (boolean visible) {
184 public void vibrate (int milliseconds) {
187 public void vibrate (long[] pattern, int repeat) {
190 public void cancelVibrate () {
193 public float getAzimuth () {
197 public float getPitch () {
201 public float getRoll () {
205 public void getRotationMatrix (float[] matrix) {
208 public long getCurrentEventTime () {
209 return processorQueue != null ? processorQueue.getCurrentEventTime() : currentEventTime;
212 public void setCatchBackKey (boolean catchBack) {
215 public void setCatchMenuKey (boolean catchMenu) {
218 public void setInputProcessor (InputProcessor processor) {
219 this.processor = processor;
222 public InputProcessor getInputProcessor () {
226 public boolean isPeripheralAvailable (Peripheral peripheral) {
227 return peripheral == Peripheral.HardwareKeyboard;
230 public int getRotation () {
234 public Orientation getNativeOrientation () {
235 return Orientation.Landscape;
238 public void setCursorCatched (boolean captured) {
239 glfwSetInputMode(app.graphics.window, GLFW_CURSOR_MODE, captured ? GLFW_CURSOR_CAPTURED : GLFW_CURSOR_NORMAL);
242 public boolean isCursorCatched () {
243 return glfwGetInputMode(app.graphics.window, GLFW_CURSOR_MODE) == GLFW_CURSOR_CAPTURED;
246 public void setCursorPosition (int x, int y) {
247 glfwSetCursorPos(app.graphics.window, x, y);
250 public void getTextInput (final TextInputListener listener, final String title, final String text) {
251 SwingUtilities.invokeLater(new Runnable() {
253 final String output = JOptionPane.showInputDialog(null, title, text);
254 app.postRunnable(new Runnable() {
257 listener.input(output);
266 public void getPlaceholderTextInput (final TextInputListener listener, final String title, final String placeholder) {
267 SwingUtilities.invokeLater(new Runnable() {
269 JPanel panel = new JPanel(new FlowLayout());
271 JPanel textPanel = new JPanel() {
272 public boolean isOptimizedDrawingEnabled () {
276 textPanel.setLayout(new OverlayLayout(textPanel));
277 panel.add(textPanel);
279 final JTextField textField = new JTextField(20);
280 textField.setAlignmentX(0.0f);
281 textPanel.add(textField);
283 final JLabel placeholderLabel = new JLabel(placeholder);
284 placeholderLabel.setForeground(Color.GRAY);
285 placeholderLabel.setAlignmentX(0.0f);
286 textPanel.add(placeholderLabel, 0);
288 textField.getDocument().addDocumentListener(new DocumentListener() {
289 public void removeUpdate (DocumentEvent event) {
293 public void insertUpdate (DocumentEvent event) {
297 public void changedUpdate (DocumentEvent event) {
301 private void updated () {
302 placeholderLabel.setVisible(textField.getText().length() == 0);
306 JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, null,
308 pane.setComponentOrientation(JOptionPane.getRootFrame().getComponentOrientation());
309 pane.selectInitialValue();
311 placeholderLabel.setBorder(new EmptyBorder(textField.getBorder().getBorderInsets(textField)));
313 JDialog dialog = pane.createDialog(null, title);
314 dialog.addWindowFocusListener(new WindowFocusListener() {
315 public void windowLostFocus (WindowEvent arg0) {
318 public void windowGainedFocus (WindowEvent arg0) {
319 textField.requestFocusInWindow();
322 dialog.setVisible(true);
325 Object selectedValue = pane.getValue();
326 if (selectedValue != null && (selectedValue instanceof Integer) && (Integer)selectedValue == JOptionPane.OK_OPTION)
327 listener.input(textField.getText());
334 static char characterForKeyCode (int key) {
335 // Map certain key codes to character codes.
341 case Keys.FORWARD_DEL:
347 static public int getGdxKeyCode (int lwjglKeyCode) {
348 switch (lwjglKeyCode) {
349 case GLFW_KEY_LEFT_BRACKET:
350 return Input.Keys.LEFT_BRACKET;
351 case GLFW_KEY_RIGHT_BRACKET:
352 return Input.Keys.RIGHT_BRACKET;
353 case GLFW_KEY_GRAVE_ACCENT:
354 return Input.Keys.GRAVE;
355 case GLFW_KEY_KP_MULTIPLY:
356 return Input.Keys.STAR;
357 case GLFW_KEY_NUM_LOCK:
358 return Input.Keys.NUM;
359 case GLFW_KEY_KP_DECIMAL:
360 return Input.Keys.PERIOD;
361 case GLFW_KEY_KP_DIVIDE:
362 return Input.Keys.SLASH;
364 return Input.Keys.MENU;
365 case GLFW_KEY_RIGHT_SUPER:
366 return Input.Keys.SYM;
367 case GLFW_KEY_LEFT_SUPER:
368 return Input.Keys.SYM;
369 case GLFW_KEY_KP_EQUAL:
370 return Input.Keys.EQUALS;
372 return Input.Keys.EQUALS;
373 case GLFW_KEY_KP_ENTER:
374 return Input.Keys.ENTER;
376 return Input.Keys.NUM_0;
378 return Input.Keys.NUM_1;
380 return Input.Keys.NUM_2;
382 return Input.Keys.NUM_3;
384 return Input.Keys.NUM_4;
386 return Input.Keys.NUM_5;
388 return Input.Keys.NUM_6;
390 return Input.Keys.NUM_7;
392 return Input.Keys.NUM_8;
394 return Input.Keys.NUM_9;
448 return Input.Keys.ALT_LEFT;
450 return Input.Keys.ALT_RIGHT;
451 case GLFW_KEY_BACKSLASH:
452 return Input.Keys.BACKSLASH;
454 return Input.Keys.COMMA;
455 case GLFW_KEY_DELETE:
456 return Input.Keys.FORWARD_DEL;
458 return Input.Keys.DPAD_LEFT;
460 return Input.Keys.DPAD_RIGHT;
462 return Input.Keys.DPAD_UP;
464 return Input.Keys.DPAD_DOWN;
466 return Input.Keys.ENTER;
468 return Input.Keys.HOME;
470 return Input.Keys.MINUS;
471 case GLFW_KEY_PERIOD:
472 return Input.Keys.PERIOD;
473 case GLFW_KEY_KP_ADD:
474 return Input.Keys.PLUS;
475 case GLFW_KEY_SEMICOLON:
476 return Input.Keys.SEMICOLON;
477 case GLFW_KEY_LSHIFT:
478 return Input.Keys.SHIFT_LEFT;
479 case GLFW_KEY_RSHIFT:
480 return Input.Keys.SHIFT_RIGHT;
482 return Input.Keys.SLASH;
484 return Input.Keys.SPACE;
486 return Input.Keys.TAB;
487 case GLFW_KEY_LEFT_CONTROL:
488 return Input.Keys.CONTROL_LEFT;
489 case GLFW_KEY_RIGHT_CONTROL:
490 return Input.Keys.CONTROL_RIGHT;
491 case GLFW_KEY_ESCAPE:
492 return Input.Keys.ESCAPE;
494 return Input.Keys.END;
495 case GLFW_KEY_INSERT:
496 return Input.Keys.INSERT;
497 case GLFW_KEY_BACKSPACE:
498 return Input.Keys.DEL;
499 case GLFW_KEY_KP_SUBTRACT:
500 return Input.Keys.MINUS;
501 case GLFW_KEY_APOSTROPHE:
502 return Input.Keys.APOSTROPHE;
504 return Input.Keys.F1;
506 return Input.Keys.F2;
508 return Input.Keys.F3;
510 return Input.Keys.F4;
512 return Input.Keys.F5;
514 return Input.Keys.F6;
516 return Input.Keys.F7;
518 return Input.Keys.F8;
520 return Input.Keys.F9;
522 return Input.Keys.F10;
524 return Input.Keys.F11;
526 return Input.Keys.F12;
528 return Input.Keys.NUM_0;
530 return Input.Keys.NUM_1;
532 return Input.Keys.NUM_2;
534 return Input.Keys.NUM_3;
536 return Input.Keys.NUM_4;
538 return Input.Keys.NUM_5;
540 return Input.Keys.NUM_6;
542 return Input.Keys.NUM_7;
544 return Input.Keys.NUM_8;
546 return Input.Keys.NUM_9;
548 return Input.Keys.UNKNOWN;
552 static public int getJglfwKeyCode (int gdxKeyCode) {
553 switch (gdxKeyCode) {
554 case Input.Keys.LEFT_BRACKET:
555 return GLFW_KEY_LEFT_BRACKET;
556 case Input.Keys.RIGHT_BRACKET:
557 return GLFW_KEY_RIGHT_BRACKET;
558 case Input.Keys.GRAVE:
559 return GLFW_KEY_GRAVE_ACCENT;
560 case Input.Keys.STAR:
561 return GLFW_KEY_KP_MULTIPLY;
563 return GLFW_KEY_NUM_LOCK;
564 case Input.Keys.EQUALS:
565 return GLFW_KEY_MENU;
566 case Input.Keys.MENU:
567 return GLFW_KEY_MENU;
569 return GLFW_KEY_LEFT_SUPER;
570 case Input.Keys.NUM_0:
572 case Input.Keys.NUM_1:
574 case Input.Keys.NUM_2:
576 case Input.Keys.NUM_3:
578 case Input.Keys.NUM_4:
580 case Input.Keys.NUM_5:
582 case Input.Keys.NUM_6:
584 case Input.Keys.NUM_7:
586 case Input.Keys.NUM_8:
588 case Input.Keys.NUM_9:
642 case Input.Keys.ALT_LEFT:
643 return GLFW_KEY_LALT;
644 case Input.Keys.ALT_RIGHT:
645 return GLFW_KEY_RALT;
646 case Input.Keys.BACKSLASH:
647 return GLFW_KEY_BACKSLASH;
648 case Input.Keys.COMMA:
649 return GLFW_KEY_COMMA;
650 case Input.Keys.FORWARD_DEL:
651 return GLFW_KEY_DELETE;
652 case Input.Keys.DPAD_LEFT:
653 return GLFW_KEY_LEFT;
654 case Input.Keys.DPAD_RIGHT:
655 return GLFW_KEY_RIGHT;
656 case Input.Keys.DPAD_UP:
658 case Input.Keys.DPAD_DOWN:
659 return GLFW_KEY_DOWN;
660 case Input.Keys.ENTER:
661 return GLFW_KEY_ENTER;
662 case Input.Keys.HOME:
663 return GLFW_KEY_HOME;
664 case Input.Keys.MINUS:
665 return GLFW_KEY_MINUS;
666 case Input.Keys.PERIOD:
667 return GLFW_KEY_PERIOD;
668 case Input.Keys.PLUS:
669 return GLFW_KEY_KP_ADD;
670 case Input.Keys.SEMICOLON:
671 return GLFW_KEY_SEMICOLON;
672 case Input.Keys.SHIFT_LEFT:
673 return GLFW_KEY_LSHIFT;
674 case Input.Keys.SHIFT_RIGHT:
675 return GLFW_KEY_RSHIFT;
676 case Input.Keys.SLASH:
677 return GLFW_KEY_SLASH;
678 case Input.Keys.SPACE:
679 return GLFW_KEY_SPACE;
683 return GLFW_KEY_BACKSPACE;
684 case Input.Keys.CONTROL_LEFT:
685 return GLFW_KEY_LEFT_CONTROL;
686 case Input.Keys.CONTROL_RIGHT:
687 return GLFW_KEY_RIGHT_CONTROL;
688 case Input.Keys.ESCAPE:
689 return GLFW_KEY_ESCAPE;
719 /** Receives GLFW input and calls InputProcessor methods.
720 * @author Nathan Sweet */
721 static class GlfwInputProcessor extends GlfwCallbackAdapter {
722 private int mouseX, mouseY, mousePressed;
723 private char lastCharacter;
724 private InputProcessor processor;
726 public GlfwInputProcessor (InputProcessor processor) {
727 if (processor == null) throw new IllegalArgumentException("processor cannot be null.");
728 this.processor = processor;
731 public void key (long window, int key, int action) {
735 key = getGdxKeyCode(key);
736 processor.keyDown(key);
739 char character = characterForKeyCode(key);
740 if (character != 0) character(window, character);
744 processor.keyUp(getGdxKeyCode(key));
748 if (lastCharacter != 0) processor.keyTyped(lastCharacter);
753 public void character (long window, char character) {
754 lastCharacter = character;
755 processor.keyTyped(character);
758 public void scroll (long window, double scrollX, double scrollY) {
759 processor.scrolled((int)-Math.signum(scrollY));
762 public void mouseButton (long window, int button, boolean pressed) {
765 processor.touchDown(mouseX, mouseY, 0, button);
767 mousePressed = Math.max(0, mousePressed - 1);
768 processor.touchUp(mouseX, mouseY, 0, button);
772 public void cursorPos (long window, int x, int y) {
775 if (mousePressed > 0)
776 processor.touchDragged(x, y, 0);
778 processor.mouseMoved(x, y);