Libgdx override keyDown using InputMultiplexer in Screen - java

I have a screen and have created a new multiplexer and set an input processor.
How can I override keyDown on my screen?
public class Screen implements Screen, TextInputListener
{
...stuff...
public Screen(Game game)
{
multiplexer = new InputMultiplexer();
multiplexer.addProcessor(mySystem);
multiplexer.addProcessor(aStage);
Gdx.input.setInputProcessor(multiplexer);
}
...more stuff....
}
Thanks

To override KeyDown you need to implement InputProcessor.
For example if you want to override the Android Back button and the Backspace button on PC you can use a class like this.
public class ScreenInputHandler implements InputProcessor {
#Override
public boolean keyDown(int keycode) {
if(keycode == Keys.BACK || keycode == Keys.BACKSPACE){
...code here
}
return false;
}
}
Remember add the input handler to your InputMultiplexer.

This is how I ended up solving it:
InputProcessor backProcessor = new InputAdapter()
{
#Override
public boolean keyDown(int keycode)
{
//do stuff
return false;
}
};
multiplexer.addProcessor(backProcessor);

Related

JButton appearance as if it were pressed

In some cases a need my JButton to appear as if it were pressed. This depends on some boolean.
I tried to create my own ButtonModel that overrides the default isPressed() method but in that way the button appears pressed only in case the mouse pointer is on top of it (without pressing a mouse button). I need it to appear pressed also if the mouse is somewhere else.
So far I tried this:
class MyButtonModel extends DefaultButtonModel
{
private boolean appearPressed;
#Override
public boolean isPressed()
{
return super.isPressed() || appearPressed;
}
}
I cannot use a JToggleButton or something similar.
My button derives from another class that implements some additional features and derives itself from JButton.
UPDATE:
I'm running on Windows 10 and use the WindowsClassic Look&Feel.
you also need to override isArmed():
class MyButtonModel extends DefaultButtonModel
{
private boolean appearPressed = true;
#Override
public boolean isPressed()
{
return super.isPressed() || appearPressed;
}
#Override
public boolean isArmed() {
return super.isArmed() || appearPressed;
}
}
The partial reply was given by #Philipp Li and #camickr. Thank you.
My button model needs to override isArmed() in order to obtain the desired result.
However, once the button is pressed, it doesn't respond anymore.
Digging in the source of DefaultButtonModel, I found this:
public void setPressed(boolean b)
{
if ((isPressed() == b) || (!isEnabled()))
return;
...
}
This method is invoked by AbstractButton.doClick() in order to notify the various ActionListeners.
In other words, if the overridden method isPressed() returns true because I want to make the button appear pressed, a successive click on that button will be ignored.
A similar thing occurs within DefaultButtonModel.setArmed().
Therefore, I implemented my button model as follows:
class MyButtonModel extends DefaultButtonModel
{
boolean appearPressed = false;
private boolean withinSetPressedMethod = false;
private boolean withinSetArmedMethod = false;
#Override
public void setPressed(boolean pressed)
{
withinSetPressedMethod = true;
super.setPressed(pressed);
withinSetPressedMethod = false;
}
#Override
public void setArmed(boolean armed)
{
withinSetArmedMethod = true;
super.setArmed(armed);
withinSetArmedMethod = false;
}
#Override
public boolean isPressed()
{
if (withinSetPressedMethod)
return (super.isPressed());
else
return (super.isPressed() || appearPressed);
}
#Override
public boolean isArmed()
{
if (withinSetArmedMethod)
return (super.isArmed());
else
return (super.isArmed() || appearPressed);
}
} // class MyButtonModel

Libgdx - stackOverFlow when I use .isPressed()

