Shared text clipboard via VMware backdoor + W95TOOLS.EXE guest agent (#361)

Three layers:

  v86 — src/vmware.js gains the legacy text-clipboard backdoor commands
  (GETSELLENGTH/GETNEXTPIECE/SETSELLENGTH/SETNEXTPIECE, 6–9). The host
  stages bytes via the vmware-clipboard-host bus event; the guest pushes
  via 8/9 and the device emits vmware-clipboard-guest when the buffer
  fills. Same wire protocol as open-vm-tools' pre-RPC copy/paste.
  Committed on the windows95-base fork branch; libv86.js rebuilt here.

  renderer — src/renderer/clipboard.ts polls Electron's clipboard (no
  change event exists), translates host UTF-8/LF ↔ guest CP-1252/CRLF,
  and bounces bytes through the two bus events. Echo-suppressed so a
  value we just wrote does not come back as a change.

  guest — guest-tools/agent/W95TOOLS.EXE is a 22 KB hidden-window agent
  that joins the Win32 clipboard-viewer chain (push-on-copy) and polls
  the backdoor on a 250 ms timer (pull-from-host). Win9x runs ring-3
  with the I/O bitmap wide open, so a plain IN EAX,DX from a user
  process reaches the port — no driver needed. Named for growth: time
  sync and host-initiated shutdown will live here too. Built with Open
  Watcom v2 inside Docker (Makefile + Dockerfile alongside the source);
  subsystem 4.0, no msvcrt, runs on Win95 RTM.

Install: copy \\HOST\TOOLS\agent\W95TOOLS.EXE into the guest and drop a
shortcut in StartUp. Text only, 64 KB cap.
This commit is contained in:
Felix Rieseberg
2026-04-11 20:17:06 -07:00
committed by GitHub
parent 6e73df11ae
commit bc76e9c79a
9 changed files with 322 additions and 10 deletions

View File

@@ -35,11 +35,13 @@ That branch merges four feature branches, each upstreamable on its own:
writes to target only `current_interface`, but per ATA spec they're writes to target only `current_interface`, but per ATA spec they're
channel-shared (one register file on the IDE cable; both drives latch channel-shared (one register file on the IDE cable; both drives latch
the same value). the same value).
- **`vmware-abspointer`** — `src/vmware.js` implements the VMware mouse - **`vmware-abspointer`** — `src/vmware.js` implements the VMware
backdoor (port `0x5658`, GETVERSION + ABSPOINTER_*) so a guest driver backdoor (port `0x5658`): GETVERSION + ABSPOINTER_* so a guest driver
(VBADOS VBMOUSE) can read absolute cursor position and track the host (VBADOS VBMOUSE) can read absolute cursor position and track the host
cursor 1:1 without pointer lock. Consumes the `mouse-absolute` bus cursor 1:1 without pointer lock, and the legacy text-clipboard commands
event that `MouseAdapter` already emits. 69 so `W95TOOLS.EXE` (guest-tools/agent) can sync `CF_TEXT` with
the host. Consumes `mouse-absolute` and `vmware-clipboard-host` bus
events; emits `vmware-absolute-mouse` and `vmware-clipboard-guest`.
- **`vga-defer-vbe-disable-v86`** — `src/vga.js` defers `dispi[4]=0` - **`vga-defer-vbe-disable-v86`** — `src/vga.js` defers `dispi[4]=0`
written from V86 mode until a legacy attribute-mode write reaches the written from V86 mode until a legacy attribute-mode write reaches the
hardware. Win9x's VDD virtualises ports 3B03DF for a windowed DOS VM hardware. Win9x's VDD virtualises ports 3B03DF for a windowed DOS VM

View File

