From f2062cd2d6cc69eb88864bfd0f61a3f97ac00958 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:11:19 +0200 Subject: [PATCH 1/2] Simulator: draw the native editor where the panned field is In the simulated keyboard's Android pan mode the native editor's bounds are raised by the pan offset, and the screen raster it is painted into is raised by the same offset again when it is composed, so typed text appeared one pan offset above the field, over unrelated content. Paint the editor lowered by the offset into the raster and clip it out of the regular children pass; its bounds, and so its hit area, stay where the field is drawn. Co-Authored-By: Claude Opus 5.5 --- .../com/codename1/impl/javase/JavaSEPort.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java b/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java index 54b7db38f0f..c6f44ad52ea 100644 --- a/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java +++ b/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java @@ -4494,6 +4494,38 @@ public void blit(int x, int y, int w, int h) { protected void paintChildren(java.awt.Graphics g) { } + /// Paints the Swing children into the screen raster. In the simulated + /// keyboard's Android pan mode the native editor's bounds are raised by the + /// pan offset, so that it sits, and takes clicks, where the panned field is + /// drawn rather than under the keyboard. The raster itself is raised by that + /// same offset when it is composed (composeSimulatorOverlays), so painting the + /// editor at its bounds here raised it twice and the typed text appeared a + /// pan offset above the field. The editor is therefore painted lowered by the + /// offset, and clipped out of the regular pass. + private void paintChildrenIntoBuffer(Graphics2D bg) { + int pan = this == canvas ? simulatorPanOffset() : 0; + JComponent editor = textCmp; + if (pan == 0 || editor == null || editor.getParent() != this || !editor.isVisible()) { + super.paintChildren(bg); + return; + } + Rectangle eb = editor.getBounds(); + java.awt.Shape oldClip = bg.getClip(); + java.awt.geom.Area rest = new java.awt.geom.Area(oldClip != null ? oldClip + : new Rectangle(0, 0, getWidth(), getHeight())); + rest.subtract(new java.awt.geom.Area(eb)); + bg.setClip(rest); + super.paintChildren(bg); + bg.setClip(oldClip); + int shift = (int) Math.round(pan * zoomLevel); + Graphics2D eg = (Graphics2D) bg.create(eb.x, eb.y + shift, eb.width, eb.height); + try { + editor.paint(eg); + } finally { + eg.dispose(); + } + } + private boolean drawScreenBuffer(java.awt.Graphics g) { if (buffer == null) { return false; @@ -4523,11 +4555,11 @@ private boolean drawScreenBuffer(java.awt.Graphics g) { AffineTransform af = bg.getTransform(); bg.setTransform(AffineTransform.getScaleInstance(1, 1)); bg.translate(-(screenCoord.x + x )* zoomLevel, -(screenCoord.y + y ) * zoomLevel); - super.paintChildren(bg); + paintChildrenIntoBuffer(bg); bg.setTransform(af); } else { bg.translate(-screenCoord.x - x, -screenCoord.y - y); - super.paintChildren(bg); + paintChildrenIntoBuffer(bg); } bg.dispose(); painted = true; From 8a1de820036d6ad9c595324d0fa21a9226d74651 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:17:11 +0200 Subject: [PATCH 2/2] Simulator: refresh the editor bounds when the pan offset changes The editor's bounds are recomputed only when it repaints, so the frame after the keyboard opened, after Next moved to another field or after the keyboard hid drew it from bounds made for the previous offset. Raise the initial bounds by the offset too, and repaint the editor whenever the offset changes. Co-Authored-By: Claude Opus 5.5 --- .../src/com/codename1/impl/javase/JavaSEPort.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java b/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java index c6f44ad52ea..19ad187b7e8 100644 --- a/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java +++ b/Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java @@ -12974,6 +12974,18 @@ public void setResizeInset(int pixels) { } public void setPanOffset(int pixels) { + // The editor's bounds carry the pan offset (paintChildrenIntoBuffer + // relies on that), but they are only recomputed when the editor + // repaints. Ask it to now, so the frame after a pan change does not + // draw it from bounds made for the previous offset. + EventQueue.invokeLater(new Runnable() { + public void run() { + JComponent editor = textCmp; + if (editor != null && editor.getParent() != null) { + editor.repaint(); + } + } + }); requestOverlayRepaint(); } @@ -13547,7 +13559,7 @@ public void keyReleased(KeyEvent e) { int marginBottom = cmp.getSelectedStyle().getPadding(Component.BOTTOM); if (getSkin() != null) { textCmp.setBounds((int) ((cmp.getAbsoluteX() + cmp.getScrollX() + getScreenCoordinates().x + canvas.x + marginLeft) * zoomLevel), - (int) ((cmp.getAbsoluteY() + cmp.getScrollY() + getScreenCoordinates().y + canvas.y + marginTop) * zoomLevel), + (int) ((cmp.getAbsoluteY() + cmp.getScrollY() + getScreenCoordinates().y + canvas.y + marginTop - simulatorPanOffset()) * zoomLevel), (int) ((cmp.getWidth() - marginLeft - marginRight) * zoomLevel), (int) ((cmp.getHeight() - marginTop - marginBottom)* zoomLevel)); //System.out.println("Set bounds to "+textCmp.getBounds());