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, GLFW_KEY_LEFT_SUPER) || glfwGetKey(app.graphics.window, GLFW_KEY_RIGHT_SUPER);
180 return glfwGetKey(app.graphics.window, getJglfwKeyCode(key));
183 public void setOnscreenKeyboardVisible (boolean visible) {
186 public void vibrate (int milliseconds) {
189 public void vibrate (long[] pattern, int repeat) {
192 public void cancelVibrate () {
195 public float getAzimuth () {
199 public float getPitch () {
203 public float getRoll () {
207 public void getRotationMatrix (float[] matrix) {
210 public long getCurrentEventTime () {
211 return processorQueue != null ? processorQueue.getCurrentEventTime() : currentEventTime;
214 public void setCatchBackKey (boolean catchBack) {
217 public void setCatchMenuKey (boolean catchMenu) {
220 public void setInputProcessor (InputProcessor processor) {
221 this.processor = processor;
224 public InputProcessor getInputProcessor () {
228 public boolean isPeripheralAvailable (Peripheral peripheral) {
229 return peripheral == Peripheral.HardwareKeyboard;
232 public int getRotation () {
236 public Orientation getNativeOrientation () {
237 return Orientation.Landscape;
240 public void setCursorCatched (boolean captured) {
241 glfwSetInputMode(app.graphics.window, GLFW_CURSOR_MODE, captured ? GLFW_CURSOR_CAPTURED : GLFW_CURSOR_NORMAL);
244 public boolean isCursorCatched () {
245 return glfwGetInputMode(app.graphics.window, GLFW_CURSOR_MODE) == GLFW_CURSOR_CAPTURED;
248 public void setCursorPosition (int x, int y) {
249 glfwSetCursorPos(app.graphics.window, x, y);
252 public void getTextInput (final TextInputListener listener, final String title, final String text) {
253 SwingUtilities.invokeLater(new Runnable() {
255 final String output = JOptionPane.showInputDialog(null, title, text);
256 app.postRunnable(new Runnable() {
259 listener.input(output);
268 public void getPlaceholderTextInput (final TextInputListener listener, final String title, final String placeholder) {
269 SwingUtilities.invokeLater(new Runnable() {
271 JPanel panel = new JPanel(new FlowLayout());
273 JPanel textPanel = new JPanel() {
274 public boolean isOptimizedDrawingEnabled () {
278 textPanel.setLayout(new OverlayLayout(textPanel));
279 panel.add(textPanel);
281 final JTextField textField = new JTextField(20);
282 textField.setAlignmentX(0.0f);
283 textPanel.add(textField);
285 final JLabel placeholderLabel = new JLabel(placeholder);
286 placeholderLabel.setForeground(Color.GRAY);
287 placeholderLabel.setAlignmentX(0.0f);
288 textPanel.add(placeholderLabel, 0);
290 textField.getDocument().addDocumentListener(new DocumentListener() {
291 public void removeUpdate (DocumentEvent event) {
295 public void insertUpdate (DocumentEvent event) {
299 public void changedUpdate (DocumentEvent event) {
303 private void updated () {
304 placeholderLabel.setVisible(textField.getText().length() == 0);
308 JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, null,
310 pane.setComponentOrientation(JOptionPane.getRootFrame().getComponentOrientation());
311 pane.selectInitialValue();
313 placeholderLabel.setBorder(new EmptyBorder(textField.getBorder().getBorderInsets(textField)));
315 JDialog dialog = pane.createDialog(null, title);
316 dialog.addWindowFocusListener(new WindowFocusListener() {
317 public void windowLostFocus (WindowEvent arg0) {
320 public void windowGainedFocus (WindowEvent arg0) {
321 textField.requestFocusInWindow();
324 dialog.setVisible(true);
327 Object selectedValue = pane.getValue();
328 if (selectedValue != null && (selectedValue instanceof Integer) && (Integer)selectedValue == JOptionPane.OK_OPTION)
329 listener.input(textField.getText());
336 static char characterForKeyCode (int key) {
337 // Map certain key codes to character codes.
343 case Keys.FORWARD_DEL:
349 static public int getGdxKeyCode (int lwjglKeyCode) {
350 switch (lwjglKeyCode) {
351 case GLFW_KEY_LEFT_BRACKET:
352 return Input.Keys.LEFT_BRACKET;
353 case GLFW_KEY_RIGHT_BRACKET:
354 return Input.Keys.RIGHT_BRACKET;
355 case GLFW_KEY_GRAVE_ACCENT:
356 return Input.Keys.GRAVE;
357 case GLFW_KEY_KP_MULTIPLY:
358 return Input.Keys.STAR;
359 case GLFW_KEY_NUM_LOCK:
360 return Input.Keys.NUM;
361 case GLFW_KEY_KP_DECIMAL:
362 return Input.Keys.PERIOD;
363 case GLFW_KEY_KP_DIVIDE:
364 return Input.Keys.SLASH;
366 return Input.Keys.MENU;
367 case GLFW_KEY_RIGHT_SUPER:
368 return Input.Keys.SYM;
369 case GLFW_KEY_LEFT_SUPER:
370 return Input.Keys.SYM;
371 case GLFW_KEY_KP_EQUAL:
372 return Input.Keys.EQUALS;
374 return Input.Keys.EQUALS;
375 case GLFW_KEY_KP_ENTER:
376 return Input.Keys.ENTER;
378 return Input.Keys.NUM_0;
380 return Input.Keys.NUM_1;
382 return Input.Keys.NUM_2;
384 return Input.Keys.NUM_3;
386 return Input.Keys.NUM_4;
388 return Input.Keys.NUM_5;
390 return Input.Keys.NUM_6;
392 return Input.Keys.NUM_7;
394 return Input.Keys.NUM_8;
396 return Input.Keys.NUM_9;
450 return Input.Keys.ALT_LEFT;
452 return Input.Keys.ALT_RIGHT;
453 case GLFW_KEY_BACKSLASH:
454 return Input.Keys.BACKSLASH;
456 return Input.Keys.COMMA;
457 case GLFW_KEY_DELETE:
458 return Input.Keys.FORWARD_DEL;
460 return Input.Keys.DPAD_LEFT;
462 return Input.Keys.DPAD_RIGHT;
464 return Input.Keys.DPAD_UP;
466 return Input.Keys.DPAD_DOWN;
468 return Input.Keys.ENTER;
470 return Input.Keys.HOME;
472 return Input.Keys.MINUS;
473 case GLFW_KEY_PERIOD:
474 return Input.Keys.PERIOD;
475 case GLFW_KEY_KP_ADD:
476 return Input.Keys.PLUS;
477 case GLFW_KEY_SEMICOLON:
478 return Input.Keys.SEMICOLON;
479 case GLFW_KEY_LSHIFT:
480 return Input.Keys.SHIFT_LEFT;
481 case GLFW_KEY_RSHIFT:
482 return Input.Keys.SHIFT_RIGHT;
484 return Input.Keys.SLASH;
486 return Input.Keys.SPACE;
488 return Input.Keys.TAB;
489 case GLFW_KEY_LEFT_CONTROL:
490 return Input.Keys.CONTROL_LEFT;
491 case GLFW_KEY_RIGHT_CONTROL:
492 return Input.Keys.CONTROL_RIGHT;
493 case GLFW_KEY_ESCAPE:
494 return Input.Keys.ESCAPE;
496 return Input.Keys.END;
497 case GLFW_KEY_INSERT:
498 return Input.Keys.INSERT;
499 case GLFW_KEY_BACKSPACE:
500 return Input.Keys.DEL;
501 case GLFW_KEY_KP_SUBTRACT:
502 return Input.Keys.MINUS;
503 case GLFW_KEY_APOSTROPHE:
504 return Input.Keys.APOSTROPHE;
506 return Input.Keys.F1;
508 return Input.Keys.F2;
510 return Input.Keys.F3;
512 return Input.Keys.F4;
514 return Input.Keys.F5;
516 return Input.Keys.F6;
518 return Input.Keys.F7;
520 return Input.Keys.F8;
522 return Input.Keys.F9;
524 return Input.Keys.F10;
526 return Input.Keys.F11;
528 return Input.Keys.F12;
530 return Input.Keys.NUM_0;
532 return Input.Keys.NUM_1;
534 return Input.Keys.NUM_2;
536 return Input.Keys.NUM_3;
538 return Input.Keys.NUM_4;
540 return Input.Keys.NUM_5;
542 return Input.Keys.NUM_6;
544 return Input.Keys.NUM_7;
546 return Input.Keys.NUM_8;
548 return Input.Keys.NUM_9;
550 return Input.Keys.UNKNOWN;
554 static public int getJglfwKeyCode (int gdxKeyCode) {
555 switch (gdxKeyCode) {
556 case Input.Keys.LEFT_BRACKET:
557 return GLFW_KEY_LEFT_BRACKET;
558 case Input.Keys.RIGHT_BRACKET:
559 return GLFW_KEY_RIGHT_BRACKET;
560 case Input.Keys.GRAVE:
561 return GLFW_KEY_GRAVE_ACCENT;
562 case Input.Keys.STAR:
563 return GLFW_KEY_KP_MULTIPLY;
565 return GLFW_KEY_NUM_LOCK;
566 case Input.Keys.EQUALS:
567 return GLFW_KEY_MENU;
568 case Input.Keys.MENU:
569 return GLFW_KEY_MENU;
571 return GLFW_KEY_LEFT_SUPER;
572 case Input.Keys.NUM_0:
574 case Input.Keys.NUM_1:
576 case Input.Keys.NUM_2:
578 case Input.Keys.NUM_3:
580 case Input.Keys.NUM_4:
582 case Input.Keys.NUM_5:
584 case Input.Keys.NUM_6:
586 case Input.Keys.NUM_7:
588 case Input.Keys.NUM_8:
590 case Input.Keys.NUM_9:
644 case Input.Keys.ALT_LEFT:
645 return GLFW_KEY_LALT;
646 case Input.Keys.ALT_RIGHT:
647 return GLFW_KEY_RALT;
648 case Input.Keys.BACKSLASH:
649 return GLFW_KEY_BACKSLASH;
650 case Input.Keys.COMMA:
651 return GLFW_KEY_COMMA;
652 case Input.Keys.FORWARD_DEL:
653 return GLFW_KEY_DELETE;
654 case Input.Keys.DPAD_LEFT:
655 return GLFW_KEY_LEFT;
656 case Input.Keys.DPAD_RIGHT:
657 return GLFW_KEY_RIGHT;
658 case Input.Keys.DPAD_UP:
660 case Input.Keys.DPAD_DOWN:
661 return GLFW_KEY_DOWN;
662 case Input.Keys.ENTER:
663 return GLFW_KEY_ENTER;
664 case Input.Keys.HOME:
665 return GLFW_KEY_HOME;
666 case Input.Keys.MINUS:
667 return GLFW_KEY_MINUS;
668 case Input.Keys.PERIOD:
669 return GLFW_KEY_PERIOD;
670 case Input.Keys.PLUS:
671 return GLFW_KEY_KP_ADD;
672 case Input.Keys.SEMICOLON:
673 return GLFW_KEY_SEMICOLON;
674 case Input.Keys.SHIFT_LEFT:
675 return GLFW_KEY_LSHIFT;
676 case Input.Keys.SHIFT_RIGHT:
677 return GLFW_KEY_RSHIFT;
678 case Input.Keys.SLASH:
679 return GLFW_KEY_SLASH;
680 case Input.Keys.SPACE:
681 return GLFW_KEY_SPACE;
685 return GLFW_KEY_BACKSPACE;
686 case Input.Keys.CONTROL_LEFT:
687 return GLFW_KEY_LEFT_CONTROL;
688 case Input.Keys.CONTROL_RIGHT:
689 return GLFW_KEY_RIGHT_CONTROL;
690 case Input.Keys.ESCAPE:
691 return GLFW_KEY_ESCAPE;
721 /** Receives GLFW input and calls InputProcessor methods.
722 * @author Nathan Sweet */
723 static class GlfwInputProcessor extends GlfwCallbackAdapter {
724 private int mouseX, mouseY, mousePressed;
725 private char lastCharacter;
726 private InputProcessor processor;
728 public GlfwInputProcessor (InputProcessor processor) {
729 if (processor == null) throw new IllegalArgumentException("processor cannot be null.");
730 this.processor = processor;
733 public void key (long window, int key, int action) {
737 key = getGdxKeyCode(key);
738 processor.keyDown(key);
741 char character = characterForKeyCode(key);
742 if (character != 0) character(window, character);
746 processor.keyUp(getGdxKeyCode(key));
750 if (lastCharacter != 0) processor.keyTyped(lastCharacter);
755 public void character (long window, char character) {
756 lastCharacter = character;
757 processor.keyTyped(character);
760 public void scroll (long window, double scrollX, double scrollY) {
761 processor.scrolled((int)-Math.signum(scrollY));
764 public void mouseButton (long window, int button, boolean pressed) {
767 processor.touchDown(mouseX, mouseY, 0, button);
769 mousePressed = Math.max(0, mousePressed - 1);
770 processor.touchUp(mouseX, mouseY, 0, button);
774 public void cursorPos (long window, int x, int y) {
777 if (mousePressed > 0)
778 processor.touchDragged(x, y, 0);
780 processor.mouseMoved(x, y);