Re-enable alt buffer, currently mouse support works in btop, htop, nano, vim, and nextvi. It does not work in Midnight Commander, but this seems to be an issue with our build of MC.

This commit is contained in:
JacksonAbney
2025-04-13 18:19:32 -08:00
parent f0e4f6a4a9
commit d51840475c
9 changed files with 126 additions and 74 deletions

View File

@@ -21,8 +21,8 @@ import org.joml.Vector2i;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nullable;
import java.io.Console;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@OnlyIn(Dist.CLIENT)
public final class MachineTerminalWidget {
@@ -151,17 +151,44 @@ public final class MachineTerminalWidget {
Vector2i position = getMousePosition(x, y);
boolean overTerminal = isMouseOverTerminal((int)x, (int)y);
if (overTerminal && shouldCaptureInput()) {
if (currentMouseMode.PrimaryMode == PrivateMode.X11MM && !currentMouseMode.isSecondaryModeEnabled(PrivateMode.SGR_MOUSE)) {
terminal.putInput('\033');
terminal.putInput('[');
terminal.putInput('M');
terminal.putInput((byte) (button + 32));
terminal.putInput((byte) (position.x + 32));
terminal.putInput((byte) (position.y + 32));
return true;
} else if (currentMouseMode.PrimaryMode == PrivateMode.X11MM) {
terminal.putInput("\033[<" + button + ";" + position.x + ";" + position.y + "M");
return true;
switch(currentMouseMode.PrimaryMode) {
case PrivateMode.X11MM, PrivateMode.CELL_MOTION_MOUSE -> {
if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.SGR_MOUSE)) {
terminal.putInput("\033[<" + button + ";" + position.x + ";" + position.y + "M");
return true;
}
else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.UTF8_MOUSE))
{
byte[] csiMBytes = "\033[M".getBytes(StandardCharsets.UTF_8);
byte[] buttonBytes = utf8(button + 32);
byte[] colBytes = utf8(position.x + 32);
byte[] rowBytes = utf8(position.y + 32);
byte[] finalBytes = new byte[csiMBytes.length + buttonBytes.length + colBytes.length + rowBytes.length];
System.arraycopy(csiMBytes, 0, finalBytes, 0, csiMBytes.length);
System.arraycopy(buttonBytes, 0, finalBytes, csiMBytes.length, buttonBytes.length);
System.arraycopy(colBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length, colBytes.length);
System.arraycopy(rowBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length + colBytes.length, rowBytes.length);
terminal.putInput(ByteBuffer.wrap(finalBytes));
return true;
}
else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.URXVT_MOUSE))
{
terminal.putInput("\033[" + (button + 32) + ";" + position.x + ";" + position.y + "M");
}
else
{
terminal.putInput('\033');
terminal.putInput('[');
terminal.putInput('M');
terminal.putInput((byte) (button + 32));
terminal.putInput((byte) (position.x + 32));
terminal.putInput((byte) (position.y + 32));
return true;
}
}
default -> System.out.println("ERR: Unsupported primary mode");
}
}
return false;
@@ -173,22 +200,53 @@ public final class MachineTerminalWidget {
Vector2i position = getMousePosition(x, y);
boolean overTerminal = isMouseOverTerminal((int)x, (int)y);
if (overTerminal && shouldCaptureInput()) {
if (currentMouseMode.PrimaryMode == PrivateMode.X11MM && !currentMouseMode.isSecondaryModeEnabled(PrivateMode.SGR_MOUSE)) {
terminal.putInput('\033');
terminal.putInput('[');
terminal.putInput('M');
terminal.putInput((byte) 35);
terminal.putInput((byte) (position.x + 32));
terminal.putInput((byte) (position.y + 32));
return true;
} else if (currentMouseMode.PrimaryMode == PrivateMode.X11MM) {
terminal.putInput("\033[<" + button + ";" + position.x + ";" + position.y + "m");
return true;
switch(currentMouseMode.PrimaryMode) {
case PrivateMode.X11MM, PrivateMode.CELL_MOTION_MOUSE -> {
if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.SGR_MOUSE)) {
terminal.putInput("\033[<" + button + ";" + position.x + ";" + position.y + "m");
return true;
}
else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.UTF8_MOUSE))
{
byte[] csiMBytes = "\033[M".getBytes(StandardCharsets.UTF_8);
byte[] buttonBytes = utf8(35);
byte[] colBytes = utf8(position.x + 32);
byte[] rowBytes = utf8(position.y + 32);
byte[] finalBytes = new byte[csiMBytes.length + buttonBytes.length + colBytes.length + rowBytes.length];
System.arraycopy(csiMBytes, 0, finalBytes, 0, csiMBytes.length);
System.arraycopy(buttonBytes, 0, finalBytes, csiMBytes.length, buttonBytes.length);
System.arraycopy(colBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length, colBytes.length);
System.arraycopy(rowBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length + colBytes.length, rowBytes.length);
terminal.putInput(ByteBuffer.wrap(finalBytes));
return true;
}
else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.URXVT_MOUSE))
{
terminal.putInput("\033[" + 35 + ";" + position.x + ";" + position.y + "M");
}
else
{
terminal.putInput('\033');
terminal.putInput('[');
terminal.putInput('M');
terminal.putInput((byte) 35);
terminal.putInput((byte) (position.x + 32));
terminal.putInput((byte) (position.y + 32));
return true;
}
}
default -> System.out.println("ERR: Unsupported primary mode");
}
}
return false;
}
private byte[] utf8(int value) {
return new String(new int[]{value}, 0, 1).getBytes(StandardCharsets.UTF_8);
}
private Vector2i getMousePosition(double x, double y) {
int tx = TERMINAL_WIDTH / Terminal.WIDTH;
int ty = TERMINAL_HEIGHT / Terminal.HEIGHT;

View File

@@ -42,16 +42,16 @@ public class ImplementedPrivateModes {
modeStatus.put(96, false); // DECNCSM;
modeStatus.put(1000, true); // X11MM;
modeStatus.put(1001, false); // HILITE_MOUSE;
modeStatus.put(1002, false); // CELL_MOTION_MOUSE;
modeStatus.put(1002, true); // CELL_MOTION_MOUSE; -- PARTIAL SUPPORT: Treated as X11MM currently, no motion events are sent. This actually seems to match Window Terminal's level of implementation.
modeStatus.put(1003, false); // ALL_MOTION_MOUSE_TRACKING;
modeStatus.put(1004, true); // FOCUS_IN_FOCUS_OUT;
modeStatus.put(1005, false); // UTF8_MOUSE;
modeStatus.put(1005, true); // UTF8_MOUSE;
modeStatus.put(1006, true); // SGR_MOUSE;
modeStatus.put(1007, false); // ALTERNATE_SCROLL_MODE;
modeStatus.put(1010, false); // SCROLL_BOTTOM_ON_OUTPUT;
modeStatus.put(1011, false); // SCROLL_BOTTOM_ON_KEY_PRESS;
modeStatus.put(1014, false); // FAST_SCROLL;
modeStatus.put(1015, false); // URXVT_MOUSE;
modeStatus.put(1015, true); // URXVT_MOUSE;
modeStatus.put(1016, false); // SGR_MOUSE_PIXEL;
modeStatus.put(1034, false); // META_KEY;
modeStatus.put(1035, false); // SPECIAL_MODIFIERS;
@@ -80,6 +80,7 @@ public class ImplementedPrivateModes {
modeStatus.put(2004, true); // SET_BRACKETED_PASTE;
modeStatus.put(2005, false); // ENABLE_READLINE_CHAR_QUOTE;
modeStatus.put(2006, false); // ENABLE_READLINE_NEWLINE_PASTE;
modeStatus.put(2026, true); // APPLICATION_SYNC;
}
public void modeUsed(int mode, boolean state) {

View File

@@ -74,4 +74,5 @@ public final class PrivateMode {
public static final int SET_BRACKETED_PASTE = 2004; // Set bracketed paste mode
public static final int ENABLE_READLINE_CHAR_QUOTE = 2005; // Enable readline character quoting
public static final int ENABLE_READLINE_NEWLINE_PASTE = 2006; // Enable readline newline pasting
public static final int APPLICATION_SYNC = 2026; // Wait to render until application is ready
}

View File

@@ -79,6 +79,7 @@ public class PrivateModeState {
public boolean SET_BRACKETED_PASTE = false;
public boolean ENABLE_READLINE_CHAR_QUOTE = false;
public boolean ENABLE_READLINE_NEWLINE_PASTE = false;
public boolean APPLICATION_SYNC = false;
public boolean getMode(int mode) {
return switch (mode) {
@@ -154,6 +155,7 @@ public class PrivateModeState {
case 2004 -> SET_BRACKETED_PASTE;
case 2005 -> ENABLE_READLINE_CHAR_QUOTE;
case 2006 -> ENABLE_READLINE_NEWLINE_PASTE;
case 2026 -> APPLICATION_SYNC;
default -> throw new IndexOutOfBoundsException();
};
}

View File

@@ -425,23 +425,17 @@ public class Terminal {
}
}
public static boolean isPrintableCharacter(final int ch) {
return ch == 0 ||
(ch > ' ' && ch <= '~') ||
ch >= 177;
}
public void putOutput(final byte value) {
final char ch = (char) value;
if (!continuationByte && (ch & (1 << 7)) != 0) {
continuationByte = true;
bytesToRead = 0;
bytesRead = 0;
unicode = 0;
if ((ch & (1 << 6)) != 0) {
bytesToRead++;
} else {
continuationByte = false;
bytesToRead = 0;
bytesRead = 0;
System.out.println("ERR: Invalid first byte received");
return;
}
@@ -862,12 +856,6 @@ public class Terminal {
// Renderer
@OnlyIn(Dist.CLIENT)
public static final class Renderer implements RendererModel, RendererView {
public static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/terminus.png");
public static final int TEXTURE_RESOLUTION = 256;
public static final float ONE_OVER_TEXTURE_RESOLUTION = 1.0f / (float) TEXTURE_RESOLUTION;
public static final int TEXTURE_COLUMNS = 16;
public static final int TEXTURE_BOLD_SHIFT = TEXTURE_COLUMNS; // Bold chars are in right half of texture.
public static final int[] COLORS = {
0x555555, // Black
0xEE3322, // Red
@@ -942,15 +930,16 @@ public class Terminal {
@Override
public void render(final PoseStack stack, final Matrix4f projectionMatrix) {
if (terminal.currentPrivateModeState.APPLICATION_SYNC) return;
validateLineCache();
renderBuffer(stack, projectionMatrix);
boolean blink = switch (terminal.cursorMode) {
case 2, 4, 6 -> false;
default -> true;
boolean steady = switch (terminal.cursorMode) {
case 2, 4, 6 -> true;
default -> false;
};
if (!blink || (System.currentTimeMillis() + terminal.hashCode()) % 1000 > 500) {
if (steady || (System.currentTimeMillis() + terminal.hashCode()) % 1000 > 500) {
renderCursor(stack);
}
}
@@ -1062,9 +1051,7 @@ public class Terminal {
final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS;
int background = switch (color.Mode) {
case SIXTEEN_COLOR -> palette[!invertBackground ? color.G : color.R];
case TWO_FIFTY_SIX_COLOR -> {
yield COLORS_256[!invertBackground ? color.G : color.R];
}
case TWO_FIFTY_SIX_COLOR -> COLORS_256[!invertBackground ? color.G : color.R];
case TRUE_COLOR -> color.ToInt();
};
@@ -1143,13 +1130,10 @@ public class Terminal {
}
if ((style & STYLE_UNDERLINE_MASK) != 0) {
final float ulu = (TEXTURE_RESOLUTION - 1) / (float) TEXTURE_RESOLUTION;
final float ulv = 1 / (float) TEXTURE_RESOLUTION;
buffer.vertex(matrix, offset, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).uv(ulu, ulv).endVertex();
buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).uv(ulu, ulv).endVertex();
buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).uv(ulu, ulv).endVertex();
buffer.vertex(matrix, offset, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).uv(ulu, ulv).endVertex();
buffer.vertex(matrix, offset, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).uv(0, 0).endVertex();
buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).uv(0, 0).endVertex();
buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).uv(0, 0).endVertex();
buffer.vertex(matrix, offset, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).uv(0, 0).endVertex();
}
}

View File

@@ -124,6 +124,7 @@ public class RM {
case 2004 -> terminal.currentPrivateModeState.SET_BRACKETED_PASTE = false;
case 2005 -> terminal.currentPrivateModeState.ENABLE_READLINE_CHAR_QUOTE = false;
case 2006 -> terminal.currentPrivateModeState.ENABLE_READLINE_NEWLINE_PASTE = false;
case 2026 -> terminal.currentPrivateModeState.APPLICATION_SYNC = false;
}
ImplementedPrivateModes.instance.modeUsed(args[i], false);

View File

@@ -18,10 +18,7 @@ public class SM {
public static void executeDECSET(Terminal terminal, int[] args, int argCount) {
for (int i = 0; i < argCount; i++) {
switch (args[i]) {
case 1 -> {
System.out.println("Enabled DECCKM");
terminal.currentPrivateModeState.DECCKM = true;
}
case 1 -> terminal.currentPrivateModeState.DECCKM = true;
case 2 -> terminal.currentPrivateModeState.DECANM = true;
case 3 -> terminal.currentPrivateModeState.DECCOLM = true;
case 4 -> terminal.currentPrivateModeState.DECSCLM = true;
@@ -64,9 +61,6 @@ public class SM {
case 45 -> terminal.currentPrivateModeState.XTREVWRAP = true;
case 46 -> terminal.currentPrivateModeState.XTLOGGING = true;
case 47 -> {
if (true) {
break;
}
terminal.clearAlt();
terminal.setCursorPos(0, 0);
terminal.currentPrivateModeState.ALT_BUFFER = true;
@@ -102,14 +96,34 @@ public class SM {
terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = true;
}
case 1004 -> terminal.currentPrivateModeState.FOCUS_IN_FOCUS_OUT = true;
case 1005 -> terminal.currentPrivateModeState.UTF8_MOUSE = true;
case 1006 -> terminal.currentPrivateModeState.SGR_MOUSE = true;
case 1005 -> {
terminal.currentPrivateModeState.SGR_MOUSE = false;
terminal.currentPrivateModeState.URXVT_MOUSE = false;
terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false;
terminal.currentPrivateModeState.UTF8_MOUSE = true;
}
case 1006 -> {
terminal.currentPrivateModeState.UTF8_MOUSE = false;
terminal.currentPrivateModeState.URXVT_MOUSE = false;
terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false;
terminal.currentPrivateModeState.SGR_MOUSE = true;
}
case 1007 -> terminal.currentPrivateModeState.ALTERNATE_SCROLL_MODE = true;
case 1010 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_OUTPUT = true;
case 1011 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS = true;
case 1014 -> terminal.currentPrivateModeState.FAST_SCROLL = true;
case 1015 -> terminal.currentPrivateModeState.URXVT_MOUSE = true;
case 1016 -> terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = true;
case 1015 -> {
terminal.currentPrivateModeState.UTF8_MOUSE = false;
terminal.currentPrivateModeState.SGR_MOUSE = false;
terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false;
terminal.currentPrivateModeState.URXVT_MOUSE = true;
}
case 1016 -> {
terminal.currentPrivateModeState.UTF8_MOUSE = false;
terminal.currentPrivateModeState.SGR_MOUSE = false;
terminal.currentPrivateModeState.URXVT_MOUSE = false;
terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = true;
}
case 1034 -> terminal.currentPrivateModeState.META_KEY = true;
case 1035 -> terminal.currentPrivateModeState.SPECIAL_MODIFIERS = true;
case 1036 -> terminal.currentPrivateModeState.META_SENDS_ESCAPE = true;
@@ -123,9 +137,6 @@ public class SM {
case 1045 -> terminal.currentPrivateModeState.EXT_REV_WRAP = true;
case 1046 -> terminal.currentPrivateModeState.ALLOW_ALT_BUFFER = true;
case 1047 -> {
if (true) {
break;
}
terminal.clearAlt();
terminal.setCursorPos(0, 0);
terminal.currentPrivateModeState.SWITCH_ALT_BUFFER = true;
@@ -137,15 +148,11 @@ public class SM {
terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right));
}
case 1048 -> {
System.out.println("SAVE");
terminal.savedX = terminal.x;
terminal.savedY = terminal.y;
terminal.currentPrivateModeState.SAVE_CURSOR = true;
}
case 1049 -> {
if (true) {
break;
}
terminal.savedX = terminal.x;
terminal.savedY = terminal.y;
terminal.clearAlt();

View File

@@ -4,7 +4,6 @@ import li.cil.oc2.common.vm.terminal.Terminal;
public class DECRC {
public static void execute(Terminal terminal) {
System.out.print("Restored cursor");
terminal.x = terminal.savedX;
terminal.y = terminal.savedY;
}

View File

@@ -4,7 +4,6 @@ import li.cil.oc2.common.vm.terminal.Terminal;
public class DECSC {
public static void execute(Terminal terminal) {
System.out.print("Saved cursor");
terminal.savedX = terminal.x;
terminal.savedY = terminal.y;
}