I'm coding a Menu using the latest version of Libgdx. Each screen (MainMenuScreen, OptionsMenuScreen, CreditsMenuScreen) contains some buttons. Each button should change the screen.
If I'm on MainMenuScreen and I press "credits", I get the CreeditsMenuScreen. But when I use "back button" to get back in the Main Menu, I get a stackOverflow error.
Here is some parts of the code:
//In the MainMenuScreen.java:
if( creditsButton.isPressed() ) {
menuManager.setScreen("credits");
}
//In the CreditsMenuScreen.java I have
if( backButton.isPressed() ) {
menuManager.setScreen("main");
}
Here is the error. I think it's connected to the touchevent but I don't know how to fix it..
Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: java.lang.StackOverflowError
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:133)
Caused by: java.lang.StackOverflowError
at org.lwjgl.BufferChecks.checkDirect(BufferChecks.java:138)
at org.lwjgl.opengl.GL20.glVertexAttribPointer(GL20.java:856)
at com.badlogic.gdx.backends.lwjgl.LwjglGL20.glVertexAttribPointer(LwjglGL20.java:829)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.setVertexAttribute(ShaderProgram.java:657)
at com.badlogic.gdx.graphics.glutils.VertexArray.bind(VertexArray.java:115)
at com.badlogic.gdx.graphics.Mesh.bind(Mesh.java:380)
at com.badlogic.gdx.graphics.Mesh.bind(Mesh.java:371)
at com.badlogic.gdx.graphics.Mesh.render(Mesh.java:479)
at com.badlogic.gdx.graphics.Mesh.render(Mesh.java:449)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.flush(SpriteBatch.java:975)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.setTransformMatrix(SpriteBatch.java:1037)
at com.badlogic.gdx.scenes.scene2d.Group.resetTransform(Group.java:210)
at com.badlogic.gdx.scenes.scene2d.Group.draw(Group.java:58)
at com.badlogic.gdx.scenes.scene2d.Stage.draw(Stage.java:128)
at com.rander.GameMenu.MainMenuScreen.show(MainMenuScreen.java:86)
at com.badlogic.gdx.Game.setScreen(Game.java:61)
at com.rander.GameMenu.MenuManager.setScreen(MenuManager.java:44)
at com.rander.GameMenu.CreditsMenuScreen.show(CreditsMenuScreen.java:74)
When you switch from one screen back to the the other, the other one has not had update() called on it since it last called setScreen() in response to its button press, so its button is still pressed. So the screens will keep switching back and forth because both buttons are in pressed state and never get an opportunity to release.
Instead of using isPressed(), add a ChangeListener on each button, and in the listener, override public void changed (ChangeEvent event, Actor actor) and change the screen there. Like this:
/// in screen constructor
creditsButton.addListener(new ChangeListener(){
public void changed (ChangeEvent event, Actor actor){
menuManager.setScreen("credits");
}
});
I solved the problem (I added the super.render() in the render method) but now, every screen is getting flicking when the mouse is moving in the window.
Here is the MenuManager class:
public class MenuManager {
private static MenuManager uniqueInstance;
HashMap<String, Screen> menuMap;
Game game;
private MenuManager(Game game) {
this.game = game;
menuMap = new HashMap<String, Screen>();
}
public static MenuManager getInstance(Game game) {
if(uniqueInstance == null) {
uniqueInstance = new MenuManager(game);
}
return uniqueInstance;
}
public void addMenuItem(String type, Screen screen) {
menuMap.put(type, screen);
}
public void removeMenuItem(String type) {
Screen remove = menuMap.remove(type);
}
public Screen getScreen(String type) {
return menuMap.get(type);
}
public void setScreen(String type) {
game.setScreen(getScreen(type));
}
}
And here is the main class:
public class TestGame extends Game {
MenuManager menuManager;
Screen mainMenuScreen;
Screen creditsMenuScreen;
Screen optionsMenuScreen;
#Override
public void create() {
Gdx.graphics.setContinuousRendering(false);
menuManager = MenuManager.getInstance(this);
mainMenuScreen = new MainMenuScreen(menuManager);
creditsMenuScreen = new CreditsMenuScreen(menuManager);
optionsMenuScreen = new OptionsMenuScreen(menuManager);
menuManager.addMenuItem("main", mainMenuScreen);
menuManager.addMenuItem("credits", creditsMenuScreen);
menuManager.addMenuItem("options", optionsMenuScreen);
//Gdx.gl.glClearColor(0, 0, 0, 0);
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
setScreen(menuManager.getScreen("main"));
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
}
#Override
public void render () {
super.render(); //important!
}
#Override
public void pause() {
//super.pause();
}
#Override
public void resume() {
//super.resume();
}
#Override
public void dispose () {
super.dispose();
}
}

Java - KeyListener not Working/Mouse Position Not Read

