kotlin-graphics/imgui

LibGDX - Keyboard not working (inputText, isKeyDown)

Opened this issue · 4 comments

I am using LibGDX and this ImGUI library to create a hierarchy system for my level editor.
I have created an add gameobject button to add new gameobject nodes to the hierarchy using the name given.

However, the inputtext call for the Hierarchy's add gameobject button creates what appears to be readonly text.

I think it's not readonly though, because imgui also doesnt seem to see the keydown events
without the textbox.

Here's part of the code that demonstrates my issue.

`
////// LOOK HERE
////////////////////////////////////////////////////////////////////////////////////////////////////

    if (imgui.isKeyDown(Keys.Z))
    {
    	// So if Z is pressed and imgui sees this, it should show the demo window while Z is pressed.
        imgui.showDemoWindow(new boolean[]{true});
        
        // When pressing Z or not pressing Z, the demo window never opens.
        // So, I believe imgui never sees that I am pressing Z.
    }
    
    
 // ^// ^// ^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ 
 // |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |
 // |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |
 // |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |          
    `

There was an earlier related issue, but it didn't involve libgdx and it wasn't pure java.
So, this is why I am posting this new issue.

..............................................Below is the full code....................................................

`package com.shadowtools;

import java.util.ArrayList;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g3d.;
import com.badlogic.gdx.graphics.g3d.attributes.
;
import com.badlogic.gdx.graphics.g3d.environment.;
import com.badlogic.gdx.graphics.g3d.loader.
;
import com.badlogic.gdx.math.;
import com.badlogic.gdx.utils.
;
import com.badlogic.gdx.graphics.*;

import imgui.Context;
import imgui.ImGui;
import imgui.InputTextFlag;
import imgui.Key;
import imgui.WindowFlag;
import imgui.impl.ImplGL3;
import imgui.impl.LwjglGlfw;
import uno.glfw.GlfwWindow;

public class ShadowTools extends ApplicationAdapter {
private PerspectiveCamera camera;
private ModelBatch modelBatch;
private G3dModelLoader modelLoader;
private UBJsonReader jsonReader;
private Model box;
private ModelInstance modelInstance;
private Environment environment;
private float CamRotX, CamRotY = 0;
private float FillIntensity = 0.8f;
private float KeyIntensity = 0.175f;
private LwjglGlfw lwjglGlfw = LwjglGlfw.INSTANCE;
private ImplGL3 lwjglGL3 = ImplGL3.INSTANCE;
private ImGui imgui = ImGui.INSTANCE;
private MeshNode MeshList;
private MeshNode MoveFrom;
private MeshNode MoveTo;
private int iMoveFrom;
private Boolean bMoveFrom = false;

private Context ctx;

public void ResetCamera()
{
	camera = new PerspectiveCamera(80, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
	camera.position.set(0, 0, 0);
	camera.lookAt(camera.position.x, camera.position.y, camera.position.z + -1);
	camera.near = 0.01f;
	camera.far = 10000;
}

class MeshNode
{
	public ArrayList<MeshNode> children = new ArrayList<MeshNode>();
	public String name = "";
	public Boolean IsSelected = false;
};

void AddMeshes()
{
	MeshNode m1 = new MeshNode();
	m1.name = "CheckeredBG";
	MeshNode m2 = new MeshNode();
	m2.name = "RedSquare";
	m1.children.add(m2);
	MeshNode m3 = new MeshNode();
	m3.name = "BlueSquare";
	m1.children.add(m3);
	MeshNode m4 = new MeshNode();
	m4.name = "PlayerController";
	MeshNode m5 = new MeshNode();
	m5.name = "Camera";
	m4.children.add(m5);
	MeshList.children.add(m1);
	MeshList.children.add(m4);
}

@Override
public void create () 
{
    ctx = new Context();

    Lwjgl3Graphics lwjgl3Graphics = (Lwjgl3Graphics) Gdx.graphics;
    long windowHandle = lwjgl3Graphics.getWindow().getWindowHandle();
    lwjglGlfw.init(new GlfwWindow(windowHandle), true, LwjglGlfw.GlfwClientApi.OpenGL);
    
    MeshList = new MeshNode();
	AddMeshes();
    
	ResetCamera();
	
	modelBatch = new ModelBatch();
			
	jsonReader = new UBJsonReader();
	modelLoader = new G3dModelLoader(jsonReader);
    box = modelLoader.loadModel(Gdx.files.getFileHandle("walking_3.g3db", Files.FileType.Internal));
	modelInstance = new ModelInstance(box, 0, 0, -5);

	//Gdx.input.setCursorCatched(true);
}

MeshNode Hierarchy(MeshNode P)
{
	return Hierarchy(P, 0);
}

char[] Name = "GameObject".toCharArray();

MeshNode Hierarchy(MeshNode P, int depth)
{
	if (Name.length <= 0)
	{
		Name = "GameObject".toCharArray();
	}
	if (P.children.size() > 0)
	{
		int c = 0;
		int k = 0;
		while (k < P.children.size())
		{
			if (P.children.get(k).IsSelected)
			{
				c++;
			}
			k++;
		}
		if (c != 1)
		{
			int w = 0;
			while (w < P.children.size())
			{
				P.children.get(w).IsSelected = false;
				if (w == 0)
				{
					P.children.get(w).IsSelected = true;
				}
				w++;
			}
		}
	}

	imgui.pushItemWidth(-1);
	imgui.inputText("Add" + depth, Name, InputTextFlag.None.getI());
	imgui.popItemWidth();
    
	if (imgui.smallButton("Add GameObject #" + depth))
	{
		int j = 0;
		while (j < P.children.size())
		{
			P.children.get(j).IsSelected = false;
			j++;
		}
		MeshNode M = new MeshNode();
		M.name = new String(Name);
		M.IsSelected = true;
		P.children.add(M);
		Name = "GameObject".toCharArray();
	}
	if (imgui.smallButton("Delete GameObject #" + depth))
	{
		int i = 0;
		while (i < P.children.size())
		{
			if (P.children.get(i).IsSelected)
			{
				P.children.remove(0);
			}
			i++;
		}
		Name = "GameObject".toCharArray();
	}
	if (imgui.smallButton("Move Up #" + depth))
	{
		int i = 0;
		while (i < P.children.size())
		{
			if (P.children.get(i).IsSelected)
			{
				if (i > 0)
				{
					MoveFrom = P.children.get(i);
					iMoveFrom = i;
					P.children.remove(0 + iMoveFrom);
					bMoveFrom = true;
				}
			}
			i++;
		}
		if (bMoveFrom)
		{
			P.children.add(iMoveFrom - 1, MoveFrom);
			bMoveFrom = false;
		}
		Name = "GameObject".toCharArray();
	}
	if (imgui.smallButton("Move Down #" + depth))
	{
		int i = 0;
		while (i < P.children.size())
		{
			if (P.children.get(i).IsSelected)
			{
				if (i < P.children.size() - 1)
				{
					MoveFrom = P.children.get(i);
					iMoveFrom = i;
					P.children.remove(iMoveFrom);
					bMoveFrom = true;
				}
			}
			i++;
		}
		if (bMoveFrom)
		{
			P.children.add(iMoveFrom + 1, MoveFrom);
			bMoveFrom = false;
		}
		Name = "GameObject".toCharArray();
	}
	if (imgui.smallButton("Move From #" + depth))
	{
		int i = 0;
		while (i < P.children.size())
		{
			if (P.children.get(i).IsSelected)
			{
				MoveFrom = P.children.get(i);
				iMoveFrom = i;
				P.children.remove(iMoveFrom);
				bMoveFrom = true;
			}
			i++;
		}
		Name = "GameObject".toCharArray();
	}
	if (imgui.smallButton("Move To #" + depth))
	{
		if (bMoveFrom)
		{
			P.children.add(MoveFrom);
			bMoveFrom = false;
		}
		Name = "GameObject".toCharArray();
	}
	imgui.pushItemWidth(-1);
	int i = 0;
	while (i < P.children.size())
	{
		String item_name = P.children.get(i).name;
		if (imgui.checkbox(item_name, new boolean[] {P.children.get(i).IsSelected}))
		{
			int j = 0;
			while (j < P.children.size())
			{
				P.children.get(j).IsSelected = false;
				j++;
			}
			P.children.get(i).IsSelected = true;
			Name = "GameObject".toCharArray();
		}
		i++;
	}
	imgui.popItemWidth();
	i = 0;
	while (i < P.children.size())
	{
		if (P.children.get(i).IsSelected)
		{
			imgui.indent(20);
			imgui.newLine();
			imgui.text("Children of '" + P.children.get(i).name + "'");
			P.children.set(i, Hierarchy(P.children.get(i), depth + 1));
		}
		i++;
	}
	return P;
}

@Override
public void render () 
{		
	Vector3 CamPos = camera.position;
	ResetCamera();
	float dt = Gdx.graphics.getDeltaTime();
	camera.position.set(CamPos);
	CamRotX += Gdx.input.getDeltaX();
	CamRotY += Gdx.input.getDeltaY();
	float CamLimit = 80;
	if (CamRotY > CamLimit)
	{
		CamRotY = CamLimit;
	}
	if (CamRotY < CamLimit * -1.0f)
	{
		CamRotY = CamLimit * -1.0f;
	}
	Quaternion q = new Quaternion();
	q.setEulerAngles(CamRotX * -1.0f, CamRotY * -1.0f, 0);
	camera.rotate(q);
	float speed = 10;
	Vector3 forward = new Vector3(camera.direction.x, 0, camera.direction.z).nor();
	Vector3 up = new Vector3(0, 1, 0).nor();
	Vector3 right = new Vector3(forward.x, forward.y, forward.z).crs(new Vector3(up.x, up.y, up.z)).nor();
    environment = new Environment();
    environment.set(new ColorAttribute(ColorAttribute.AmbientLight, FillIntensity, FillIntensity, FillIntensity, 1));
    environment.set(new ColorAttribute(ColorAttribute.Diffuse));
    environment.set(new ColorAttribute(ColorAttribute.Specular));
    environment.set(new ColorAttribute(ColorAttribute.Reflection));
    DirectionalLight Key = new DirectionalLight().set(KeyIntensity, KeyIntensity, KeyIntensity, 0, 0, 0);
    Vector3 rightKey = new Vector3(right.x, right.y, right.z);
    rightKey.scl(-1.5f);
    Vector3 upKey = new Vector3(up.x, up.y, up.z);
    upKey.scl(-1.0f);
    Vector3 forwardKey = new Vector3(forward.x, forward.y, forward.z);
    forwardKey.scl(1.25f);
    Vector3 dirKey = new Vector3(0, 0, 0);
    dirKey.add(forwardKey);
    dirKey.add(upKey);
    dirKey.add(rightKey);        
    Key.direction.set(dirKey);
    environment.add(Key);
	if (Gdx.input.isKeyPressed(Input.Keys.W))
	{
		camera.position.mulAdd(forward, dt * speed);
	}
	if (Gdx.input.isKeyPressed(Input.Keys.S))
	{
		camera.position.mulAdd(forward, dt * speed * -1.0f);
	}
	if (Gdx.input.isKeyPressed(Input.Keys.A))
	{
		camera.position.mulAdd(right, dt * speed * -1.0f);
	}
	if (Gdx.input.isKeyPressed(Input.Keys.D))
	{
		camera.position.mulAdd(right, dt * speed);
	}
	if (Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT))
	{
		camera.position.mulAdd(up, dt * speed * -1.0f);
	}
	if (Gdx.input.isKeyPressed(Input.Keys.SPACE))
	{
		camera.position.mulAdd(up, dt * speed);
	}
	
	Gdx.gl.glClearColor(0, 0, 0, 1);
	Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
	camera.update();
	modelBatch.begin(camera);
	modelBatch.render(modelInstance, environment);
	modelBatch.end();
	
    lwjglGlfw.newFrame();
    
    
    ////// LOOK HERE
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    if (imgui.isKeyDown(Keys.Z))
    {
    	// So if Z is pressed and imgui sees this, it should show the demo window while Z is pressed.
        imgui.showDemoWindow(new boolean[]{true});
        
        // When pressing Z or not pressing Z, the demo window never opens.
        // So, I believe imgui never sees that I am pressing Z.
    }
    
    
 // ^// ^// ^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ //^ 
 // |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |
 // |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |
 // |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |// |          
    

	if (imgui.begin("Hierarchy", new boolean[] {true}, WindowFlag.None.getI()))
	{
		MeshList = Hierarchy(MeshList);
	}
	imgui.end();

    imgui.render();

    if (imgui.getDrawData() != null) {
        lwjglGL3.renderDrawData(imgui.getDrawData());
    }
}

@Override
public void dispose () {
	box.dispose();
	modelBatch.dispose();
}

}
`

Hopefully, someone has a solution.
Thank you so much!

exuvo commented

You need to forward GDX InputProcessor calls to imgui when it has focus.
See either my #104 (comment) or the bottom of https://github.com/exuvo/Aurora-J/blob/master/core/src/se/exuvo/aurora/screens/ImGuiScreen.kt (relevant code around line 1200) for working examples.

I have seen that you have examples of this, but sadly, I don't know Kotlin and I have tried to convert this to java, but I got stuck on the line ImplGlfw.charCallback. I am not using glfw, rather, I am using LWJGL. And, I'm not using LWJGL3 either. So in the implementation I'm using, there is no charCallback. :/

exuvo commented

All charCallback does is if (!imeInProgress) io.addInputCharacter(char)
io refers to imgui.classes.IO.kt from your context ctx.io
imeInProgress is a global boolean from package imgui in helpers.kt

Perfect, thank you! Closing this issue now.