@@ -21,3 +21,23 @@ Install inside the guest:
absolute mouse driver**. absolute mouse driver**.
3. Reboot. The app detects the driver and stops grabbing pointer lock; 3. Reboot. The app detects the driver and stops grabbing pointer lock;
ESC still toggles lock for games that want raw relative input. ESC still toggles lock for games that want raw relative input.
## agent/ — W95TOOLS guest agent
`W95TOOLS.EXE` is a hidden-window agent that talks to the emulator over
the VMware backdoor (port 0x5658). Currently it does one thing: bridges
Windows 95's `CF_TEXT` clipboard to the host (legacy backdoor commands
69; host side is `src/renderer/clipboard.ts`, which polls Electron's
clipboard). It's also where time sync, host-initiated shutdown, and a
tray icon will live when those land.
Install inside the guest:
1. Copy `\\HOST\TOOLS\agent\W95TOOLS.EXE` to `C:\WINDOWS\`.
2. Drop a shortcut to it in
`C:\WINDOWS\Start Menu\Programs\StartUp` so it runs on login.
Copy text on either side and it appears on the other within ~250 ms.
Text only; conversion is Windows-1252 ↔ UTF-8 with CRLF ↔ LF, capped at
64 KB. Built from `w95tools.c` with Open Watcom v2 — `make -C
guest-tools/agent` (needs Docker).

View File

@@ -0,0 +1,12 @@
FROM --platform=linux/amd64 debian:bookworm-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends curl xz-utils ca-certificates make && \
rm -rf /var/lib/apt/lists/*
RUN mkdir -p /opt/watcom && \
curl -fsSL https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz \
| tar -xJ -C /opt/watcom
ENV WATCOM=/opt/watcom
ENV PATH=$WATCOM/binl64:$PATH
ENV INCLUDE=$WATCOM/h:$WATCOM/h/nt
ENV LIB=$WATCOM/lib386:$WATCOM/lib386/nt
WORKDIR /work

View File

@@ -0,0 +1,30 @@
# Build W95TOOLS.EXE for Windows 95 with Open Watcom v2, inside Docker.
#
# Watcom is the only readily-available cross-compiler that emits a PE binary
# Win95 RTM will load (subsystem 4.0, no msvcrt). mingw-w64 targets NT. The
# macOS-native Watcom binaries are unsigned and Gatekeeper kills them, so we
# run the linux/amd64 build under Docker instead.
IMAGE := windows95-ow2
# Docker Desktop's bind-mount file sync races with recently-edited files; work
# around it by piping the source on stdin and building in /tmp inside the
# container, then dumping the EXE bytes back over stdout.
DOCKER := docker run --rm -i --platform linux/amd64 $(IMAGE)
CFLAGS := -bt=nt -3r -zq -wx -we -os -s
.PHONY: all image clean
all: W95TOOLS.EXE
image:
docker build --platform linux/amd64 -t $(IMAGE) .
W95TOOLS.EXE: w95tools.c image
$(DOCKER) sh -c 'cd /tmp && cat >w95tools.c && \
wcc386 $(CFLAGS) w95tools.c && \
wlink system nt_win option quiet name W95TOOLS.EXE \
file w95tools.o library kernel32,user32 && \
cat W95TOOLS.EXE' <w95tools.c >$@
clean:
rm -f W95TOOLS.EXE

Binary file not shown.

View File

@@ -0,0 +1,181 @@
/*
* W95TOOLS — guest-side integration agent for the windows95 emulator.
*
* Currently: bidirectional text clipboard. Talks to the emulator over the
* legacy VMware backdoor (port 0x5658; implemented in v86's vmware.js).
* Joins the Win32 clipboard-viewer chain so guest copies are pushed
* immediately, and polls the backdoor on a timer so host copies show up
* within ~250 ms.
*
* Win9x runs ring-3 code with the I/O bitmap wide open, so a plain IN works
* from a user process — no driver needed. On NT this would #GP; we don't run
* there.
*
* Build with Open Watcom v2 (see Makefile). Links USER32/KERNEL32 only,
* runs on Win95 RTM.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define VMW_MAGIC 0x564D5868UL
#define VMW_PORT 0x5658
#define CMD_GETLEN 6
#define CMD_GETDATA 7
#define CMD_SETLEN 8
#define CMD_SETDATA 9
#define CMD_VERSION 10
#define POLL_MS 250
#define MAX_CLIP 0xFFFF
extern unsigned long bd(unsigned long cmd, unsigned long arg);
#pragma aux bd = \
"mov eax, 564D5868h" \
"mov edx, 5658h" \
"in eax, dx" \
parm [ecx] [ebx] \
value [eax] \
modify [edx];
extern unsigned long bd_ebx(unsigned long cmd, unsigned long arg);
#pragma aux bd_ebx = \
"mov eax, 564D5868h" \
"mov edx, 5658h" \
"in eax, dx" \
parm [ecx] [ebx] \
value [ebx] \
modify [eax edx];
static HWND g_next;
static int g_ignore;
static void push_to_host(HWND hwnd)
{
HANDLE h;
char *p;
unsigned long len, i, w;
if (!IsClipboardFormatAvailable(CF_TEXT)) {
bd(CMD_SETLEN, 0);
return;
}
if (!OpenClipboard(hwnd)) return;
h = GetClipboardData(CF_TEXT);
if (h && (p = (char *)GlobalLock(h)) != 0) {
len = lstrlen(p);
if (len > MAX_CLIP) len = MAX_CLIP;
bd(CMD_SETLEN, len);
for (i = 0; i < len; i += 4) {
w = (unsigned char)p[i];
if (i + 1 < len) w |= (unsigned long)(unsigned char)p[i+1] << 8;
if (i + 2 < len) w |= (unsigned long)(unsigned char)p[i+2] << 16;
if (i + 3 < len) w |= (unsigned long)(unsigned char)p[i+3] << 24;
bd(CMD_SETDATA, w);
}
GlobalUnlock(h);
}
CloseClipboard();
}
static void pull_from_host(HWND hwnd)
{
long len;
unsigned long i, w;
HGLOBAL h;
char *p;
len = (long)bd(CMD_GETLEN, 0);
if (len < 0) return;
if (len > MAX_CLIP) len = MAX_CLIP;
h = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)len + 1);
if (!h) return;
p = (char *)GlobalLock(h);
for (i = 0; i < (unsigned long)len; i += 4) {
w = bd(CMD_GETDATA, 0);
p[i] = (char)w;
if (i + 1 < (unsigned long)len) p[i+1] = (char)(w >> 8);
if (i + 2 < (unsigned long)len) p[i+2] = (char)(w >> 16);
if (i + 3 < (unsigned long)len) p[i+3] = (char)(w >> 24);
}
p[len] = 0;
GlobalUnlock(h);
if (!OpenClipboard(hwnd)) { GlobalFree(h); return; }
g_ignore++;
EmptyClipboard();
SetClipboardData(CF_TEXT, h);
CloseClipboard();
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_CREATE:
g_next = SetClipboardViewer(hwnd);
SetTimer(hwnd, 1, POLL_MS, 0);
return 0;
case WM_DRAWCLIPBOARD:
if (g_ignore > 0) g_ignore--;
else push_to_host(hwnd);
if (g_next) SendMessage(g_next, msg, wp, lp);
return 0;
case WM_CHANGECBCHAIN:
if ((HWND)wp == g_next) g_next = (HWND)lp;
else if (g_next) SendMessage(g_next, msg, wp, lp);
return 0;
case WM_TIMER:
pull_from_host(hwnd);
return 0;
case WM_DESTROY:
ChangeClipboardChain(hwnd, g_next);
KillTimer(hwnd, 1);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wp, lp);
}
int PASCAL WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cmd, int show)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
(void)hp; (void)cmd; (void)show;
if (CreateMutex(0, FALSE, "W95Tools") && GetLastError() == ERROR_ALREADY_EXISTS)
return 0;
if (bd_ebx(CMD_VERSION, 0) != VMW_MAGIC) {
MessageBox(0, "VMware backdoor not present.", "W95Tools", MB_OK | MB_ICONSTOP);
return 1;
}
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hi;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = 0;
wc.lpszClassName = "W95Tools";
RegisterClass(&wc);
hwnd = CreateWindow("W95Tools", "W95Tools", WS_OVERLAPPED,
0, 0, 0, 0, 0, 0, hi, 0);
if (!hwnd) return 1;
while (GetMessage(&msg, 0, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

62
src/renderer/clipboard.ts Normal file
View File

@@ -0,0 +1,62 @@
// Bidirectional text clipboard between the host and the Win95 guest.
//
// Transport is the legacy VMware backdoor clipboard protocol (port 0x5658,
// commands 69) implemented in v86's vmware.js. Inside the guest, W95TOOLS.EXE
// (guest-tools/agent) polls the backdoor and bridges it to CF_TEXT via the
// Win32 clipboard-viewer chain. Out here we poll Electron's clipboard — there
// is no change event — and translate between host UTF-8/LF and guest
// Windows-1252/CRLF.
import { clipboard } from "electron";
const CP1252 = new TextDecoder("windows-1252");
// v86's vmware.js and the guest agent both clamp to 64 KB; clamp here too so
// a huge host clipboard never even gets allocated/encoded.
const CLIP_MAX = 0x10000;
function fromGuest(bytes: Uint8Array): string {
return CP1252.decode(bytes).replace(/\r\n/g, "\n");
}
function toGuest(text: string): Uint8Array {
const s = text.slice(0, CLIP_MAX).replace(/\r\n|\n/g, "\r\n");
const n = Math.min(s.length, CLIP_MAX);
const out = new Uint8Array(n);
for (let i = 0; i < n; i++) {
const c = s.charCodeAt(i);
out[i] = c < 256 ? c : 0x3f;
}
return out;
}
export function setupClipboardSync(emulator: any): () => void {
// Track the last value seen on each side so a value we just wrote doesn't
// bounce back as a "change" from the other side.
let lastHost = clipboard.readText();
let lastGuest = "";
emulator.add_listener("vmware-clipboard-guest", (bytes: Uint8Array) => {
const text = fromGuest(bytes);
if (text === lastHost || text === lastGuest) return;
lastGuest = text;
lastHost = text;
clipboard.writeText(text);
console.log("[clip] guest → host", text.length, "chars");
});
const poll = () => {
const text = clipboard.readText();
if (text === lastHost) return;
lastHost = text;
if (text === lastGuest) return;
emulator.bus.send("vmware-clipboard-host", toGuest(text));
console.log("[clip] host → guest", text.length, "chars");
};
const id = window.setInterval(poll, 500);
window.addEventListener("focus", poll);
return () => {
window.clearInterval(id);
window.removeEventListener("focus", poll);
};
}

View File

@@ -19,6 +19,7 @@ import { resetState } from "./utils/reset-state";
import { setupSmbShare } from "./smb"; import { setupSmbShare } from "./smb";
import { setupTcpRelay } from "./net/tcp-relay"; import { setupTcpRelay } from "./net/tcp-relay";
import { setupDnsShim } from "./net/dns-shim"; import { setupDnsShim } from "./net/dns-shim";
import { setupClipboardSync } from "./clipboard";
import { startProbe } from "./debug-harness"; import { startProbe } from "./debug-harness";
import { SyncFileBuffer } from "./sync-file-buffer"; import { SyncFileBuffer } from "./sync-file-buffer";
@@ -406,6 +407,10 @@ export class Emulator extends React.Component<{}, EmulatorState> {
startProbe(window["emulator"]); startProbe(window["emulator"]);
} }
// Host ↔ guest text clipboard. The guest side is W95TOOLS.EXE on the
// TOOLS share; until that's running this is a no-op poller.
setupClipboardSync(window["emulator"]);
// New v86 instance // New v86 instance
// Mouse stays disabled until either the pointer is captured or the guest's // Mouse stays disabled until either the pointer is captured or the guest's
// VMware-backdoor mouse driver requests absolute mode. // VMware-backdoor mouse driver requests absolute mode.

View File

@@ -426,13 +426,13 @@ this.mouse_clicks=this.mouse_delta_x=this.mouse_delta_y=0;break;case 245:this.en
0;break;default:y(a)}this.mouse_irq()}}else if(this.read_controller_output_port)this.read_controller_output_port=!1,this.controller_output_port=a;else{y(a);this.mouse_buffer.clear();this.kbd_buffer.clear();this.kbd_buffer.push(250);switch(a){case 237:this.next_read_led=!0;break;case 240:this.next_handle_scan_code_set=!0;break;case 242:this.kbd_buffer.push(171);this.kbd_buffer.push(131);break;case 243:this.next_read_rate=!0;break;case 244:this.enable_keyboard_stream=!0;break;case 245:this.enable_keyboard_stream= 0;break;default:y(a)}this.mouse_irq()}}else if(this.read_controller_output_port)this.read_controller_output_port=!1,this.controller_output_port=a;else{y(a);this.mouse_buffer.clear();this.kbd_buffer.clear();this.kbd_buffer.push(250);switch(a){case 237:this.next_read_led=!0;break;case 240:this.next_handle_scan_code_set=!0;break;case 242:this.kbd_buffer.push(171);this.kbd_buffer.push(131);break;case 243:this.next_read_rate=!0;break;case 244:this.enable_keyboard_stream=!0;break;case 245:this.enable_keyboard_stream=
!1;break;case 246:break;case 255:this.kbd_buffer.clear();this.kbd_buffer.push(250);this.kbd_buffer.push(170);this.kbd_buffer.push(0);break;default:y(a)}this.kbd_irq()}}; !1;break;case 246:break;case 255:this.kbd_buffer.clear();this.kbd_buffer.push(250);this.kbd_buffer.push(170);this.kbd_buffer.push(0);break;default:y(a)}this.kbd_irq()}};
Gc.prototype.port64_write=function(a){y(a);switch(a){case 32:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(this.command_register);this.kbd_irq();break;case 96:this.read_command_register=!0;break;case 209:this.read_controller_output_port=!0;break;case 211:this.read_output_register=!0;break;case 212:this.next_is_mouse_command=!0;break;case 167:this.command_register|=32;break;case 168:this.command_register&=-33;break;case 169:this.kbd_buffer.clear();this.mouse_buffer.clear(); Gc.prototype.port64_write=function(a){y(a);switch(a){case 32:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(this.command_register);this.kbd_irq();break;case 96:this.read_command_register=!0;break;case 209:this.read_controller_output_port=!0;break;case 211:this.read_output_register=!0;break;case 212:this.next_is_mouse_command=!0;break;case 167:this.command_register|=32;break;case 168:this.command_register&=-33;break;case 169:this.kbd_buffer.clear();this.mouse_buffer.clear();
this.kbd_buffer.push(0);this.kbd_irq();break;case 170:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(85);this.kbd_irq();break;case 171:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(0);this.kbd_irq();break;case 173:this.command_register|=16;break;case 174:this.command_register&=-17;break;case 254:this.cpu.reboot_internal();break;default:y(a)}};function Hc(a,b){this.cpu=a;this.bus=b;this.absolute=this.enabled=!1;this.queue=[];this.buttons=0;this.last_y=this.last_x=-1;this.tail_is_move=!1;this.clip_out=new Uint8Array(0);this.clip_out_cursor=0;this.clip_out_fresh=!1;this.clip_in=new Uint8Array(0);this.clip_in_cursor=0;this.bus.register("vmware-clipboard-host",function(c){this.clip_out=65536<c.length?c.subarray(0,65536):c;this.clip_out_cursor=0;this.clip_out_fresh=!0},this);this.bus.register("mouse-absolute",function(c){const d=Math.max(0, this.kbd_buffer.push(0);this.kbd_irq();break;case 170:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(85);this.kbd_irq();break;case 171:this.kbd_buffer.clear();this.mouse_buffer.clear();this.kbd_buffer.push(0);this.kbd_irq();break;case 173:this.command_register|=16;break;case 174:this.command_register&=-17;break;case 254:this.cpu.reboot_internal();break;default:y(a)}};function Hc(a,b){function c(){}this.cpu=a;this.bus=b;this.absolute=this.enabled=!1;this.queue=[];this.buttons=0;this.last_y=this.last_x=-1;this.tail_is_move=!1;this.clip_out=new Uint8Array(0);this.clip_out_cursor=0;this.clip_out_fresh=!1;this.clip_in=new Uint8Array(0);this.clip_in_cursor=0;this.bus.register("vmware-clipboard-host",function(d){this.clip_out=65536<d.length?d.subarray(0,65536):d;this.clip_out_cursor=0;this.clip_out_fresh=!0},this);this.bus.register("mouse-absolute",function(d){const e=
Math.min(65535,Math.round(c[0]/c[2]*65535)));c=Math.max(0,Math.min(65535,Math.round(c[1]/c[3]*65535)));if(d!==this.last_x||c!==this.last_y)this.last_x=d,this.last_y=c,this.push_packet(0,!0)},this);this.bus.register("mouse-click",function(c){this.buttons=(c[0]?32:0)|(c[1]?8:0)|(c[2]?16:0);this.push_packet(0,!1)},this);this.bus.register("mouse-wheel",function(c){this.push_packet(-c[0]|0,!1)},this);a.io.register_read(22104,this,void 0,void 0,this.port_read32);a.io.register_write(22104,this,void 0,void 0, Math.max(0,Math.min(65535,Math.round(d[0]/d[2]*65535)));d=Math.max(0,Math.min(65535,Math.round(d[1]/d[3]*65535)));if(e!==this.last_x||d!==this.last_y)this.last_x=e,this.last_y=d,this.push_packet(0,!0)},this);this.bus.register("mouse-click",function(d){this.buttons=(d[0]?32:0)|(d[1]?8:0)|(d[2]?16:0);this.push_packet(0,!1)},this);this.bus.register("mouse-wheel",function(d){this.push_packet(-d[0]|0,!1)},this);a.io.register_read(22104,this,function(){return 255},function(){return 65535},this.port_read32);
this.port_write32)}Hc.prototype.push_packet=function(a,b){!this.enabled||!this.absolute||0>this.last_x||(b&&this.tail_is_move&&4<=this.queue.length?(this.queue[this.queue.length-3]=this.last_x,this.queue[this.queue.length-2]=this.last_y):1024<this.queue.length+4?(this.enabled=!1,this.queue.length=0):(this.queue.push(this.buttons,this.last_x,this.last_y,a),this.tail_is_move=b))}; a.io.register_write(22104,this,c,c,c)}Hc.prototype.push_packet=function(a,b){!this.enabled||!this.absolute||0>this.last_x||(b&&this.tail_is_move&&4<=this.queue.length?(this.queue[this.queue.length-3]=this.last_x,this.queue[this.queue.length-2]=this.last_y):1024<this.queue.length+4?(this.enabled=!1,this.queue.length=0):(this.queue.push(this.buttons,this.last_x,this.last_y,a),this.tail_is_move=b))};
Hc.prototype.port_read32=function(){var a=this.cpu.reg32;if(1447909480!==(a[0]|0))return-1;switch(a[1]&65535){case 10:return a[3]=1447909480,6;case 6:if(!this.clip_out_fresh)break;this.clip_out_fresh=!1;this.clip_out_cursor=0;return this.clip_out.length;case 7:var b=this.clip_out;a=this.clip_out_cursor;b=b[a]|0|(b[a+1]|0)<<8|(b[a+2]|0)<<16|(b[a+3]|0)<<24;this.clip_out_cursor=a+4;return b;case 8:return a=Math.min(a[3]>>>0,65536),this.clip_in=new Uint8Array(a),this.clip_in_cursor=0,0===a&&this.bus.send("vmware-clipboard-guest", Hc.prototype.port_read32=function(){var a=this.cpu.reg32;if(1447909480!==a[0])return-1;switch(a[1]&65535){case 10:return a[3]=1447909480,6;case 6:if(!this.clip_out_fresh)break;this.clip_out_fresh=!1;this.clip_out_cursor=0;return this.clip_out.length;case 7:var b=this.clip_out;a=this.clip_out_cursor;b=b[a]|0|(b[a+1]|0)<<8|(b[a+2]|0)<<16|(b[a+3]|0)<<24;this.clip_out_cursor=a+4;return b;case 8:return a=Math.min(a[3]>>>0,65536),this.clip_in=new Uint8Array(a),this.clip_in_cursor=0,0===a&&this.bus.send("vmware-clipboard-guest",
this.clip_in),0;case 9:b=this.clip_in;a=a[3]>>>0;var c=this.clip_in_cursor;c<b.length&&(b[c++]=a);c<b.length&&(b[c++]=a>>>8);c<b.length&&(b[c++]=a>>>16);c<b.length&&(b[c++]=a>>>24);this.clip_in_cursor=c;c>=b.length&&(this.bus.send("vmware-clipboard-guest",b),this.clip_in=new Uint8Array(0),this.clip_in_cursor=0);return 0;case 40:return this.enabled?this.queue.length:-65536;case 39:b=Math.min(a[3]>>>0,4,this.queue.length);c=[0,0,0,0];for(let d=0;d<b;d++)c[d]=this.queue.shift();a[3]=c[1];a[1]=c[2];a[2]= this.clip_in),0;case 9:b=this.clip_in;a=a[3]>>>0;var c=this.clip_in_cursor;c<b.length&&(b[c++]=a);c<b.length&&(b[c++]=a>>>8);c<b.length&&(b[c++]=a>>>16);c<b.length&&(b[c++]=a>>>24);this.clip_in_cursor=c;c>=b.length&&(this.bus.send("vmware-clipboard-guest",b),this.clip_in=new Uint8Array(0),this.clip_in_cursor=0);return 0;case 40:return this.enabled?this.queue.length:-65536;case 39:b=Math.min(a[3]>>>0,4,this.queue.length);c=[0,0,0,0];for(let d=0;d<b;d++)c[d]=this.queue.shift();a[3]=c[1];a[1]=c[2];a[2]=
c[3];return c[0];case 41:switch(a[3]|0){case 1161905490:this.enabled=!0;this.queue.length=0;this.tail_is_move=!1;this.queue.push(876762442);break;case 245:this.absolute=this.enabled=!1;this.queue.length=0;this.bus.send("vmware-absolute-mouse",!1);break;case 1396851026:this.absolute=!0;this.bus.send("vmware-absolute-mouse",!0);break;case 1279611474:this.absolute=!1,this.bus.send("vmware-absolute-mouse",!1)}return 0}return-1};Hc.prototype.port_write32=function(){}; c[3];return c[0];case 41:switch(a[3]){case 1161905490:this.enabled=!0;this.queue.length=0;this.tail_is_move=!1;this.queue.push(876762442);break;case 245:this.absolute=this.enabled=!1;this.queue.length=0;this.bus.send("vmware-absolute-mouse",!1);break;case 1396851026:this.absolute=!0;this.bus.send("vmware-absolute-mouse",!0);break;case 1279611474:this.absolute=!1,this.bus.send("vmware-absolute-mouse",!1)}return 0}return-1};Hc.prototype.get_state=function(){return[this.enabled,this.absolute]};
Hc.prototype.get_state=function(){return[this.enabled,this.absolute]};Hc.prototype.set_state=function(a){this.enabled=a[0];this.absolute=a[1];this.bus.send("vmware-absolute-mouse",this.absolute)};const Ic=DataView.prototype,Jc={size:1,get:Ic.getUint8,set:Ic.setUint8},Kc={size:2,get:Ic.getUint16,set:Ic.setUint16},U={size:4,get:Ic.getUint32,set:Ic.setUint32},Mc=Lc([{magic:U},{class:Jc},{data:Jc},{version0:Jc},{osabi:Jc},{abiversion:Jc},{pad0:function(a){return{size:a,get:()=>-1}}(7)},{type:Kc},{machine:Kc},{version1:U},{entry:U},{phoff:U},{shoff:U},{flags:U},{ehsize:Kc},{phentsize:Kc},{phnum:Kc},{shentsize:Kc},{shnum:Kc},{shstrndx:Kc}]);console.assert(52===Mc.reduce((a,b)=>a+b.size,0)); Hc.prototype.set_state=function(a){this.enabled=a[0];this.absolute=a[1];this.bus.send("vmware-absolute-mouse",this.absolute)};const Ic=DataView.prototype,Jc={size:1,get:Ic.getUint8,set:Ic.setUint8},Kc={size:2,get:Ic.getUint16,set:Ic.setUint16},U={size:4,get:Ic.getUint32,set:Ic.setUint32},Mc=Lc([{magic:U},{class:Jc},{data:Jc},{version0:Jc},{osabi:Jc},{abiversion:Jc},{pad0:function(a){return{size:a,get:()=>-1}}(7)},{type:Kc},{machine:Kc},{version1:U},{entry:U},{phoff:U},{shoff:U},{flags:U},{ehsize:Kc},{phentsize:Kc},{phnum:Kc},{shentsize:Kc},{shnum:Kc},{shstrndx:Kc}]);console.assert(52===Mc.reduce((a,b)=>a+b.size,0));
const Nc=Lc([{type:U},{offset:U},{vaddr:U},{paddr:U},{filesz:U},{memsz:U},{flags:U},{align:U}]);console.assert(32===Nc.reduce((a,b)=>a+b.size,0));const Oc=Lc([{name:U},{type:U},{flags:U},{addr:U},{offset:U},{size:U},{link:U},{info:U},{addralign:U},{entsize:U}]);console.assert(40===Oc.reduce((a,b)=>a+b.size,0));function Lc(a){return a.map(function(b){var c=Object.keys(b);console.assert(1===c.length);c=c[0];b=b[c];console.assert(0<b.size);return{name:c,type:b,size:b.size,get:b.get,set:b.set}})} const Nc=Lc([{type:U},{offset:U},{vaddr:U},{paddr:U},{filesz:U},{memsz:U},{flags:U},{align:U}]);console.assert(32===Nc.reduce((a,b)=>a+b.size,0));const Oc=Lc([{name:U},{type:U},{flags:U},{addr:U},{offset:U},{size:U},{link:U},{info:U},{addralign:U},{entsize:U}]);console.assert(40===Oc.reduce((a,b)=>a+b.size,0));function Lc(a){return a.map(function(b){var c=Object.keys(b);console.assert(1===c.length);c=c[0];b=b[c];console.assert(0<b.size);return{name:c,type:b,size:b.size,get:b.get,set:b.set}})}
function Pc(a,b){const c={};let d=0;for(const e of b)b=e.get.call(a,d,!0),console.assert(void 0===c[e.name]),c[e.name]=b,d+=e.size;return[c,d]}function Qc(a,b,c){const d=[];let e=0;for(var f=0;f<c;f++){const [g,h]=Pc(new DataView(a.buffer,a.byteOffset+e,void 0),b);d.push(g);e+=h}return[d,e]};const Rc={[0]:0,[1]:525,[2]:525,[3]:350,[4]:350,[5]:350}; function Pc(a,b){const c={};let d=0;for(const e of b)b=e.get.call(a,d,!0),console.assert(void 0===c[e.name]),c[e.name]=b,d+=e.size;return[c,d]}function Qc(a,b,c){const d=[];let e=0;for(var f=0;f<c;f++){const [g,h]=Pc(new DataView(a.buffer,a.byteOffset+e,void 0),b);d.push(g);e+=h}return[d,e]};const Rc={[0]:0,[1]:525,[2]:525,[3]:350,[4]:350,[5]:350};
function V(a,b,c,d){this.io=a.io;this.cpu=a;this.dma=a.devices.dma;this.cmd_table=this.build_cmd_lookup_table();this.sra=0;this.srb=192;this.dor=12;this.tdr=0;this.msr=128;this.dsr=0;this.cmd_phase=1;this.cmd_flags=this.cmd_code=0;this.cmd_buffer=new Uint8Array(17);this.cmd_remaining=this.cmd_cursor=0;this.response_data=new Uint8Array(15);this.reset_sense_int_count=this.curr_drive_no=this.status1=this.status0=this.response_length=this.response_cursor=0;this.locked=!1;this.head_load_time=this.step_rate_interval= function V(a,b,c,d){this.io=a.io;this.cpu=a;this.dma=a.devices.dma;this.cmd_table=this.build_cmd_lookup_table();this.sra=0;this.srb=192;this.dor=12;this.tdr=0;this.msr=128;this.dsr=0;this.cmd_phase=1;this.cmd_flags=this.cmd_code=0;this.cmd_buffer=new Uint8Array(17);this.cmd_remaining=this.cmd_cursor=0;this.response_data=new Uint8Array(15);this.reset_sense_int_count=this.curr_drive_no=this.status1=this.status0=this.response_length=this.response_cursor=0;this.locked=!1;this.head_load_time=this.step_rate_interval=