So I have a button that when pressed needs to write the current mouse position out to a text box until the user presses shift, then it stops and leaves the most recent mouse position as the final text in the text box. Heres what I have done:
First a created the following class.
public class KeyListener extends KeyAdapter {
private boolean wasPressed = false;
private int keyCode;
public KeyListener(int keyCode) {
this.keyCode = keyCode;
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("CALLED");
if(e.getKeyCode() == keyCode)
wasPressed = true;
}
public void setState(boolean state) {
wasPressed = state;
}
public boolean getState() {
return wasPressed;
}
}
Then in my "main" class I have the following code.
JButton track1 = new JButton("Track");
KeyListener kl = new KeyListener(KeyEvent.VK_SHIFT);
...
public DisplayFrame() {
this.addKeyListener(kl);
track1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
kl.setState(false);
while(!kl.getState()) {
Point p = MouseInfo.getPointerInfo().getLocation();
topLeft.setText(p.getX() + "," + p.getY());
}
}
});
}
I then of course added the text box to a JPanel and it's displaying everything correctly, however, when I click the Track button nothing happens. I can tell that it is entering the loop, but no text is displayed in the textbox and pressing shift doesn't break the loop.
Try to make a new thread within the actionPerformed method like this:
Thread exampleThread = new Thread() {
public void run() {
//Do your actions within the new thread
}
};
//After the thread is made, we start it.
exampleThread.start();
You have to do this because the actionListener runs in a different thread.

MouseListener and KeyListener used at the same time

How do I use MouseListener and KeyListener at the same time?
For example, how to do something like this
public void keyPressed( KeyEvent e){
// If the mouse button is clicked while any key is held down, print the key
}
Use a boolean value for whether a mouse button is held down, and then update that variable in a MouseListener.
boolean buttonDown = false;
public class ExampleListener implements MouseListener {
public void mousePressed(MouseEvent e) {
buttonDown = true;
}
public void mouseReleased(MouseEvent e) {
buttonDown = false;
}
//Other implemented methods unimportant to this post...
}
Then, in your KeyListener class, just test the buttonDown variable.
Try creating a boolean isKeyPressed. In keyPressed, set it to true and in keyReleased set it to false. Then, when the mouse is clicked, first check if isKeyPressed is true.
You could try checking the state of the KeyEvent modifiers, for example...
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
int mods = e.getModifiers();
System.out.println(mods);
if ((mods & KeyEvent.BUTTON1_MASK) != 0) {
System.out.println("Button1 down");
}
}
});
I should also point out, you can do...
int ext = e.getModifiersEx();
if ((ext & KeyEvent.BUTTON1_DOWN_MASK) != 0) {
System.out.println("Button1_down_mask");
}
Which, as I've just discovered, produces results for other mouse buttons...

Libgdx Mouse just clicked

I'm trying to get when the mouse just clicked, not when the mouse is pressed.
I mean I use a code in a loop and if I detect if the mouse is pressed the code will execute a lot of time, but I want execute the code only Once, when the mouse has just clicked.
This is my code :
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
//Some stuff
}
See http://code.google.com/p/libgdx/wiki/InputEvent - you need to handle input events instead of polling, by extending InputProcessor and passing your custom input processor to Gdx.input.setInputProcessor().
EDIT:
public class MyInputProcessor implements InputProcessor {
#Override
public boolean touchDown (int x, int y, int pointer, int button) {
if (button == Input.Buttons.LEFT) {
// Some stuff
return true;
}
return false;
}
}
And wherever you want to use that:
MyInputProcessor inputProcessor = new MyInputProcessor();
Gdx.input.setInputProcessor(inputProcessor);
If find it easier to use this pattern:
class AwesomeGameClass {
public void init() {
Gdx.input.setInputProcessor(new InputProcessor() {
#Override
public boolean TouchDown(int x, int y, int pointer, int button) {
if (button == Input.Buttons.LEFT) {
onMouseDown();
return true;
}
return false
}
... the other implementations for InputProcessor go here, if you're using Eclipse or Intellij they'll add them in automatically ...
});
}
private void onMouseDown() {
}
}
You can use Gdx.input.justTouched(), which is true in the first frame where the mouse is clicked. Or, as the other answer states, you can use an InputProcessor (or InputAdapter) and handle the touchDown event:
Gdx.input.setInputProcessor(new InputAdapter() {
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if (button == Buttons.LEFT) {
// do something
}
}
});
Without InputProcessor you can use easy like this in your render loop:
#Override
public void render(float delta) {
if(Gdx.input.isButtonJustPressed(Input.Buttons.LEFT)){
//TODO:
}
}

Categories