Skip to content

Commit

Permalink
lcdui: Also serialize inputs and UI routines
Browse files Browse the repository at this point in the history
Now we don't need a bogus "delay" in input polling, as Ratatouille
and Heroes Lore: Wind of Soltia work properly with this improved
serialization.

Canvas' serviceRepaints is probably not accurate yet, as it just
forces a screen redraw to happen without much care for anything
else, but it'll do for now.

Fixes #60 and also resolves the last comment in #38.
  • Loading branch information
AShiningRay committed Feb 21, 2025
1 parent bcf0ce7 commit 3cef9e2
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 44 deletions.
9 changes: 8 additions & 1 deletion src/javax/microedition/lcdui/Canvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,14 @@ public void repaint(int x, int y, int width, int height)
}
}

public void serviceRepaints() { } // repaint() should synchronize itself whenever needed (at least that's the plan).
public void serviceRepaints()
{
// TODO: Flesh this out properly, some games might need it.
if(!isShown() || !isPainting) { return; }

// Right now all this does is force a redraw, no queue consideration is made.
Mobile.getPlatform().flushGraphics(platformImage, 0, 0, width, height);
}

public void setFullScreenMode(boolean mode)
{
Expand Down
4 changes: 2 additions & 2 deletions src/javax/microedition/lcdui/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ public void setCurrent(Displayable next)
isSettingCurrent = true;
try
{
if (current != null) { current.hideNotify(); }
if (current != null) { callSerially(() -> { current.hideNotify(); }); }
Mobile.getPlatform().keyState = 0; // reset keystate
next.showNotify();
callSerially(() -> { next.showNotify(); });
}
finally { isSettingCurrent = false; }
if(next instanceof Alert) { ((Alert) next).setNextScreen(current); }
Expand Down
12 changes: 6 additions & 6 deletions src/javax/microedition/lcdui/Displayable.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void removeCommand(Command cmd)

public void setTitle(String text) { title = text; }

public boolean isShown() { return true; }
public boolean isShown() { return Mobile.getDisplay().getCurrent() == this; }

public Ticker getTicker() { return ticker; }

Expand Down Expand Up @@ -349,14 +349,14 @@ protected void doRightCommand()

protected void _invalidate()
{
// zb3: TODO: consider queuing this
// the code below ensures this function is not reentrant
if (getDisplay().getCurrent() != this) { return; }

if (isValidating)
if (isValidating) // Shouldn't happen, but if it does, treat it like Canvas does and queue this next invalidate for later.
{
Mobile.log(Mobile.LOG_ERROR, Displayable.class.getPackage().getName() + "." + Displayable.class.getSimpleName() + ": " + "Recursive invalidation attempt detected.");
Thread.dumpStack();
Mobile.log(Mobile.LOG_WARNING, Displayable.class.getPackage().getName() + "." + Displayable.class.getSimpleName() + ": " + "Recursive invalidation attempt detected.");
//Thread.dumpStack();
Mobile.getDisplay().callSerially(() -> { _invalidate(); });
return;
}
else
{
Expand Down
55 changes: 20 additions & 35 deletions src/org/recompile/mobile/MobilePlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ public class MobilePlatform
private long elapsedTime = 0;
private long sleepTime = 0;

private long lastEventTime = System.nanoTime();

// Whether the user has toggled the ShowFPS option
private final int OVERLAY_WIDTH = 80;
private final int OVERLAY_HEIGHT = 20;
Expand Down Expand Up @@ -153,34 +151,34 @@ public void resizeLCD(int width, int height)

public void keyPressed(int keycode)
{
updateKeyState(Mobile.getGameAction(keycode), 1);
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.keyPressed(keycode); }
Mobile.getDisplay().callSerially(() -> { updateKeyState(Mobile.getGameAction(keycode), 1); });
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.keyPressed(keycode); }); }
}

public void keyReleased(int keycode)
{
updateKeyState(Mobile.getGameAction(keycode), 0);
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.keyReleased(keycode); }
Mobile.getDisplay().callSerially(() -> {updateKeyState(Mobile.getGameAction(keycode), 0); });
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.keyReleased(keycode); }); }
}

public void keyRepeated(int keycode)
{
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.keyRepeated(keycode); }
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.keyRepeated(keycode); }); }
}

public void pointerDragged(int x, int y)
{
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.pointerDragged(x, y); }
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.pointerDragged(x, y); }); }
}

public void pointerPressed(int x, int y)
{
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.pointerPressed(x, y); }
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.pointerPressed(x, y); }); }
}

public void pointerReleased(int x, int y)
{
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.pointerReleased(x, y); }
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.pointerReleased(x, y); }); }
}

private void updateKeyState(int key, int val)
Expand Down Expand Up @@ -327,33 +325,20 @@ public final void processInputs()

for(int i = 0; i < pressedKeys.length; i++)
{
/*
* We'll poll new inputs 1000 times per second, any inputs done in a smaller interval
* will be ignored. This is actually a workaround for games that don't work well with a
* JVM spanning multiple cores (e.g. Some versions of Ratatouille) which can result in
* the input thread being locked sending many commands during transitions, commands
* that the game will then have to process in its own time, making it seem like it's not
* responding to inputs.
*/
if(lastEventTime - System.nanoTime() < -1_000_000)
if(pressedKeys[i] == true && previouslyPressed[i] == false)
{
if(pressedKeys[i] == true && previouslyPressed[i] == false)
{
lastEventTime = System.nanoTime();
keyPressed(Mobile.getMobileKey(i));
previouslyPressed[i] = true;
}
else if(pressedKeys[i] == true && previouslyPressed[i] == true)
{
keyRepeated(Mobile.getMobileKey(i));
}
else if (pressedKeys[i] == false && previouslyPressed[i] == true)
{
keyReleased(Mobile.getMobileKey(i));
previouslyPressed[i] = false;
}
keyPressed(Mobile.getMobileKey(i));
previouslyPressed[i] = true;
}
else if(pressedKeys[i] == true && previouslyPressed[i] == true)
{
keyRepeated(Mobile.getMobileKey(i));
}
else if (pressedKeys[i] == false && previouslyPressed[i] == true)
{
keyReleased(Mobile.getMobileKey(i));
previouslyPressed[i] = false;
}

}
}

Expand Down

0 comments on commit 3cef9e2

Please sign in to comment.